diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 523e7a4be44..b65375b3c56 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,11 +12,11 @@ jobs: travis-check: name: Python ${{ matrix.python-version }} - runs-on: ubuntu-20.04 + runs-on: ubuntu-24.04 strategy: matrix: - python-version: [3.6, 3.7, 3.8, 3.9] + python-version: [3.8, 3.9, 3.11, 3.12] fail-fast: false steps: @@ -29,12 +29,19 @@ jobs: uses: actions/setup-python@v2 with: python-version: ${{ matrix.python-version }} + - name: Update pip + run: pip install --upgrade pip - name: Install dependencies run: | pip install sphinx${SPHINX_VERSION:+==$SPHINX_VERSION} pip install -r requirements-travis.txt - name: Run inspekt - run: inspekt checkall --disable-style E501,E265,W601,W605,E402,E722,E741 --no-license-check + run: inspekt checkall --disable-style E501,E265,W601,W605,E402,E722,E741 --disable-lint W,R,C,E1002,E1101,E1103,E1120,F0401,I0011,E0601,E0602,E0606 --no-license-check - run: echo "This job's status is ${{ job.status }}." - name: Run spellchecker - run: pylint --errors-only --disable=all --enable=spelling --spelling-dict=en_US --spelling-private-dict-file=spell.ignore * + run: | + set +e + pylint --errors-only --disable=all --enable=spelling --spelling-dict=en_US --spelling-private-dict-file=spell.ignore * + exitcode=$? + set -e + test $exitcode == 32 -o $exitcode == 0 diff --git a/contributor_reviewer_maintainer_guidelines.rst b/contributor_reviewer_maintainer_guidelines.rst index 36c545e847f..b40f33b85f6 100644 --- a/contributor_reviewer_maintainer_guidelines.rst +++ b/contributor_reviewer_maintainer_guidelines.rst @@ -1,2 +1,2 @@ Please follow up the same best practices as avocado-vt: -https://github.com/avocado-framework/avocado-vt/blob/master/PR_Review_And_Contribute_Practices.txt +https://github.com/avocado-framework/avocado-vt/blob/master/docs/source/contributing/Guidelines.rst diff --git a/libvirt/tests/cfg/backingchain/blockcommit/check_allocation_watermark_during_blockcommit.cfg b/libvirt/tests/cfg/backingchain/blockcommit/check_allocation_watermark_during_blockcommit.cfg index 5609f7f89a2..cd28feb36ec 100644 --- a/libvirt/tests/cfg/backingchain/blockcommit/check_allocation_watermark_during_blockcommit.cfg +++ b/libvirt/tests/cfg/backingchain/blockcommit/check_allocation_watermark_during_blockcommit.cfg @@ -2,24 +2,40 @@ type = check_allocation_watermark_during_blockcommit target_disk = "vdb" domstats_option = " --block --backing | grep allocation " + changing_index = "4" + changing_alloc = "block.${changing_index}.allocation" disappear_index = "4" disappear_alloc = "block.${disappear_index}.allocation" lvm_num = 3 snap_nums = 3 - virsh_opt = " -k0" + write_file_bs = "1M" + write_file_count = "400" + lv_size = "200M" variants case: - inactive_layer: - commit_option = "--top ${target_disk}[3] --base ${target_disk}[1] --wait --verbose --bandwidth 10" + commit_option = "--top ${target_disk}[3] --base ${target_disk}[1] --wait --verbose --bandwidth 1" commit_success_msg = "Commit complete" - active_layer: - commit_option = " --wait --verbose --pivot --bandwidth 10" + commit_option = " --wait --verbose --pivot --bandwidth 1" commit_success_msg = "Successfully pivoted" variants: - file_disk: + storage_type = nfs + set_sebool_local = 'yes' + local_boolean_varible = 'virt_use_nfs' + setup_local_nfs = "yes" + nfs_mount_src = "/var/lib/avocado/data/avocado-vt/nfs-export" + nfs_mount_dir = "/var/lib/avocado/data/avocado-vt/nfs-mount" + nfs_mount_options = "rw" + export_ip = "*" + export_dir = "/var/lib/avocado/data/avocado-vt/nfs-export" + export_options= "rw,root_squash" + local_boolean_value = "on" disk_type = "nfs" disk_dict = {"type_name":"file", "target":{"dev": "${target_disk}", "bus": "virtio"}, "driver": {"name": "qemu", "type":"qcow2"}} extra_option = ",snapshot=external --diskspec vda,snapshot=no " - block_disk: disk_type = "block" - disk_dict = {"type_name":"${disk_type}", "target":{"dev": "${target_disk}", "bus": "virtio"}, "driver": {"name": "qemu", "type":"raw"}} - extra_option = ",snapshot=external,stype=block --diskspec vda,snapshot=no --reuse-external " + convert_format = "qcow2" + disk_dict = {"type_name":"${disk_type}", "target":{"dev": "${target_disk}", "bus": "virtio"}, "driver": {"name": "qemu", "type":"qcow2"}} + extra_option = ",snapshot=external,stype=block --diskspec vda,snapshot=no --reuse-external" diff --git a/libvirt/tests/cfg/backingchain/blockcopy/blockcopy_with_different_dest_xml.cfg b/libvirt/tests/cfg/backingchain/blockcopy/blockcopy_with_different_dest_xml.cfg index cbbc22b7d37..55cc85ad47d 100644 --- a/libvirt/tests/cfg/backingchain/blockcopy/blockcopy_with_different_dest_xml.cfg +++ b/libvirt/tests/cfg/backingchain/blockcopy/blockcopy_with_different_dest_xml.cfg @@ -20,6 +20,7 @@ - block_disk: dest_disk_type = "block" dest_disk_dict = {"type_name":"${dest_disk_type}", "target":{"dev": "${target_disk}", "bus": "virtio"}, "driver": {"name": "qemu", "type":"raw"}} + simulated_iscsi = "modprobe scsi_debug dev_size_mb=800" - rbd_with_auth_disk: dest_disk_type = "rbd_with_auth" mon_host = "EXAMPLE_MON_HOST" @@ -30,6 +31,23 @@ rbd_image_size = "${image_size}" sec_dict = {"secret_ephemeral": "no", "secret_private": "yes", "description": "sec_desc", "usage": "ceph", "usage_name": "cephlibvirt"} dest_disk_dict = {"type_name":"network", "target":{"dev": "${target_disk}", "bus": "scsi"}, "driver": {"name": "qemu", "type":"raw"}} + - rbd_with_luks_and_auth: + source_disk_dict = {"type_name":"${source_disk_type}", "target":{"dev": "${target_disk}", "bus": "scsi"}, "driver": {"name": "qemu", "type":"qcow2"}} + dest_disk_type = "rbd_with_luks_and_auth" + mon_host = "EXAMPLE_MON_HOST" + auth_key = "EXAMPLE_AUTH_KEY" + auth_user = "EXAMPLE_AUTH_USER" + image_path = "EXAMPLE_IMAGE_PATH" + client_name = "EXAMPLE_CLIENT_NAME" + rbd_image_size = "${image_size}" + ceph_usage_name="cephlibvirt" + sec_dict = {"secret_ephemeral": "no", "secret_private": "yes", "description": "sec_desc_auth", "usage": "ceph", "usage_name": "${ceph_usage_name}"} + dest_disk_dict = {"type_name":"network", "target":{"dev": "${target_disk}", "bus": "scsi"}, "driver": {"name": "qemu", "type":"raw"}} + private_key_password = "EXAMPLE_PWD" + secret_pwd = "`printf %s ${private_key_password} | base64`" + rbd_image_format = "luks" + rbd_image_parameter = "--object secret,id=luks1.img_luks0,data=${secret_pwd},format=base64 -o key-secret=luks1.img_luks0 rbd:{}:id={}:key={}:auth_supported=cephx:mon_host={}" + luks_sec_dict = {"secret_ephemeral": "no", "secret_private": "yes", "description": "sec_desc_luks", "usage": "volume", "volume":"%s", "uuid":"198784e8-f977-40ac-8d0d-4d0fcca70588"} - nbd_disk: dest_disk_type = "nbd" nbd_server_port = "10808" diff --git a/libvirt/tests/cfg/backingchain/blockcopy/blockcopy_with_different_qcow2_properties.cfg b/libvirt/tests/cfg/backingchain/blockcopy/blockcopy_with_different_qcow2_properties.cfg index 6060253faf7..cfeb929e147 100644 --- a/libvirt/tests/cfg/backingchain/blockcopy/blockcopy_with_different_qcow2_properties.cfg +++ b/libvirt/tests/cfg/backingchain/blockcopy/blockcopy_with_different_qcow2_properties.cfg @@ -7,6 +7,7 @@ snap_extra = " --no-metadata --diskspec vda,snapshot=no" copy_image = "/tmp/copy.qcow2" image_path = "/var/lib/libvirt/images/test.qcow2" + snap_path = "/var/lib/libvirt/images/snap1" image_format = "qcow2" image_size = "500M" variants property: @@ -16,6 +17,14 @@ expected_extended_l2 = "true" property_command = "cluster_size=${cluster_size},extended_l2=${extended_l2_value}" image_extras = "-o ${property_command}" + expected_chain_after_snap = ['${snap_path}','${image_path}'] + - with_datastore: + func_supported_since_libvirt_ver = (10, 10, 0) + datastore_path = "/var/lib/libvirt/images/datastore" + data_file_option = " -o data_file=%s" + property_command = "data_file=${datastore_path}" + image_extras = "-o ${property_command}" + expected_chain_after_snap = ['${snap_path}','${image_path}', '${datastore_path}'] variants: - not_encrypt_disk: enable_encrypt_disk = "no" diff --git a/libvirt/tests/cfg/backingchain/blockjob/blockjob_pivot_after_irregular_operations.cfg b/libvirt/tests/cfg/backingchain/blockjob/blockjob_pivot_after_irregular_operations.cfg index 755d43cff14..675da48ad84 100644 --- a/libvirt/tests/cfg/backingchain/blockjob/blockjob_pivot_after_irregular_operations.cfg +++ b/libvirt/tests/cfg/backingchain/blockjob/blockjob_pivot_after_irregular_operations.cfg @@ -6,7 +6,7 @@ abort_option = " --abort" variants test_scenario: - before_finish: - blockcopy_options = "blockcopy %s %s %s --transient-job --bandwidth 2" + blockcopy_options = "blockcopy %s %s %s --transient-job --bytes 200" err_msg = "not ready for pivot yet" - delete_copy_file: blockcopy_options = " --transient-job --wait --verbose " diff --git a/libvirt/tests/cfg/backingchain/virsh_domblk/domblkthreshold_with_backingchain_element.cfg b/libvirt/tests/cfg/backingchain/virsh_domblk/domblkthreshold_with_backingchain_element.cfg index 487c3484441..8c327f6ac1a 100644 --- a/libvirt/tests/cfg/backingchain/virsh_domblk/domblkthreshold_with_backingchain_element.cfg +++ b/libvirt/tests/cfg/backingchain/virsh_domblk/domblkthreshold_with_backingchain_element.cfg @@ -1,8 +1,14 @@ - backingchain.virsh_domblk: type = domblkthreshold_with_backingchain_element start_vm = 'yes' - target_disk = 'vda' + target_disk = 'vdb' domblk_threshold = '1' + actual_threshold = "1" + disk_type = "file" + disk_image_format = "raw" + disk_dict = {"type_name":"${disk_type}", "target":{"dev": "${target_disk}", "bus": "virtio"}, "driver": {"name": "qemu", "type": "raw"}} + disk_size = "3G" + snap_extra = " -diskspec vda,snapshot=no" variants case_name: - backing_target: domblk_index = 3 diff --git a/libvirt/tests/cfg/backingchain/with_disk_attributes_test/commit_pull_with_disk_source_attributes.cfg b/libvirt/tests/cfg/backingchain/with_disk_attributes_test/commit_pull_with_disk_source_attributes.cfg new file mode 100644 index 00000000000..ac7133ea0b1 --- /dev/null +++ b/libvirt/tests/cfg/backingchain/with_disk_attributes_test/commit_pull_with_disk_source_attributes.cfg @@ -0,0 +1,18 @@ +- backingchain.with_disk_attributes_test.with_source_attributes: + type = commit_pull_with_disk_source_attributes + start_vm = no + common_options = " --wait --verbose" + target_disk = "vdb" + disk_type = "file" + snap_num = 3 + disk_dict = {"type_name":"${disk_type}", "target":{"dev": "${target_disk}", "bus": "virtio"}, "driver": {"name": "qemu", "type":"qcow2"}} + variants: + - with_datastore: + func_supported_since_libvirt_ver = (10, 10, 0) + data_file_option = " -o data_file=%s" + variants block_cmd: + - blockcommit: + blockcommit_options = " --active --pivot" + expected_chain_index = "base" + - blockpull: + expected_chain_index = "3" diff --git a/libvirt/tests/cfg/bios/virsh_boot.cfg b/libvirt/tests/cfg/bios/virsh_boot.cfg index 03f42982221..3ec1418374f 100644 --- a/libvirt/tests/cfg/bios/virsh_boot.cfg +++ b/libvirt/tests/cfg/bios/virsh_boot.cfg @@ -186,6 +186,7 @@ uefi_target_dev = "sda" check_prompt = ".*has invalid signature" || "'Verification failed: (0x1A) Security Violation'" - by_seabios: + no s390-virtio boot_type = "seabios" loader = "/usr/share/seabios/bios-256k.bin" loader_type = "rom" diff --git a/libvirt/tests/cfg/bios/virsh_boot_sysinfo.cfg b/libvirt/tests/cfg/bios/virsh_boot_sysinfo.cfg index 9429c7d7866..37f819d4b1f 100644 --- a/libvirt/tests/cfg/bios/virsh_boot_sysinfo.cfg +++ b/libvirt/tests/cfg/bios/virsh_boot_sysinfo.cfg @@ -39,6 +39,7 @@ error_msg = "Firmware entry must have either value or 'file' attribute" variants: - by_seabios: + no s390-virtio boot_type = "seabios" - by_ovmf: only q35 diff --git a/libvirt/tests/cfg/bios/virsh_boot_tseg.cfg b/libvirt/tests/cfg/bios/virsh_boot_tseg.cfg index d3497270b8a..7b7ea713439 100644 --- a/libvirt/tests/cfg/bios/virsh_boot_tseg.cfg +++ b/libvirt/tests/cfg/bios/virsh_boot_tseg.cfg @@ -52,4 +52,5 @@ loader = "/usr/share/OVMF/OVMF_CODE.secboot.fd" loader_type = "pflash" - by_seabios: + no s390-virtio boot_type = "seabios" diff --git a/libvirt/tests/cfg/controller/controller_functional.cfg b/libvirt/tests/cfg/controller/controller_functional.cfg index c785f01a7fb..232632d5dd3 100644 --- a/libvirt/tests/cfg/controller/controller_functional.cfg +++ b/libvirt/tests/cfg/controller/controller_functional.cfg @@ -12,7 +12,7 @@ controller_type = pci variants: - pci_bridge_auto_add: - only i440fx + only i440fx remove_address = "no" variants: - no_pci_controller: @@ -36,7 +36,7 @@ controller_model = pci-root controller_pcihole64 = 1024 - pcie_root: - only q35 + only q35, aarch64 controller_type = pci controller_model = pcie-root - second_level_bridge: @@ -50,19 +50,33 @@ controller_type = virtio-serial controller_bus = ccw - controller_alias: - only i440fx - add_contrl_list = "[{'model': 'pci-root', 'index': '0', 'alias': 'ua-PCI_ROOT'},{'model': 'pci-bridge', 'alias': 'ua-PCI_BRIDGE'}, {'model': 'pci-expander-bus', 'alias': 'ua-PCI_EXPANDER_BUS'}]" - qemu_patterns = "[('-device', 'pci-bridge.*,.*,.*id.*ua-PCI_BRIDGE'), ('-device', 'pxb.*,.*,.*id.*ua-PCI_EXPANDER_BUS')]" + no s390-virtio, pseries + pcie_root_config = {'model': 'pcie-root', 'index': '0', 'alias': 'ua-ROOT'} + pcie_root_port_config = {'model': 'pcie-root-port', 'alias': 'ua-ROOT_PORT'} + pcie_root_port2_config = {'model': 'pcie-root-port', 'alias': 'ua-ROOT_PORT2'} + pcie_to_pci_bridge_config = {'model': 'pcie-to-pci-bridge', 'alias': 'ua-ROOT_PCIE_PCI'} + pci_bridge_config = {'model': 'pci-bridge', 'alias': 'ua-PCI_BRIDGE'} + pcie_switch_upstream_port = {'model': 'pcie-switch-upstream-port', 'alias': 'ua-UPSTREAM_PORT'} + pcie_switch_downstream_port = {'model': 'pcie-switch-downstream-port', 'alias': 'ua-DOWNSTREAM_PORT'} + pci_expander_bus_config = {'model': 'pcie-expander-bus', 'alias': 'ua-PCIE_EXPANDER_BUS'} + add_contrl_list = "[${pcie_root_config},${pcie_root_port_config}, ${pcie_root_port2_config}, ${pcie_to_pci_bridge_config}, ${pci_bridge_config}, ${pcie_switch_upstream_port}, ${pcie_switch_downstream_port}, ${pci_expander_bus_config}]" + pattern1 = "('-device', 'pcie-root-port.*,.*,.*id.*ua-ROOT_PORT'), ('-device', 'pcie-root-port.*,.*,.*id.*ua-ROOT_PORT2')" + pattern2 = "('-device', 'pcie-pci-bridge.*,.*id.*ua-ROOT_PCIE_PCI'), ('-device', 'pci-bridge.*,.*,.*id.*ua-PCI_BRIDGE')" + pattern3 = "('-device', 'upstream.*,.*id.*ua-UPSTREAM_PORT'),('-device', 'downstream.*,.*id.*ua-DOWNSTREAM_PORT')" + qemu_patterns = "[${pattern1},${pattern2},${pattern3},('-device', 'pxb-pcie.*,.*,.*id.*ua-PCIE_EXPANDER_BUS')]" + i440fx: + add_contrl_list = "[{'model': 'pci-root', 'index': '0', 'alias': 'ua-PCI_ROOT'},{'model': 'pci-bridge', 'alias': 'ua-PCI_BRIDGE'}, {'model': 'pci-expander-bus', 'alias': 'ua-PCI_EXPANDER_BUS'}]" + qemu_patterns = "[('-device', 'pci-bridge.*,.*,.*id.*ua-PCI_BRIDGE'), ('-device', 'pxb.*,.*,.*id.*ua-PCI_EXPANDER_BUS')]" check_contr_addr = "no" check_within_guest = "no" - pcie_root_port_model: - only q35 + only q35, aarch64 run_vm = "yes" check_contr_addr = "no" remove_contr = "no" new_model = pcie-root-port old_model = ioh3420 - auto_index = "yes" + auto_index= "yes" attach_option = "--address pci:0000.%s.00.0" qemu_patterns = "[('-device', 'pcie-root-port.*,.*id.*pci.%s.*,.*bus.*pcie.0.*,.*addr.*0x2')]" guest_patterns = "['00:.* PCI bridge: Red Hat']" @@ -168,7 +182,7 @@ controller_type = virtio-serial controller_vectors = '1' - virtio_serial_0_vectors: - no q35 + no q35, aarch64 controller_type = virtio-serial controller_vectors = '0' - usb_controller: @@ -177,10 +191,10 @@ variants: # ehci and ich9-ehci1 are USB2.0 controller model - ehci_model: - no pseries + no pseries, aarch64 controller_model = ehci - ich9_ehci1_model: - no pseries + no pseries, aarch64 controller_model = ich9-ehci1 companion_controller_model = ich9-uhci companion_controller_num = 3 @@ -188,7 +202,7 @@ controller_index = 0 # nec-xhci and qemu-xhci are USB3.0 controller model - nec_xhci_model: - no pseries + no pseries, aarch64 controller_model = nec-xhci - qemu_xhci_model: variants: @@ -217,7 +231,7 @@ only i440fx controller_model = pci-root - pcie_root: - only q35 + only q35, aarch64 controller_model = pcie-root - negative: controller_index = -1 @@ -226,7 +240,7 @@ - pci_bridge: controller_model = pci-bridge - pcie_root: - only q35 + only q35, aarch64 controller_model = pcie-root - zero: controller_index = 0 @@ -300,7 +314,7 @@ controller_model = 'pcie-root' err_msg = "The PCI controller.*index='0' must be model='pci-root'" - pci_root_model: - only q35 + only q35, aarch64 controller_model = 'pci-root' err_msg = "The PCI controller.*index='0' must be model='pcie-root'" - other_model: diff --git a/libvirt/tests/cfg/controller/pci_controller_memreserve.cfg b/libvirt/tests/cfg/controller/pci_controller_memreserve.cfg new file mode 100644 index 00000000000..4f44dc1f84f --- /dev/null +++ b/libvirt/tests/cfg/controller/pci_controller_memreserve.cfg @@ -0,0 +1,38 @@ +- pci_controller_memreserve: + type = pci_controller_memreserve + start_vm = no + func_supported_since_libvirt_ver = (10, 3, 0) + # Two vms are required for the tests, one for ovmf and the other for seabios + vms = "avocado-vt-vm1 vm2" + only q35 + variants: + - 8M: + memReserve = 8192 + - 10M: + memReserve = 10240 + ovmf: + expect_memReserve = 16384 + - 16M: + memReserve = 16384 + - 32M: + memReserve = 32768 + variants: + - firmware: + variants: + - ovmf: + firmware_type = "ovmf" + loader_dict = {'os_firmware': 'efi'} + - seabios: + firmware_type = "seabios" + variants: + - controller: + variants: + - pci_bridge: + only q35 + contr_model = "pci-bridge" + depend_contr_dict = {"type": "pci", "model": "pcie-to-pci-bridge", "index": "%s"} + contr_pattern = ".*PCI-PCI bridge" + - pcie_root_port: + contr_model = "pcie-root-port" + contr_pattern = "%s.*PCIe Root port" + contr_dict = {"type": "pci", "model": "${contr_model}", "index": "%s", "target": {"memReserve":"${memReserve}"}} diff --git a/libvirt/tests/cfg/cpu/aarch64_cpu_sve.cfg b/libvirt/tests/cfg/cpu/aarch64_cpu_sve.cfg index ff8de345e32..1e272c01223 100644 --- a/libvirt/tests/cfg/cpu/aarch64_cpu_sve.cfg +++ b/libvirt/tests/cfg/cpu/aarch64_cpu_sve.cfg @@ -4,46 +4,72 @@ check_cmd_lscpu = "which lscpu" check_sve = "lscpu | grep sve" check_sve_config = "grep CONFIG_ARM64_SVE=y /boot/config-%s" - get_maxium_sve_length = "dmesg | grep 'SVE: maximum available vector length'" + get_maximum_sve_length = "dmesg | grep 'SVE: maximum available vector length'" cpu_xml_policy = "require" cpu_xml_mode = "host-passthrough" only aarch64 variants: - boot_test: + status_error = "no" variants: - enable_sve: - expect_sve = "yes" - disable_sve: cpu_xml_policy = "disable" expect_sve = "no" - - vector_length_test: + - with_vector_length: variants: - valid_length: - expect_sve = "yes" + status_error = "no" variants: - - single_vector: - variants: - - sve128: - vector_length = "sve128" - - sve256: - vector_length = "sve256" - - sve512: - vector_length = "sve512" - - mutiple_vector: - vector_lenth_list = '[{"sve128":"require"}, {"sve256":"require"}, {"sve384":"disable"}, {"sve512":"require"}]' + - 128: + vector_length = "sve128" + - 256: + vector_length = "sve256" + - 512: + vector_length = "sve512" + - all_supported_lengths: + all_supports = "yes" - invalid_length: - only negative_test - expect_sve = "no" + status_error = "yes" vector_length = "sve1234" expect_msg = "unsupported configuration: unknown CPU feature: sve1234" - conflict_length: - only negative_test - vector_lenth_list = '[{"sve":"disable"}, {"sve128":"require"}]' + status_error = "yes" + vector_length_list = '[{"sve":"disable"}, {"sve128":"require"}]' define_error = "yes" expect_msg = "SVE disabled, but SVE vector lengths provided" - variants: - - positive_test: + - unsupported_length: + unsupported_len = yes + status_error = "yes" + expect_msg = "does not support the vector length" + - discontinous_length: + status_error = "yes" + discontinous_len = "yes" + expect_msg = "KVM host requires all supported vector lengths smaller than .* bits .* enabled" + - optimized-routines: + status_error = "no" + all_supports = "yes" + install_pkgs = ["git", "gcc", "make", "glibc-static", "mpfr-devel", "libmpc-devel"] + target_dir = "/home/optimized_routines" + optimized_repo_cmd = "git clone --depth=1 https://github.com/ARM-software/optimized-routines ${target_dir}" + optimized_echo_cmd = "echo 'CFLAGS += -march=armv8.2-a+sve' >> config.mk" + optimized_compile_cmd = "cd ${target_dir}; cp config.mk.dist config.mk; ${optimized_echo_cmd}; make" + optimized_execute_cmd = "cd ${target_dir}; make check 2>/dev/null" + - sve_selftests_in_kernel: status_error = "no" - - negative_test: - only invalid_length, conflict_length + all_supports = "yes" + install_pkgs = ["git", "gcc", "make", "kernel-devel", "kernel-headers", "rsync", "brewkoji", "tar"] + target_dir = "/home/sve_stress" + kernel_testing_dir = "${target_dir}/tools/testing" + suite_dir = "${kernel_testing_dir}/selftests/arm64/fp" + sve_exec_timeout = 240 + kernel_download_cmd = "cd /var/tmp && brew download-build --rpm %s && rpm2cpio %s | cpio -idm" + kernel_tar_cmd = "cd /var/tmp && tar Jxf %s --strip-components 1 -C ${target_dir}" + kernel_selftest_compile_cmd = "cd ${kernel_testing_dir}; make all -C selftests/ TARGETS=arm64" + sve_stress_get_lenths = "${suite_dir}/sve-probe-vls" + sve_stress_exec_cmd = "cd ${suite_dir}; timeout ${sve_exec_timeout} ./vlset --inherit %s ./sve-stress 2>/dev/null" + sve_ptrace_exec_cmd = "cd ${suite_dir}; ./sve-ptrace" + - no_host_sve_support: + host_without_sve = "yes" status_error = "yes" + expect_msg = ".*sve.* feature not supported by KVM" diff --git a/libvirt/tests/cfg/cpu/aarch64_gic_version.cfg b/libvirt/tests/cfg/cpu/aarch64_gic_version.cfg new file mode 100644 index 00000000000..12ecca07ada --- /dev/null +++ b/libvirt/tests/cfg/cpu/aarch64_gic_version.cfg @@ -0,0 +1,17 @@ +- aarch64_gic_version: + type = aarch64_gic_version + start_vm = "yes" + check_gic_command_host = "grep GIC /proc/interrupts | head -1" + check_gic_command_guest = "grep GIC /proc/interrupts | head -1" + only aarch64 + variants: + - gic_version_2: + gic_version = '2' + err_msg = "error: Failed to start domain" + status_error = "yes" + - gic_version_3: + gic_version = '3' + status_error = "no" + - gic_version_host: + gic_version = 'host' + status_error = "no" diff --git a/libvirt/tests/cfg/cpu/iothread.cfg b/libvirt/tests/cfg/cpu/iothread.cfg index 4c1589a579f..ad72ac143cb 100644 --- a/libvirt/tests/cfg/cpu/iothread.cfg +++ b/libvirt/tests/cfg/cpu/iothread.cfg @@ -5,7 +5,7 @@ - positive_test: variants: - iothread_config: - start_vm = "yes" + need_start_vm = "yes" variants: - only_iothread_id: iothread_ids = "6" @@ -15,7 +15,7 @@ iothread_ids = "2 4 6 8" iothread_num = "5" - defaultiothread_config: - start_vm = "yes" + need_start_vm = "yes" func_supported_since_libvirt_ver = (8, 5, 0) vm_attrs = {'defaultiothread': {'thread_pool_min': '8', 'thread_pool_max': '16'}} - thread_pool: @@ -30,7 +30,7 @@ - shutoff_vm: cmd_options = '--config' - live_vm: - start_vm = "yes" + need_start_vm = "yes" pre_vm_stats = "running" cmd_options = '' - iothreadpin: @@ -51,6 +51,19 @@ iothreadset_id = "1" iothreadset_val = "--poll-max-ns 2147483647 --poll-grow 2147483647 --poll-shrink 2147483647" test_operations = "iothreadset" + - iothread_cold_set: + func_supported_since_libvirt_ver = (9, 4, 0) + need_start_vm = "yes" + thread_pool_min = 2147483647 + thread-pool-max = 2147483647 + iothread_num = "2" + iothread_ids = "1 2" + iothreadset_id = "1" + iothreadset_val = "--thread-pool-min 2147483647 --thread-pool-max 2147483647 --poll-max-ns 2147483647 --poll-grow 2147483647 --poll-shrink 2147483647" + cmd_options = '--config' + iothread_config = {'iothread': [{'id': '2', 'thread_pool_min': '1', 'thread_pool_max': '1', 'poll': {'max': '1', 'grow': '1', 'shrink': '1'}}]} + test_operations = "iothreadset" + check_iotheadids_inactive = "yes" - disk_attach: pre_vm_stats = "running" create_disk = "yes" @@ -69,7 +82,7 @@ iothreadpins = "2:100" pseries, aarch64: iothreadpins = "2:300" - start_vm = "yes" + need_start_vm = "yes" err_msg = "Numerical result out of range|Invalid argument" - no_matchs_iothread: define_error = "yes" diff --git a/libvirt/tests/cfg/cpu/max_vcpus.cfg b/libvirt/tests/cfg/cpu/max_vcpus.cfg index f2bca771803..fddd0fb64ae 100644 --- a/libvirt/tests/cfg/cpu/max_vcpus.cfg +++ b/libvirt/tests/cfg/cpu/max_vcpus.cfg @@ -14,6 +14,7 @@ report_num_q35_7_8 = "384" report_num_q35_8_3 = "512" report_num_q35_8_4 = "710" + report_num_q35_9_6 = "4096" - positive_test: status_error = "no" variants: @@ -49,8 +50,8 @@ - no_iommu: only q35 check = "no_iommu" + status_error = "no" guest_vcpu = "256" - err_msg = "unsupported configuration: more than 255 vCPUs require extended interrupt mode enabled on the iommu device" - with_iommu: only q35 check = "with_iommu" @@ -59,5 +60,5 @@ - ioapic_iommu: only q35 check = "ioapic_iommu_ne" - guest_vcpu = "711" - err_msg = "unsupported configuration: Maximum CPUs greater than specified machine type limit|exceeds the maximum cpus supported" + guest_vcpu = "4097" + err_msg = "unsupported configuration: Maximum CPUs greater than specified machine type limit|exceeds the maximum cpus supported|CPU topology doesn't match maximum vcpu count" diff --git a/libvirt/tests/cfg/cpu/multi_vms_with_stress.cfg b/libvirt/tests/cfg/cpu/multi_vms_with_stress.cfg new file mode 100644 index 00000000000..128fca6b241 --- /dev/null +++ b/libvirt/tests/cfg/cpu/multi_vms_with_stress.cfg @@ -0,0 +1,5 @@ +- multi_vms_with_stress: + type = multi_vms_with_stress + memory = 4194304 + vm_names = vm2 vm3 + stress_args = '--cpu 4 --io 4 --vm 2 --vm-bytes 128M &' diff --git a/libvirt/tests/cfg/cpu/topology.cfg b/libvirt/tests/cfg/cpu/topology.cfg new file mode 100644 index 00000000000..eb86f4b15d4 --- /dev/null +++ b/libvirt/tests/cfg/cpu/topology.cfg @@ -0,0 +1,15 @@ +- topology: + type = topology + only Linux + start_vm = no + current_vcpus = 4 + max_vcpus = 4 + cores = 2 + threads = 1 + sockets = 2 + variants: + - positive: + variants: + - hotplug: + current_vcpus = 3 + diff --git a/libvirt/tests/cfg/cpu/vcpu_affinity.cfg b/libvirt/tests/cfg/cpu/vcpu_affinity.cfg index f2fd307f296..385c0e9a774 100644 --- a/libvirt/tests/cfg/cpu/vcpu_affinity.cfg +++ b/libvirt/tests/cfg/cpu/vcpu_affinity.cfg @@ -82,7 +82,7 @@ check = "vcpu_outrange_cpuset" config_xml = "vcpu" start_fail = "yes" - err_msg = "Numerical result out of range" + err_msg = "Numerical result out of range;Invalid value.*cpuset" - cputune: vcpu_cpuset = "0" variants: @@ -90,7 +90,7 @@ check = "cputune_outrange_cpuset" config_xml = "cputune" start_fail = "yes" - err_msg = "Numerical result out of range" + err_msg = "Numerical result out of range;Invalid value.*cpuset" - invalid_cpuset: check = "cputune_invalid_cpuset" config_xml = "cputune" diff --git a/libvirt/tests/cfg/cpu/vcpu_cve.cfg b/libvirt/tests/cfg/cpu/vcpu_cve.cfg index 676966371b7..c8f4c4de6a9 100644 --- a/libvirt/tests/cfg/cpu/vcpu_cve.cfg +++ b/libvirt/tests/cfg/cpu/vcpu_cve.cfg @@ -4,6 +4,7 @@ start_vm = no variants cpu_mode: - host_model: + no aarch64 cpu_mode = 'host-model' - host_passthrough: cpu_mode = 'host-passthrough' diff --git a/libvirt/tests/cfg/cpu/vcpu_feature.cfg b/libvirt/tests/cfg/cpu/vcpu_feature.cfg index bb91a5c82d5..2af78e5267b 100644 --- a/libvirt/tests/cfg/cpu/vcpu_feature.cfg +++ b/libvirt/tests/cfg/cpu/vcpu_feature.cfg @@ -3,7 +3,7 @@ start_vm = "no" cpu_check = "full" variants: - - policy_diable: + - policy_disable: feature_policy = "disable" - policy_require: feature_policy = "require" @@ -13,8 +13,19 @@ variants: - positive_test: variants: + - host_with_pauth: + only aarch64 + only policy_disable + func_supported_since_libvirt_ver = (10, 7, 0) + host_supported_feature = "yes" + feature_name = "pauth" + feature_check_name = "paca" + check_vm_feature = "yes" + check_qemu_pattern = "-cpu host,pauth=off" + cpu_check = "none" + start_vm = "yes" - host_with_vmx: - only policy_diable + only policy_disable host_supported_feature = "yes" feature_name = "vmx" check_vm_feature = "yes" @@ -27,3 +38,4 @@ host_supported_feature = "no" feature_name = "cr8legacy" err_msg = "guest CPU doesn't match specification: missing features: .*${feature_name}" + diff --git a/libvirt/tests/cfg/cpu/vcpu_max_topology.cfg b/libvirt/tests/cfg/cpu/vcpu_max_topology.cfg new file mode 100644 index 00000000000..cb82d45e257 --- /dev/null +++ b/libvirt/tests/cfg/cpu/vcpu_max_topology.cfg @@ -0,0 +1,28 @@ +- vcpu.max_topology: + type = vcpu_max_topology + memory = 4194304 + vcpus_placement = "static" + sockets = "" + cores = "" + clusters = "" + variants: + - one_socket: + sockets = "one" + cores = "many" + variants: + - default_clusters: + clusters = "" + - many_clusters: + clusters = "many" + - one_core_per_socket: + sockets = "many" + cores = "one" + clusters = "" + - many_cores_per_socket: + sockets = "many" + cores = "many" + variants: + - default_clusters: + clusters = "" + - many_clusters: + clusters = "many" diff --git a/libvirt/tests/cfg/cpu/vcpu_misc.cfg b/libvirt/tests/cfg/cpu/vcpu_misc.cfg index 3250ea833e3..da9788bc779 100644 --- a/libvirt/tests/cfg/cpu/vcpu_misc.cfg +++ b/libvirt/tests/cfg/cpu/vcpu_misc.cfg @@ -8,12 +8,17 @@ - snapshot: cpu_mode = "host-model" test_operations = "do_snapshot" - expected_str_before_startup = ${cpu_mode} + mem_file = " /tmp/mem_file" + snapshot_options = "{} --memspec ${mem_file}" expected_str_after_startup = 'mode="custom"' + aarch64: + cpu_mode = "host-passthrough" + expected_str_after_startup = ${cpu_mode} pseries: expected_str_after_startup = ${cpu_mode} + expected_str_before_startup = ${cpu_mode} - vendor_id: - no pseries, s390x + no pseries, s390x, aarch64 cpu_mode = "host-model" check_vendor_id = "yes" - with_topology: @@ -32,8 +37,9 @@ expected_str_after_startup = 'mode="host-passthrough"' customize_cpu_features = "yes" - with_maxphysaddr: - no s390-virtio - func_supported_since_libvirt_ver = (9, 3, 0) + cpu_mode = "host-model" + no s390-virtio,aarch64 + func_supported_since_libvirt_ver = (9, 3, 0) maxphysaddr = {'mode': 'passthrough', 'limit':'%d'} expected_qemuline = "host-phys-bits-limit=%s" cmd_in_guest = "lscpu|grep Address" diff --git a/libvirt/tests/cfg/cpu/vcpupin.cfg b/libvirt/tests/cfg/cpu/vcpupin.cfg index f351f25c240..0901b0476ea 100644 --- a/libvirt/tests/cfg/cpu/vcpupin.cfg +++ b/libvirt/tests/cfg/cpu/vcpupin.cfg @@ -3,6 +3,7 @@ vcpu_placement = 'static' vcpu_max = 4 vcpu_current = 2 + update_xml = yes variants: - positive: variants test_case: @@ -16,3 +17,8 @@ - vcpupin_current_inactive_vm: vcpupin_conf = "{'0': 'x,y', '1': 'x-y,^z', '2': 'x-y,^z,m', '3': 'r'}" affinity_pattern = 'CPU Affinity:\s*(.*) .*out of' + - cpuset_limilted_in_cgroup: + update_xml = no + vcpu_max = 2 + vcpupin_conf = {'0': '2', '1': '4'} + vm_attrs = {'cputune': {'vcpupins': [{'vcpu': '0', 'cpuset': '2'}, {'vcpu': '1', 'cpuset': '4'}]}} diff --git a/libvirt/tests/cfg/virsh_cmd/domain/virsh_cpu_compare_xml.cfg b/libvirt/tests/cfg/cpu/virsh_cpu_compare_xml.cfg similarity index 88% rename from libvirt/tests/cfg/virsh_cmd/domain/virsh_cpu_compare_xml.cfg rename to libvirt/tests/cfg/cpu/virsh_cpu_compare_xml.cfg index 7bcc41ee5d6..a83cce44149 100644 --- a/libvirt/tests/cfg/virsh_cmd/domain/virsh_cpu_compare_xml.cfg +++ b/libvirt/tests/cfg/cpu/virsh_cpu_compare_xml.cfg @@ -8,6 +8,7 @@ compare_file_type = "domxml" variants: - custom_mode: + no aarch64 cpu_mode = "custom" status_error = "yes" msg_pattern = "incompatible" @@ -19,6 +20,11 @@ variants: - action_none: msg_pattern = "identical" + - change_vendor: + no s390_virtio, ppc64le + cpu_compare_mode = "modify" + msg_pattern = "incompatible" + status_error = "yes" - delete_features: cpu_compare_mode = "delete" status_error = "no" diff --git a/libvirt/tests/cfg/cpu/vm_features.cfg b/libvirt/tests/cfg/cpu/vm_features.cfg index b33c14e7bcb..66220594efe 100644 --- a/libvirt/tests/cfg/cpu/vm_features.cfg +++ b/libvirt/tests/cfg/cpu/vm_features.cfg @@ -14,6 +14,24 @@ - tlbflush: func_supported_since_libvirt_ver = (5, 0, 0) hyperv_attr = {'relaxed': {'state': 'on'}, 'vapic': {'state': 'on'}, 'vpindex': {'state': 'on'}, 'tlbflush': {'state': 'on'}} + - tlbflush_direct_extended: + func_supported_since_libvirt_ver = (10, 10, 0) + hyperv_attr = {'tlbflush': {'state': 'on', 'direct':{'state': 'on'}, 'extended':{'state': 'on'}}, 'vapic': {'state': 'on'}, 'vpindex': {'state': 'on'},'relaxed': {'state': 'on'}} + qemu_include = 'hv-tlbflush=on,hv-tlbflush-direct=on,hv-tlbflush-ext=on' + expected_xpaths = [{'element_attrs':['.//tlbflush[@state="on"]']},{'element_attrs':['.//tlbflush/direct[@state="on"]']},{'element_attrs':['.//tlbflush/extended[@state="on"]']}] + check_xml = "yes" + - emsr_bitmap: + func_supported_since_libvirt_ver = (10, 10, 0) + hyperv_attr = {'emsr_bitmap': {'state': 'on'}} + qemu_include = 'hv-emsr-bitmap=on' + check_xml = "yes" + expected_xpaths = [{'element_attrs':['.//emsr_bitmap[@state="on"]']}] + - xmm_input: + func_supported_since_libvirt_ver = (10, 10, 0) + hyperv_attr = {'xmm_input': {'state': 'on'}} + qemu_include = 'hv-xmm-input=on' + check_xml = "yes" + expected_xpaths = [{'element_attrs':['.//xmm_input[@state="on"]']}] - frequencies: func_supported_since_libvirt_ver = (5, 0, 0) hyperv_attr = {'relaxed': {'state': 'on'}, 'vapic': {'state': 'on'}, 'vpindex': {'state': 'on'}, 'frequencies': {'state': 'on'}} @@ -26,6 +44,9 @@ hyperv_attr={'relaxed': {'state': 'on'}} - disable: hyperv_attr={'relaxed': {'state': 'on'}} + - passthrough: + hyperv_attr = {'mode': 'passthrough'} + qemu_include = 'hv-passthrough=on' - pmu: no pseries, s390-virtio variants: diff --git a/libvirt/tests/cfg/daemon/check_socket_files_with_services.cfg b/libvirt/tests/cfg/daemon/check_socket_files_with_services.cfg new file mode 100644 index 00000000000..717aa8c87c7 --- /dev/null +++ b/libvirt/tests/cfg/daemon/check_socket_files_with_services.cfg @@ -0,0 +1,5 @@ +- daemon.check_socket_files_with_services: + type = check_socket_files_with_services + start_vm = no + service_list = ['qemu', 'interface', 'network', 'nodedev', 'nwfilter', 'secret', 'storage', 'proxy'] + other_socket_files = ['virtlockd-sock', 'virtlogd-sock'] diff --git a/libvirt/tests/cfg/daemon/check_users.cfg b/libvirt/tests/cfg/daemon/check_users.cfg new file mode 100644 index 00000000000..26589e9b1ee --- /dev/null +++ b/libvirt/tests/cfg/daemon/check_users.cfg @@ -0,0 +1,5 @@ +- daemon.check_users: + type = check_users + func_supported_since_libvirt_ver = (10, 10, 0) + start_vm = no + users_list = ['g qemu', 'g libvirt', 'g kvm', 'u qemu', 'm qemu kvm'] diff --git a/libvirt/tests/cfg/daemon/check_virsh_connection_switch_between_monolithic_and_modular.cfg b/libvirt/tests/cfg/daemon/check_virsh_connection_switch_between_monolithic_and_modular.cfg new file mode 100644 index 00000000000..b1e24099973 --- /dev/null +++ b/libvirt/tests/cfg/daemon/check_virsh_connection_switch_between_monolithic_and_modular.cfg @@ -0,0 +1,3 @@ +- daemon.check_virsh_connection_switch_between_monolithic_and_modular: + type = check_virsh_connection_switch_between_monolithic_and_modular + start_vm = no diff --git a/libvirt/tests/cfg/daemon/conf_file/libvirtd_conf/check_negative_parameter.cfg b/libvirt/tests/cfg/daemon/conf_file/libvirtd_conf/check_negative_parameter.cfg new file mode 100644 index 00000000000..13099069b9e --- /dev/null +++ b/libvirt/tests/cfg/daemon/conf_file/libvirtd_conf/check_negative_parameter.cfg @@ -0,0 +1,47 @@ +- conf_file.libvirtd_conf.check_negative_parameter: + type = check_negative_parameter + start_vm = no + log_file = "/var/log/messages" + require_modular_daemon = "yes" + variants parameter_name: + - listen_tcp: + only virtproxyd + parameter_value = "-1" + - listen_tls: + only virtproxyd + parameter_value = "-40" + - tls_no_sanity_certificate: + only virtproxyd + parameter_value = "-1" + - max_clients: + parameter_value = "-1" + - max_queued_clients: + parameter_value = "-1" + - max_anonymous_clients: + parameter_value = "-1" + - max_workers: + parameter_value = "-1" + - min_workers: + parameter_value = "-1" + - prio_workers: + parameter_value = "-1" + - max_client_requests: + parameter_value = "-5" + - audit_level: + parameter_value = "-2" + - audit_logging: + parameter_value = "-1" + - log_level: + parameter_value = "-1" + - keepalive_count: + parameter_value = "-5" + variants daemon_name: + - virtqemud: + - virtnwfilterd: + - virtinterfaced: + - virtsecretd: + - virtproxyd: + - virtstoraged: + - virtnodedevd: + - virtnetworkd: + check_string_in_log = "load config file: internal error: /etc/libvirt/${daemon_name}.conf" diff --git a/libvirt/tests/cfg/daemon/conf_file/libvirtd_conf/set_audit_logging.cfg b/libvirt/tests/cfg/daemon/conf_file/libvirtd_conf/set_audit_logging.cfg index 2178b2a1b0a..6892a29cae0 100644 --- a/libvirt/tests/cfg/daemon/conf_file/libvirtd_conf/set_audit_logging.cfg +++ b/libvirt/tests/cfg/daemon/conf_file/libvirtd_conf/set_audit_logging.cfg @@ -3,8 +3,21 @@ start_vm = no variants: - positive_test: - variants: + variants test_scenario: - disable_audit_log: enable_audit = no - enable_audit_log: enable_audit = yes + - default_audit_log: + enable_audit = yes + set_audit_level = "no" + ausearch_type_list = "VIRT_CONTROL VIRT_MACHINE_ID VIRT_RESOURCE" + - concurrent_filters: + enable_audit = yes + set_audit_level = "no" + log_filters="1:qemu 1:libvirt 4:object 4:json 4:event 1:util" + log_for_object = 'debug : virObject|info : virObject|warning : virObject' + log_for_json = 'debug : virJSON|info : virJSON|warning : virJSON' + log_for_event = 'debug : virEvent|info : virEvent|warning : virEvent' + log_for_filter_list = "["${log_for_object}", "${log_for_json}", "${log_for_event}"]" + log_for_util = 'virConf' diff --git a/libvirt/tests/cfg/daemon/conf_file/libvirtd_conf/virt_admin_logging.cfg b/libvirt/tests/cfg/daemon/conf_file/libvirtd_conf/virt_admin_logging.cfg index f0fb2b1490c..42727934073 100644 --- a/libvirt/tests/cfg/daemon/conf_file/libvirtd_conf/virt_admin_logging.cfg +++ b/libvirt/tests/cfg/daemon/conf_file/libvirtd_conf/virt_admin_logging.cfg @@ -18,7 +18,7 @@ str_to_grep = "journal" - libvirtd_virt_admin_log_output: enable_libvirtd_debug_log = "no" - log_outputs = "3:journald" + log_outputs = "3:journald|3:stderr" enable_journal_socket = "no" virt_disk_device_source = "/var/lib/libvirt/images/no_existed_libvirtd.qcow2" log_file_path = "/var/log/messages" diff --git a/libvirt/tests/cfg/daemon/conf_file/qemu_conf/set_virtlogd.cfg b/libvirt/tests/cfg/daemon/conf_file/qemu_conf/set_virtlogd.cfg index 0805480214d..808f5723212 100644 --- a/libvirt/tests/cfg/daemon/conf_file/qemu_conf/set_virtlogd.cfg +++ b/libvirt/tests/cfg/daemon/conf_file/qemu_conf/set_virtlogd.cfg @@ -32,8 +32,126 @@ - disabled_virtlogd: expected_result = virtlogd_disabled start_vm = no + - specific_config_file: + expected_result = virtlogd_specific_config_file_enable + virtlogd_config_file = "/etc/sysconfig/virtlogd" + virtlogd_config_bak_file = "/etc/sysconfig/virtlogd.bak" + virtlogd_config_file_new = "/etc/libvirt/virtlogd-new.conf" + virtlogd_config_file_alternative_new = "/var/log/libvirt/virtlogd-new.log" + start_vm = no + - specific_timeout: + expected_result = virtlogd_specific_timeout + virtlogd_config_file = "/etc/sysconfig/virtlogd" + virtlogd_config_bak_file = "/etc/sysconfig/virtlogd.bak" + virtlogd_config_file_new = "/etc/libvirt/virtlogd-new.conf" + start_vm = no + - record_qenu_crash_log: + expected_result = record_qenu_crash_log + crash_information = "unable to map backing store for guest RAM: Cannot allocate memory" + start_vm = no + - stop_virtlogd: + expected_result = stop_virtlogd + start_vm = no + - default_max_size_max_backups: + expected_result = default_max_size_max_backups + max_backups = 3 + start_vm = no + - recreate_qemu_log: + expected_result = recreate_qemu_log + start_vm = no + - opened_fd_of_qemu_log_file: + expected_result = opened_fd_of_qemu_log_file + start_vm = no + - vm_destroy_log_into_qemu_log_file: + expected_result = vm_destroy_log_into_qemu_log_file + start_vm = no + - start_vm_twice_log_into_qemu_log_file: + expected_result = start_vm_twice_log_into_qemu_log_file + start_vm = no + - record_save_restore_guest_log: + expected_result = record_save_restore_guest_log + start_vm = no + save_vm_path = "/tmp/test1.save" + - valid_max_clients: + expected_result = valid_max_clients + max_clients = 20 + start_vm = no + action = "restart" + virtlogd_log_file = "/var/log/libvirt/virtlogd.log" + - valid_boundary_max_clients: + expected_result = valid_boundary_max_clients + low_max_clients = 0 + high_max_clients = 4294967295 + start_vm = no + virtlogd_log_file = "/var/log/libvirt/virtlogd.log" + action = "restart" + - nclients_occupied_released: + expected_result = nclients_occupied_released + max_clients = 20 + virtlogd_log_file = "/var/log/libvirt/virtlogd.log" + nclients = 'nclients=1.*nclients_unauth=0' + save_vm_path = "/tmp/test1.save" + action = "restart" + start_vm = no + - guest_runnning_after_virtlogd_crash: + expected_result = guest_runnning_after_virtlogd_crash + start_vm = no + stdio_handler = "logd" + - reload_new_config: + expected_result = reload_new_config + start_vm = no + action = "reload" + virtlogd_file_new = "/var/log/libvirt/virtlogd_new.log" + virtlogd_log_file = "/var/log/libvirt/virtlogd.log" + - log_filters_not_same_with_loglevel: + expected_result = log_filters_not_same_with_loglevel + start_vm = no + action = "restart" + filter_loglevel_1 = "debug.*virLogDaemonClientFree" + filter_loglevel_2 = "info.*virEventGLibHandleUpdate" + filter_loglevel_3 = "debug.*virNetServerProgramNew" + filter_loglevel_4 = "error : virPidFileAcquirePath" + log_filters = "1:+logging 2:event 3:rpc" + log_level = 4 + virtlogd_file = "/var/log/libvirt/virtlogd.log" + - reload_max_size_config: + expected_result = reload_max_size_config + start_vm = no + action = "reload" + max_size = 204800 + - set_max_size_config: + expected_result = set_max_size_config + start_vm = no + action = "restart" + max_size = 204800 + - set_max_backups: + expected_result = set_max_backups + max_backups = 2 + start_vm = no + action = "restart" + - reload_max_backups: + expected_result = reload_max_backups + max_backups = 4 + max_size = 204800 + action = "reload" + start_vm = no - negative_test: variants: - invalid: expected_result = unbootable stdio_handler = 'invalid' + - invalid_boundary_max_clients: + expected_result = invalid_boundary_max_clients + low_max_clients = -1 + high_max_clients = 4294967296 + start_vm = no + action = "restart" + - invalid_virtlogd_conf: + start_vm = no + expected_result = 'invalid_virtlogd_conf' + max_clients = 'invalid' + variants: + - reload_virtlogd: + action = "reload" + - restart_virtlogd: + action = "restart" diff --git a/libvirt/tests/cfg/daemon/conf_file/sysconfig_libvirt_guests/libvirt_guests.cfg b/libvirt/tests/cfg/daemon/conf_file/sysconfig_libvirt_guests/libvirt_guests.cfg index f4fd29e6b4e..8ec3059b212 100644 --- a/libvirt/tests/cfg/daemon/conf_file/sysconfig_libvirt_guests/libvirt_guests.cfg +++ b/libvirt/tests/cfg/daemon/conf_file/sysconfig_libvirt_guests/libvirt_guests.cfg @@ -5,11 +5,36 @@ - positive_test: status_error = "no" shutdown_timeout = 300 + variants: + - without_transient_vm: + - with_transient_vm: + only no_parallel_shutdown.suspend_on_shutdown.default_vol.none_on_boot, no_parallel_shutdown.shutdown_on_shutdown.none_on_boot + func_supported_since_libvirt_ver = (10, 3, 0) + start_vm = "no" + transient_vm = "yes" + additional_vms = 1 + on_boot = "" + shutdown_timeout = "" + parallel_shutdown = "" + variants: + - persistent_only_none: + only suspend_on_shutdown + persistent_only = "" + transient_vm_operation = "nothing" + - persistent_only_true: + persistent_only = "true" + transient_vm_operation = "nothing" + - persistent_only_default: + only suspend_on_shutdown + persistent_only = "default" + transient_vm_operation = "nothing" variants: - start_on_boot: on_boot = "start" - ignore_on_boot: on_boot = "ignore" + - none_on_boot: + on_boot = "" variants: - suspend_on_shutdown: on_shutdown = "suspend" diff --git a/libvirt/tests/cfg/daemon/enable_disable_daemon_socket_services.cfg b/libvirt/tests/cfg/daemon/enable_disable_daemon_socket_services.cfg new file mode 100644 index 00000000000..eeabd3d5951 --- /dev/null +++ b/libvirt/tests/cfg/daemon/enable_disable_daemon_socket_services.cfg @@ -0,0 +1,17 @@ +- daemon.enable_disable_daemon_socket_services: + type = enable_disable_daemon_socket_services + start_vm = no + service_list = ['qemu', 'interface', 'network', 'nodedev', 'nwfilter', 'secret', 'storage', 'proxy'] + variants: + - main_socket: + service_list = ['qemu', 'interface', 'network', 'nodedev', 'nwfilter', 'secret', 'storage'] + sock_type = + - ro_socket: + service_list = ['qemu', 'interface', 'network', 'nodedev', 'nwfilter', 'secret', 'storage'] + sock_type = -ro + - admin_socket: + service_list = ['qemu', 'interface', 'network', 'nodedev', 'nwfilter', 'secret', 'storage'] + sock_type = -admin + - only_virtproxyd: + service_list = ['proxy'] + sock_type = diff --git a/libvirt/tests/cfg/daemon/libvirtd/libvirtd.cfg b/libvirt/tests/cfg/daemon/libvirtd/libvirtd.cfg index 540a5eb105d..5fa7f02f23d 100644 --- a/libvirt/tests/cfg/daemon/libvirtd/libvirtd.cfg +++ b/libvirt/tests/cfg/daemon/libvirtd/libvirtd.cfg @@ -19,3 +19,31 @@ libvirtd_conf_dict = {'listen_tls': '0'} daemons_masked = 'libvirtd.socket libvirtd-ro.socket libvirtd-admin.socket libvirtd-tls.socket libvirtd-tcp.socket' sysconfig_conf_path = '/etc/sysconfig/libvirtd' + - check_max_anonymous_clients: + start_vm = no + log_level = 1 + log_filters = "1:*" + conf_list = ["max_anonymous_clients"] + check_string_in_log = "nclients_unauth_max=20" + require_modular_daemon = "yes" + variants daemon_name: + - libvirtd: + virsh_uri = "qemu:///system" + require_modular_daemon = "no" + - virtqemud: + virsh_uri = "qemu:///system" + - virtnwfilterd: + virsh_uri = "nwfilter:///system" + - virtinterfaced: + virsh_uri = "interface:///system" + - virtsecretd: + virsh_uri = "secret:///system" + - virtproxyd: + virsh_uri = "qemu+tcp:///system" + - virtstoraged: + virsh_uri = "storage:///system" + - virtnodedevd: + virsh_uri = "nodedev:///system" + - virtnetworkd: + virsh_uri = "network:///system" + log_file = "/var/log/libvirt/${daemon_name}.log" diff --git a/libvirt/tests/cfg/daemon/qemu_monitor_socket_creation_delay.cfg b/libvirt/tests/cfg/daemon/qemu_monitor_socket_creation_delay.cfg new file mode 100644 index 00000000000..04845cfa529 --- /dev/null +++ b/libvirt/tests/cfg/daemon/qemu_monitor_socket_creation_delay.cfg @@ -0,0 +1,8 @@ +- daemon.qemu_monitor_socket_creation_delay: + type = qemu_monitor_socket_creation_delay + start_vm = no + check_image = no + take_regular_screendumps = no + qemu_wrapper_path = "../../deps/qemu_wrapper.py" + tmp_qemu_wrapper_path = "/tmp/qemu_wrapper.py" + emulator_dict = {"path": "${tmp_qemu_wrapper_path}"} diff --git a/libvirt/tests/cfg/event/virsh_event.cfg b/libvirt/tests/cfg/event/virsh_event.cfg index 623d255f51e..ecc8e818d84 100644 --- a/libvirt/tests/cfg/event/virsh_event.cfg +++ b/libvirt/tests/cfg/event/virsh_event.cfg @@ -57,6 +57,7 @@ only test_events events_list = "kill_qemu" signal = 'SIGKILL' + skip_cluster_leak_warn = "yes" - reboot_event: event_name = "reboot" events_list = "reset" @@ -116,10 +117,14 @@ max_mem = 25600000 maxmem_slots = "16" mem_unit = "KiB" - memory = 4048896 - current_mem = 4048896 + memory = 1572864 + current_mem = 1572864 dimm_unit = "m" dimm_size = 128 + cpu_mode = 'host-model' + aarch64: + cpu_mode = 'host-passthrough' + dimm_size = 1024 expected_fails = "unplug of device was rejected by the guest" - watchdog_event: event_all_option = "yes" @@ -194,3 +199,4 @@ # Test virsh qemu_monitor_event no invalid_event qemu_monitor_test = "yes" + diff --git a/libvirt/tests/cfg/features/ras.cfg b/libvirt/tests/cfg/features/ras.cfg new file mode 100644 index 00000000000..ecab1808fd4 --- /dev/null +++ b/libvirt/tests/cfg/features/ras.cfg @@ -0,0 +1,14 @@ +- features.ras: + type = ras + start_vm = no + only aarch64 + func_supported_since_libvirt_ver = (10, 4, 0) + unsupported_err_msg = "Ras feature is not supported on current version." + variants: + - on: + ras_state = on + - off: + ras_state = off + variants: + - positive_test: + status_error = "no" diff --git a/libvirt/tests/cfg/gpu/hotplug_gpu.cfg b/libvirt/tests/cfg/gpu/hotplug_gpu.cfg new file mode 100644 index 00000000000..fbd941b2639 --- /dev/null +++ b/libvirt/tests/cfg/gpu/hotplug_gpu.cfg @@ -0,0 +1,8 @@ +- gpu.hotplug_gpu: + type = hotplug_gpu + start_vm = "no" + + only aarch64 + variants: + - gpu_address: + hostdev_dict = {'mode': 'subsystem', 'type': 'pci', 'source': {'untyped_address': gpu_pci_addr}, 'managed': 'yes'} diff --git a/libvirt/tests/cfg/gpu/lifecycle_vm_with_gpu.cfg b/libvirt/tests/cfg/gpu/lifecycle_vm_with_gpu.cfg new file mode 100644 index 00000000000..dbeb02931b3 --- /dev/null +++ b/libvirt/tests/cfg/gpu/lifecycle_vm_with_gpu.cfg @@ -0,0 +1,9 @@ +- gpu.lifecycle_vm_with_gpu: + type = lifecycle_vm_with_gpu + start_vm = "no" + unsupported_error = "VFIO migration is not supported in kernel" + + only aarch64 + variants: + - gpu_address: + hostdev_dict = {'mode': 'subsystem', 'type': 'pci', 'source': {'untyped_address': gpu_pci_addr}, 'managed': 'yes'} diff --git a/libvirt/tests/cfg/gpu/start_vm_with_gpu.cfg b/libvirt/tests/cfg/gpu/start_vm_with_gpu.cfg new file mode 100644 index 00000000000..a6c0e4e9ca4 --- /dev/null +++ b/libvirt/tests/cfg/gpu/start_vm_with_gpu.cfg @@ -0,0 +1,14 @@ +- gpu.start_vm_with_gpu: + type = start_vm_with_gpu + start_vm = "no" + + only aarch64 + variants: + - gpu_address: + variants: + - managed_yes: + hostdev_dict = {'mode': 'subsystem', 'type': 'pci', 'source': {'untyped_address': gpu_pci_addr}, 'managed': 'yes'} + - managed_no: + hostdev_dict = {'mode': 'subsystem', 'type': 'pci', 'source': {'untyped_address': gpu_pci_addr}, 'managed': 'no'} + - managed_ignore: + hostdev_dict = {'mode': 'subsystem', 'type': 'pci', 'source': {'untyped_address': gpu_pci_addr}} diff --git a/libvirt/tests/cfg/gpu/start_vm_with_gpu_managed_disabled.cfg b/libvirt/tests/cfg/gpu/start_vm_with_gpu_managed_disabled.cfg new file mode 100644 index 00000000000..4e74751e75e --- /dev/null +++ b/libvirt/tests/cfg/gpu/start_vm_with_gpu_managed_disabled.cfg @@ -0,0 +1,16 @@ +- gpu.managed_disabled_gpu: + type = start_vm_with_gpu_managed_disabled + start_vm = "no" + error_msg = "Unmanaged PCI device" + + only aarch64 + variants: + - gpu_address: + variants: + - managed_no: + hostdev_dict = {'mode': 'subsystem', 'type': 'pci', 'source': {'untyped_address': gpu_pci_addr}, 'managed': 'no'} + - managed_ignore: + hostdev_dict = {'mode': 'subsystem', 'type': 'pci', 'source': {'untyped_address': gpu_pci_addr}} + variants test_scenario: + - define_start: + - hotplug: diff --git a/libvirt/tests/cfg/gpu/vm_cuda_sanity.cfg b/libvirt/tests/cfg/gpu/vm_cuda_sanity.cfg new file mode 100644 index 00000000000..ceba493922b --- /dev/null +++ b/libvirt/tests/cfg/gpu/vm_cuda_sanity.cfg @@ -0,0 +1,10 @@ +- gpu.vm_cuda_sanity: + type = vm_cuda_sanity + start_vm = "no" + cuda_samples_path = "http://download.libvirt.redhat.com/libvirt-CI-resources/gpu/cuda-samples.tar.gz" + cuda_tests = ["./cuda-samples/build/Samples/1_Utilities/deviceQuery/deviceQuery", "./cuda-samples/build/Samples/1_Utilities/bandwidthTest/bandwidthTest", "./cuda-samples/build/Samples//0_Introduction/simpleMultiCopy/simpleMultiCopy"] + + only aarch64 + variants: + - gpu_address: + hostdev_dict = {'mode': 'subsystem', 'type': 'pci', 'source': {'untyped_address': gpu_pci_addr}, 'managed': 'yes'} diff --git a/libvirt/tests/cfg/gpu/vm_mig_sanity.cfg b/libvirt/tests/cfg/gpu/vm_mig_sanity.cfg new file mode 100644 index 00000000000..39b77f76d8b --- /dev/null +++ b/libvirt/tests/cfg/gpu/vm_mig_sanity.cfg @@ -0,0 +1,10 @@ +- gpu.mig_sanity: + type = vm_mig_sanity + start_vm = "no" + cuda_samples_path = "http://download.libvirt.redhat.com/libvirt-CI-resources/gpu/cuda-samples.tar.gz" + cuda_test = "./cuda-samples/build/Samples/5_Domain_Specific/BlackScholes/BlackScholes" + + only aarch64 + variants: + - gpu_address: + hostdev_dict = {'mode': 'subsystem', 'type': 'pci', 'source': {'untyped_address': gpu_pci_addr}, 'managed': 'yes'} diff --git a/libvirt/tests/cfg/gpu/vm_nvidia_gpu_driver.cfg b/libvirt/tests/cfg/gpu/vm_nvidia_gpu_driver.cfg new file mode 100644 index 00000000000..a7f9ef175b8 --- /dev/null +++ b/libvirt/tests/cfg/gpu/vm_nvidia_gpu_driver.cfg @@ -0,0 +1,8 @@ +- gpu.nvidia_driver: + type = vm_nvidia_gpu_driver + start_vm = "no" + + only aarch64 + variants: + - gpu_address: + hostdev_dict = {'mode': 'subsystem', 'type': 'pci', 'source': {'untyped_address': gpu_pci_addr}, 'managed': 'yes'} diff --git a/libvirt/tests/cfg/graphics/graphics_functional.cfg b/libvirt/tests/cfg/graphics/graphics_functional.cfg index 36f6aba92db..8bbea5789c2 100644 --- a/libvirt/tests/cfg/graphics/graphics_functional.cfg +++ b/libvirt/tests/cfg/graphics/graphics_functional.cfg @@ -225,6 +225,11 @@ need_vnc_dict = "no" check_dom_xml = "yes" check_qemu_pattern = '-vnc none' + - listen_type_non_exist: + vnc_listen_type = "not_exist" + vnc_autoport = "not_set" + need_vnc_dict = "no" + check_dom_xml = "yes" - listen_type_address: vnc_listen_type = 'address' variants: @@ -334,6 +339,24 @@ valid_time = 60 opt_str = " --gtk-vnc-debug" rv_log_auth = "Authentication failed" + - check_with_domdisplay: + check_with_domdisplay = "yes" + vnc_passwd_place = "guest" + vnc_autoport = "yes" + variants: + - include_password_no: + - include_password_yes: + domdisplay_options = "--include-password" + - disable_fips: + vnc_autoport = "yes" + check_fips = "yes" + check_qemu_pattern = "-enable-fips" + expect_exist = False + variants: + - without_passwd: + - with_passwd: + graphic_passwd = "PASSWORD.EXAMPLE" + vnc_passwd_place = "guest" - spice_vnc: spice_xml = yes vnc_xml = yes @@ -425,10 +448,12 @@ - port_-2: vnc_port = -2 - port_0: + check_dom_xml = "yes" vnc_port = 0 - port_1: vnc_port = 1 - port_65536: + check_dom_xml = "yes" vnc_port = 65536 - without_cert: vnc_tls = 1 diff --git a/libvirt/tests/cfg/guest_agent/guest_agent.cfg b/libvirt/tests/cfg/guest_agent/guest_agent.cfg index c63fa507fff..bce252849b8 100644 --- a/libvirt/tests/cfg/guest_agent/guest_agent.cfg +++ b/libvirt/tests/cfg/guest_agent/guest_agent.cfg @@ -10,8 +10,12 @@ only ga_started hotunplug_ga = "yes" - customize_source_path: - src_path = '/test/agent' con_label = "system_u:object_r:qemu_var_run_t:s0" + variants: + - auto_gen_path: + src_path = "/var/org.qemu.guest_agent.0" + - random: + src_path = "/var/agent" - hotplug_ga_without_tgt_type: only ga_started hotplug_ga_without_tgt_type = "yes" diff --git a/libvirt/tests/cfg/guest_agent/unix_source_path/agent_auto_generated_unix_source_path_session_mode.cfg b/libvirt/tests/cfg/guest_agent/unix_source_path/agent_auto_generated_unix_source_path_session_mode.cfg new file mode 100644 index 00000000000..7ee3887733d --- /dev/null +++ b/libvirt/tests/cfg/guest_agent/unix_source_path/agent_auto_generated_unix_source_path_session_mode.cfg @@ -0,0 +1,7 @@ +- agent.auto_generated.unix_source_path.session_mode: + type = agent_auto_generated_unix_source_path_session_mode + start_vm = "no" + test_user = USER.EXAMPLE + test_passwd = PASSWORD.EXAMPLE + unpr_vm_name = UNPRIVILEGED_VM.EXAMPLE + func_supported_since_libvirt_ver = (9, 9, 0) diff --git a/libvirt/tests/cfg/guest_kernel_debugging/guest_kdump.cfg b/libvirt/tests/cfg/guest_kernel_debugging/guest_kdump.cfg new file mode 100644 index 00000000000..ecd35787550 --- /dev/null +++ b/libvirt/tests/cfg/guest_kernel_debugging/guest_kdump.cfg @@ -0,0 +1,47 @@ +- guest_kernel_debugging.guest_kdump: + type = guest_kdump + main_vm = "avocado-vm" + vms = "vm" + mem = "32768" + take_regular_screendumps = "no" + login_timeout = 240 + guest_stress = "no" + stress_time = "300" + guest_upstream_kernel = "no" + crash_utility = "no" + crash_dir = "/var/crash/" + debug_dir = "/home/" + dump_options = "--memory-only --bypass-cache" + start_vm = "yes" + kill_vm = "yes" + variants: + - kdump_no_stress: + - kdump_with_stress: + guest_stress = "yes" + - kdump_with_stress_crash_utility: + crash_utility = "yes" + guest_stress = "yes" + - two_guests_kdump_no_stress: + vms = "vm1 vm2" + mem = "10000" + - two_guests_kdump_with_stress: + vms = "vm1 vm2" + mem = "10000" + guest_stress = "yes" + - two_guests_kdump_with_stress_crash_utility: + vms = "vm1 vm2" + mem = "10000" + crash_utility = "yes" + guest_stress = "yes" + - four_guests_kdump_no_stress: + vms = "vm1 vm2 vm3 vm4" + mem = "5000" + - four_guests_kdump_with_stress: + vms = "vm1 vm2 vm3 vm4" + mem = "5000" + guest_stress = "yes" + - four_guests_kdump_with_stress_crash_utility: + vms = "vm1 vm2 vm3 vm4" + mem = "5000" + crash_utility = "yes" + guest_stress = "yes" diff --git a/libvirt/tests/cfg/guest_kernel_debugging/nmi_test.cfg b/libvirt/tests/cfg/guest_kernel_debugging/nmi_test.cfg index 6525485dc70..7ef69bc0d78 100644 --- a/libvirt/tests/cfg/guest_kernel_debugging/nmi_test.cfg +++ b/libvirt/tests/cfg/guest_kernel_debugging/nmi_test.cfg @@ -18,3 +18,7 @@ # using inject-nmi and qemu-monitor-command to send nmi, # so the expected times are 2 for Non-maskable interrupts expected_nmi_times = 2 + check_qemu_monitor = yes + s390-virtio: + expected_nmi_times = 0 + check_qemu_monitor = no diff --git a/libvirt/tests/cfg/virsh_cmd/domain/virsh_dump.cfg b/libvirt/tests/cfg/guest_kernel_debugging/virsh_dump.cfg similarity index 80% rename from libvirt/tests/cfg/virsh_cmd/domain/virsh_dump.cfg rename to libvirt/tests/cfg/guest_kernel_debugging/virsh_dump.cfg index 163e930c580..117e3c5c5c0 100644 --- a/libvirt/tests/cfg/virsh_cmd/domain/virsh_dump.cfg +++ b/libvirt/tests/cfg/guest_kernel_debugging/virsh_dump.cfg @@ -95,3 +95,24 @@ setup_libvirt_polkit = "yes" unprivileged_user = "EXAMPLE" virsh_uri = "qemu:///system" + - no_space_left: + dump_options = "--memory-only" + dump_dir = "/var/tmp/too_small" + - crash_utility_tests: + crash_utility = "yes" + variants: + - memory_dump: + dump_options = "--memory-only" + variants: + - elf_format: + memory_dump_format = 'elf' + - kdump-zlib_format: + memory_dump_format = 'kdump-zlib' + - kdump-lzo_format: + memory_dump_format = 'kdump-lzo' + - kdump-snappy_format: + memory_dump_format = 'kdump-snappy' + - memory_crash_dump: + dump_options = "--crash --memory-only" + - memory_bypass_cache_dump: + dump_options = "--memory-only --bypass-cache --verbose" diff --git a/libvirt/tests/cfg/guest_os_booting/boot_menu/bootmenu.cfg b/libvirt/tests/cfg/guest_os_booting/boot_menu/bootmenu.cfg index a2ac19afc1f..e94a6d46cc0 100644 --- a/libvirt/tests/cfg/guest_os_booting/boot_menu/bootmenu.cfg +++ b/libvirt/tests/cfg/guest_os_booting/boot_menu/bootmenu.cfg @@ -3,6 +3,8 @@ start_vm = no bootmenu_enable = "yes" bootmenu_dict = {'bootmenu_enable': '%s', 'bootmenu_timeout': '%s', 'bios_useserial': 'yes'} + aarch64: + bootmenu_dict = {'bootmenu_enable': '%s', 'bootmenu_timeout': '%s'} variants: - positive_test: status_error = "no" @@ -31,9 +33,10 @@ error_msg = "invalid value for boot menu timeout, must be in range [0,65535]" variants: - by_ovmf: - only q35 + only q35, aarch64 firmware_type = "ovmf" check_prompt = "BdsDxe: loading Boot0000 "UiApp" from Fv" - by_seabios: + only x86_64 firmware_type = "seabios" check_prompt = "Select boot device" diff --git a/libvirt/tests/cfg/guest_os_booting/boot_order/boot_from_cdrom_device.cfg b/libvirt/tests/cfg/guest_os_booting/boot_order/boot_from_cdrom_device.cfg index 25a8596ac68..8d0888df366 100644 --- a/libvirt/tests/cfg/guest_os_booting/boot_order/boot_from_cdrom_device.cfg +++ b/libvirt/tests/cfg/guest_os_booting/boot_order/boot_from_cdrom_device.cfg @@ -3,24 +3,34 @@ start_vm = no disk1_attrs_target = {'dev': 'vda', 'bus': 'virtio'} cdrom_attrs = "{'type_name': 'file', 'device': 'cdrom', 'driver': {'name': 'qemu', 'type': 'raw', 'cache': 'none'}, 'readonly': True}" - bootable_patterns = ["begin the installation process|Install Red Hat Enterprise"] variants: - without_cdrom: only os_dev + aarch64: + bootable_patterns = ["Shell>", "Booting .* on physical CPU"] - with_cdrom_with_no_src: + no s390-virtio cdrom1_attrs = {'target': {'dev': 'sda', 'bus': 'sata'}, **${cdrom_attrs}} + aarch64: + cdrom1_attrs = {'target': {'dev': 'sda', 'bus': 'scsi'}, **${cdrom_attrs}} + bootable_patterns = ["Shell>", "Booting .* on physical CPU"] - with_cdrom: check_bootable_iso = "yes" cdrom1_attrs = {'source': {'attrs': {'file': boot_img_path}}, 'target': {'dev': 'sda', 'bus': 'scsi'}, **${cdrom_attrs}} + bootable_patterns = ["begin the installation process|Install Red Hat Enterprise|Starting installer"] - multi_cdroms: cdrom1_attrs = {'target': {'dev': 'sda', 'bus': 'scsi'}, **${cdrom_attrs}} cdrom2_attrs = {'source': {'attrs': {'file': boot_img_path}}, 'target': {'dev': 'sdb', 'bus': 'sata'}, **${cdrom_attrs}} + aarch64, s390-virtio: + cdrom2_attrs = {'source': {'attrs': {'file': boot_img_path}}, 'target': {'dev': 'sdb', 'bus': 'scsi'}, **${cdrom_attrs}} cdrom_boot_order: check_bootable_iso = "yes" + bootable_patterns = ["begin the installation process|Install Red Hat Enterprise|Starting installer"] os_dev: - status_error = "yes" + status_error = "yes" variants: - os_dev: + no s390-virtio os_attrs_boots = ['cdrom'] - cdrom_boot_order: variants firmware_type: @@ -29,4 +39,6 @@ with_cdrom_with_no_src: status_error = "yes" - ovmf: - only q35 + only q35, aarch64 + - no_firmware: + only s390-virtio diff --git a/libvirt/tests/cfg/guest_os_booting/boot_order/boot_from_disk_device.cfg b/libvirt/tests/cfg/guest_os_booting/boot_order/boot_from_disk_device.cfg index c11b36e8459..1b2e23d087d 100644 --- a/libvirt/tests/cfg/guest_os_booting/boot_order/boot_from_disk_device.cfg +++ b/libvirt/tests/cfg/guest_os_booting/boot_order/boot_from_disk_device.cfg @@ -4,6 +4,7 @@ disk1_attrs_target = {'dev': 'vda', 'bus': 'virtio'} variants: - os_dev: + no s390-virtio os_attrs_boots = ['hd'] disk1_attrs = {'target': ${disk1_attrs_target}} variants: @@ -12,6 +13,8 @@ disk1_img = "non-bootable.qcow2" disk2_attrs = {'target': {'dev': 'sda', 'bus': 'sata'}} status_error = "yes" + aarch64: + disk2_attrs = {'target': {'dev': 'sda', 'bus': 'scsi'}} - disk_boot_order: variants: - single_disk: @@ -22,8 +25,16 @@ disk2_attrs = {'target': {'dev': 'sda', 'bus': 'scsi'}} seabios: status_error = "yes" + - multi_disks_bootable: + download_disk1_img = yes + disk1_img_url = + disk1_img = "bootable_standard_partitions.qcow2" + disk1_attrs = {'target': ${disk1_attrs_target}} + disk2_attrs = {'target': {'dev': 'sda', 'bus': 'scsi'}} variants firmware_type: - seabios: only x86_64 - ovmf: - only q35 + only q35, aarch64 + - no_firmware: + only s390-virtio diff --git a/libvirt/tests/cfg/guest_os_booting/boot_order/boot_from_usb_device.cfg b/libvirt/tests/cfg/guest_os_booting/boot_order/boot_from_usb_device.cfg new file mode 100644 index 00000000000..fd42fe49131 --- /dev/null +++ b/libvirt/tests/cfg/guest_os_booting/boot_order/boot_from_usb_device.cfg @@ -0,0 +1,21 @@ +- guest_os_booting.boot_order.usb_device: + type = boot_from_usb_device + start_vm = no + bus_type = "usb" + bootmenu_dict = {'bootmenu_enable': 'yes', 'bootmenu_timeout': '3000', 'bios_useserial': 'yes'} + check_prompt = "UEFI .* USB|1. USB MSC Drive .*|UsbBootDetectMedia: UsbBootIsUnitReady .*|.*UsbBootExecCmd: Success to Exec 0x0 Cmd \(Result = 1\).*" + only q35, aarch64 + aarch64: + bootmenu_dict = {'bootmenu_enable': 'yes', 'bootmenu_timeout': '3000'} + variants usb_device: + - block_device: + disk_type = "block" + target_disk = "sda" + device_attrs = {"type_name":"${disk_type}", "target":{"dev": "${target_disk}", "bus": "${bus_type}"}, 'boot': '1'} + - redirdev_device: + port_num = "4000" + device_attrs = {'source': {'host': 'localhost', 'service': '4000', 'mode': 'connect'}, 'protocol': {'type': 'raw'}, 'type_name': 'tcp', 'bus': '${bus_type}', 'type': 'tcp', 'boot': {'order': '1'}} + only q35 + required_cmds = ['lsusb'] + - hostdev_device: + device_attrs = {'type_name': 'usb', 'mode': 'subsystem', 'source': {'vendor_id': '%s', 'product_id': '%s'}, 'type': 'usb', 'managed': 'no', 'boot_order': '1'} diff --git a/libvirt/tests/cfg/guest_os_booting/boot_order/boot_from_virtiofs_device.cfg b/libvirt/tests/cfg/guest_os_booting/boot_order/boot_from_virtiofs_device.cfg new file mode 100644 index 00000000000..6c7c411fdc9 --- /dev/null +++ b/libvirt/tests/cfg/guest_os_booting/boot_order/boot_from_virtiofs_device.cfg @@ -0,0 +1,12 @@ +- guest_os_booting.boot_order.virtiofs_device: + type = boot_from_virtiofs_device + start_vm = no + vm_memory = 15728640 + no s390-virtio + variants: + - start_guest: + target_dir = "mount_tag" + console_dev = "ttyS0,115200" + guest_cmd = "df -h" + os_dict = {'cmdline': 'root=virtiofs:${target_dir} console=${console_dev}', 'initrd': '%s', 'kernel': '%s'} + virtiofs_dict = {'target': {'dir': '${target_dir}'}, 'type_name': 'mount', 'source': {'dir': '%s'}, 'binary': {'path': '/usr/libexec/virtiofsd'}, 'accessmode': 'passthrough', 'boot': '1', 'driver': {'type': 'virtiofs'}} diff --git a/libvirt/tests/cfg/guest_os_booting/boot_order/boot_with_multiple_boot_dev.cfg b/libvirt/tests/cfg/guest_os_booting/boot_order/boot_with_multiple_boot_dev.cfg new file mode 100644 index 00000000000..32a76da3701 --- /dev/null +++ b/libvirt/tests/cfg/guest_os_booting/boot_order/boot_with_multiple_boot_dev.cfg @@ -0,0 +1,46 @@ +- guest_os_booting.boot_order.boot_with_multiple_boot_dev: + type = boot_with_multiple_boot_dev + start_vm = no + os_dict = {'boots': ['%s', '%s'], 'bootmenu_enable': 'yes', 'bios_useserial': 'yes'} + target_bus = 'sata' + aarch64: + target_bus = 'scsi' + os_dict = {'boots': ['%s', '%s'], 'bootmenu_enable': 'yes'} + cdrom_dict = {'source': {'attrs': {'file': '%s'}}, 'type_name': 'file', 'device': 'cdrom', 'driver': {'name': 'qemu', 'type': 'raw'}, 'target': {'dev': 'sda', 'bus': '${target_bus}'}} + check_prompt = ["begin the installation process|Install Red Hat Enterprise"] + no s390-virtio + variants first_dev: + - hd: + variants second_dev: + - cdrom: + variants bootable_device: + - hd_bootable: + - cdrom_bootable: + - network: + variants bootable_device: + - hd_bootable: + - network_bootable: + check_prompt = ["iPXE initialising devices|Start PXE over IPv4"] + - cdrom: + variants second_dev: + - hd: + variants bootable_device: + - hd_bootable: + - cdrom_bootable: + - network: + variants bootable_device: + - cdrom_bootable: + - network_bootable: + check_prompt = ["iPXE initialising devices|Start PXE over IPv4"] + - network: + variants second_dev: + - hd: + variants bootable_device: + - hd_bootable: + - network_bootable: + check_prompt = ["iPXE initialising devices|Start PXE over IPv4"] + - cdrom: + variants bootable_device: + - cdrom_bootable: + - network_bootable: + check_prompt = ["iPXE initialising devices|Start PXE over IPv4"] diff --git a/libvirt/tests/cfg/guest_os_booting/boot_order/boot_with_multiple_boot_order.cfg b/libvirt/tests/cfg/guest_os_booting/boot_order/boot_with_multiple_boot_order.cfg new file mode 100644 index 00000000000..18c7d71dc1d --- /dev/null +++ b/libvirt/tests/cfg/guest_os_booting/boot_order/boot_with_multiple_boot_order.cfg @@ -0,0 +1,102 @@ +- guest_os_booting.boot_order.boot_with_multiple_boot_order: + type = boot_with_multiple_boot_order + start_vm = no + os_dict = {'bootmenu_enable': 'yes', 'bios_useserial': 'yes'} + target_bus = 'sata' + aarch64: + os_dict = {'bootmenu_enable': 'yes'} + target_bus = 'scsi' + s390-virtio: + os_dict = {'bootmenu_enable': 'no'} + target_bus = 'scsi' + cdrom_dict = {'source': {'attrs': {'file': '%s'}}, 'type_name': 'file', 'device': 'cdrom', 'driver': {'name': 'qemu', 'type': 'raw'}, 'target': {'dev': 'sda', 'bus': '${target_bus}'}} + check_prompt = ["begin the installation process|Install Red Hat Enterprise|Starting installer"] + variants first_dev: + - hd: + disk_order = {'boot': '1'} + variants second_dev: + - cdrom: + cdrom_order = {'boot': '2'} + variants bootable_device: + - hd_bootable: + variants: + - @default: + - with_loadparm: + only s390-virtio + disk_order = {'boot': '1', 'loadparm': '1'} + test_cmd = "lsreipl" + expected_output = Loadparm:\s+"1" + - cdrom_bootable: + - network: + network_order = {'boot': '2'} + variants bootable_device: + - hd_bootable: + - network_bootable: + check_prompt = ["iPXE initialising devices|Start PXE over IPv4"] + s390-virtio: + set_up_tftp = yes + check_prompt = ["Starting installer"] + install_tree_url = INSTALL_TREE_URL + network_order = {'boot': '2', 'source': {'network': 'tftpnet'}} + vm_memory = 1953125 + - cdrom: + cdrom_order = {'boot': '1'} + variants second_dev: + - hd: + disk_order = {'boot': '2'} + variants bootable_device: + - hd_bootable: + variants: + - @default: + - with_loadparm: + only s390-virtio + disk_order = {'boot': '2', 'loadparm': '2'} + test_cmd = "lsreipl" + expected_output = Loadparm:\s+"2" + - cdrom_bootable: + - network: + network_order = {'boot': '2'} + variants bootable_device: + - cdrom_bootable: + - network_bootable: + check_prompt = ["iPXE initialising devices|Start PXE over IPv4"] + s390-virtio: + set_up_tftp = yes + check_prompt = ["Starting installer"] + install_tree_url = INSTALL_TREE_URL + network_order = {'boot': '2', 'source': {'network': 'tftpnet'}} + vm_memory = 1953125 + - network: + network_order = {'boot': '1'} + variants second_dev: + - hd: + disk_order = {'boot': '2'} + variants bootable_device: + - hd_bootable: + variants: + - @default: + - with_loadparm: + only s390-virtio + disk_order = {'boot': '2', 'loadparm': '2'} + test_cmd = "lsreipl" + expected_output = Loadparm:\s+"2" + - network_bootable: + check_prompt = ["iPXE initialising devices|Start PXE over IPv4"] + s390-virtio: + set_up_tftp = yes + check_prompt = ["Starting installer"] + install_tree_url = INSTALL_TREE_URL + network_order = {'boot': '1', 'source': {'network': 'tftpnet'}} + vm_memory = 1953125 + - cdrom: + cdrom_order = {'boot': '2'} + variants bootable_device: + - cdrom_bootable: + - network_bootable: + check_prompt = ["iPXE initialising devices|Start PXE over IPv4"] + s390-virtio: + set_up_tftp = yes + check_prompt = ["Starting installer"] + install_tree_url = INSTALL_TREE_URL + network_order = {'boot': '1', 'source': {'network': 'tftpnet'}} + vm_memory = 1953125 diff --git a/libvirt/tests/cfg/guest_os_booting/boot_order/hotplug_device_with_boot_order.cfg b/libvirt/tests/cfg/guest_os_booting/boot_order/hotplug_device_with_boot_order.cfg new file mode 100644 index 00000000000..9dfa2607510 --- /dev/null +++ b/libvirt/tests/cfg/guest_os_booting/boot_order/hotplug_device_with_boot_order.cfg @@ -0,0 +1,24 @@ +- guest_os_booting.boot_order.hotplug: + type = hotplug_device_with_boot_order + start_vm = no + target_dev = "vda" + boot_order = 1 + order_xpath = [{'element_attrs': ["./devices/disk/boot[@order='2']"]}] + variants device_type: + - disk_device: + bus_type = "virtio" + target_disk = "vdb" + device_dict = {"type_name":"file", "target":{"dev": "${target_disk}", "bus": "${bus_type}"}, 'boot': '2'} + - usb_device: + bus_type = "usb" + target_disk = "sda" + device_dict = {"type_name":"file", "target":{"dev": "${target_disk}", "bus": "${bus_type}"}, 'boot': '2'} + s390-virtio: + expected_error = unsupported configuration: This QEMU doesn't support + - filesystem_device: + target_dir = "mount_tag" + source_dir = "/tmp" + order_xpath = [{'element_attrs': ["./devices/filesystem/boot[@order='2']"]}] + device_dict = {'target': {'dir': '${target_dir}'}, 'type_name': 'mount', 'source': {'dir': '${source_dir}'}, 'binary': {'path': '/usr/libexec/virtiofsd'}, 'accessmode': 'passthrough', 'boot': '2', 'driver': {'type': 'virtiofs'}} + s390-virtio: + expected_error = unsupported configuration: setting virtiofs boot order is supported only with PCI bus diff --git a/libvirt/tests/cfg/guest_os_booting/direct_kernel_boot/direct_kernel_boot.cfg b/libvirt/tests/cfg/guest_os_booting/direct_kernel_boot/direct_kernel_boot.cfg index 563c2522445..4d4a51340cf 100644 --- a/libvirt/tests/cfg/guest_os_booting/direct_kernel_boot/direct_kernel_boot.cfg +++ b/libvirt/tests/cfg/guest_os_booting/direct_kernel_boot/direct_kernel_boot.cfg @@ -6,6 +6,8 @@ initrd_url = "${repo_url}/images/pxeboot/initrd.img" vmlinuz_url = "${repo_url}/images/pxeboot/vmlinuz" direct_kernel_dict = {'cmdline': 'console=ttyS0 inst.repo=${repo_url}', 'initrd': '%s', 'kernel': '%s'} + s390-virtio: + direct_kernel_dict = {'cmdline': 'console=ttysclp0 inst.repo=${repo_url}', 'initrd': '%s', 'kernel': '%s'} variants: - start_guest: check_prompt = "Starting installer" diff --git a/libvirt/tests/cfg/guest_os_booting/firmware_configuration/os_acpi.cfg b/libvirt/tests/cfg/guest_os_booting/firmware_configuration/os_acpi.cfg index 90e0174b992..8cf656f467c 100644 --- a/libvirt/tests/cfg/guest_os_booting/firmware_configuration/os_acpi.cfg +++ b/libvirt/tests/cfg/guest_os_booting/firmware_configuration/os_acpi.cfg @@ -4,6 +4,7 @@ acpi_url = "EXAMPLE_ACPI_URL" acpi_file = "slic.dat" acpi_dict = {'acpi': {'table_type': 'slic', 'table': '%s'}} + no aarch64, s390-virtio variants: - start_guest: cmd_in_guest = "acpidump" diff --git a/libvirt/tests/cfg/guest_os_booting/firmware_configuration/smbios_mode.cfg b/libvirt/tests/cfg/guest_os_booting/firmware_configuration/smbios_mode.cfg new file mode 100644 index 00000000000..e0a034ed820 --- /dev/null +++ b/libvirt/tests/cfg/guest_os_booting/firmware_configuration/smbios_mode.cfg @@ -0,0 +1,36 @@ +- guest_os_booting.smbios_mode: + type = smbios_mode + start_vm = no + no s390-virtio + variants: + - positive_test: + variants smbios_mode: + - emulate: + os_dict = {'smbios_mode': 'emulate'} + expected_system_info = {'Manufacturer': 'Red Hat', 'Product Name': 'KVM', 'UUID': '%s', 'Family': 'Red Hat Enterprise Linux'} + - host: + os_dict = {'smbios_mode': 'host'} + expected_system_info = {'Manufacturer': '%s', 'Product Name': '%s', 'SKU Number': '%s', 'Family': '%s'} + - sysinfo: + with_sysinfo = "yes" + os_dict = {'smbios_mode': 'sysinfo'} + sysinfo_type = {'type': 'smbios'} + sysinfo_bios = {'bios_entry': [{'entry': 'LENOVO', 'entry_name': 'vendor'}, {'entry': '6FET82WW (3.12 )', 'entry_name': 'version'}, {'entry': '02/08/2012', 'entry_name': 'date'}]} + sysinfo_system = {'system_entry': [{'entry': 'Fedora', 'entry_name': 'manufacturer'}, {'entry': 'Virt-Manager', 'entry_name': 'product'}, {'entry': '0.8.2-3.fc14', 'entry_name': 'version'}, {'entry': '32,dfcb37-5af1-552b-357c-be8c3aa38310', 'entry_name': 'serial'}, {'entry': '%s', 'entry_name': 'uuid'}, {'entry': '1234567890', 'entry_name': 'sku'}, {'entry': 'Red Hat', 'entry_name': 'family'}]} + sysinfo_baseBoard = {'baseBoard_entry': [{'entry': 'SUN', 'entry_name': 'manufacturer'}, {'entry': '20BE0061MC', 'entry_name': 'product'}, {'entry': '0B98401 Pro', 'entry_name': 'version'}, {'entry': 'W1KS427111E', 'entry_name': 'serial'}, {'entry': 'abcde', 'entry_name': 'asset'}, {'entry': 'edcba', 'entry_name': 'location'}]} + sysinfo_chassis = {'chassis_entry': [{'entry': 'Dell Inc.', 'entry_name': 'manufacturer'}, {'entry': '2.12', 'entry_name': 'version'}, {'entry': '65X0XF2', 'entry_name': 'serial'}, {'entry': '40000101', 'entry_name': 'asset'}, {'entry': 'Type3Sku1', 'entry_name': 'sku'}]} + sysinfo_oemStrings = {'oemStrings_entry': [{'entry': 'myappname:some arbitrary data'}, {'entry': 'otherappname:more arbitrary data'}]} + - negative_test: + variants: + - invalid_mode: + os_dict = {'smbios_mode': 'abc'} + error_msg = "unknown smbios mode 'abc'" + - without_sysinfo_snippet: + os_dict = {'smbios_mode': 'sysinfo'} + error_msg = "Domain .* sysinfo are not available" + - with_mismatch_uuid: + with_sysinfo = "yes" + os_dict = {'smbios_mode': 'sysinfo'} + sysinfo_type = {'type': 'smbios'} + sysinfo_system = {'system_entry': [{'entry': '11111111-1111-1111-1111-111111111111', 'entry_name': 'uuid'}]} + error_msg = "UUID mismatch between and " diff --git a/libvirt/tests/cfg/guest_os_booting/firmware_configuration/sysinfo_fwcfg.cfg b/libvirt/tests/cfg/guest_os_booting/firmware_configuration/sysinfo_fwcfg.cfg new file mode 100644 index 00000000000..32970c35e22 --- /dev/null +++ b/libvirt/tests/cfg/guest_os_booting/firmware_configuration/sysinfo_fwcfg.cfg @@ -0,0 +1,29 @@ +- guest_os_booting.sysinfo_fwcfg: + type = sysinfo_fwcfg + start_vm = no + entry_value = "example value" + no s390-virtio + variants: + - positive_test: + variants: + - with_entry_value: + entry_name = "opt/com.example/name" + fwcfg_dict = {'type': 'fwcfg', 'entry_name': '%s', 'entry': '${entry_value}'} + - with_entry_file: + entry_file = "yes" + entry_name = "opt/com.coreos/config" + file_name = "provision.ign" + fwcfg_dict = {'type': 'fwcfg', 'entry_name': '%s', 'entry_file': '%s'} + - negative_test: + fwcfg_dict = {'type': 'fwcfg', 'entry_name': '%s', 'entry': '${entry_value}'} + variants: + - with_missing_value: + entry_name = "opt/com.rhel/name" + fwcfg_dict = {'type': 'fwcfg', 'entry_name': '%s'} + error_msg = "Firmware entry must have either value or 'file' attribute" + - without_correct_prefix: + entry_name = "tmp/com.rhel/name" + error_msg = "Invalid firmware name" + - with_exist_name: + entry_name = "opt/org.qemu/" + error_msg = "That firmware name is reserved" diff --git a/libvirt/tests/cfg/guest_os_booting/migration/migration_boot.cfg b/libvirt/tests/cfg/guest_os_booting/migration/migration_boot.cfg index 58e0e2895fa..7fd79d42f76 100644 --- a/libvirt/tests/cfg/guest_os_booting/migration/migration_boot.cfg +++ b/libvirt/tests/cfg/guest_os_booting/migration/migration_boot.cfg @@ -25,6 +25,7 @@ virsh_migrate_connect_uri = "qemu:///system" variants: - os_dev: + no s390-virtio os_attrs_boots = ['hd', 'cdrom', 'network'] - boot_order: disk_boot_idx = 1 diff --git a/libvirt/tests/cfg/guest_os_booting/os_configuration/without_default_os_attributes.cfg b/libvirt/tests/cfg/guest_os_booting/os_configuration/without_default_os_attributes.cfg index a5fabc7271b..5f0ff42b3c0 100644 --- a/libvirt/tests/cfg/guest_os_booting/os_configuration/without_default_os_attributes.cfg +++ b/libvirt/tests/cfg/guest_os_booting/os_configuration/without_default_os_attributes.cfg @@ -2,11 +2,11 @@ type = without_default_os_attributes start_vm = no firmware_type = "ovmf" - only q35 + only q35, aarch64 variants: - without_arch: os_dict = {'type': 'hvm', 'boots': ['hd'], 'machine': 'q35', 'os_firmware': 'efi'} - os_xpath = [{'element_attrs': ["./os/type[@arch='x86_64']"]}] + os_xpath = [{"element_attrs": [f"./os/type[@arch='{host_arch}']"]}] - without_boot_dev: os_dict = {'type': 'hvm', 'arch': 'x86_64', 'machine': 'q35', 'os_firmware': 'efi'} os_xpath = [{'element_attrs': ["./os/boot[@dev='hd']"]}] diff --git a/libvirt/tests/cfg/guest_os_booting/ovmf_firmware/ovmf_backed_nvram.cfg b/libvirt/tests/cfg/guest_os_booting/ovmf_firmware/ovmf_backed_nvram.cfg index 2b8e554e547..68477f27858 100644 --- a/libvirt/tests/cfg/guest_os_booting/ovmf_firmware/ovmf_backed_nvram.cfg +++ b/libvirt/tests/cfg/guest_os_booting/ovmf_firmware/ovmf_backed_nvram.cfg @@ -3,12 +3,21 @@ start_vm = no loader_path = "/usr/share/edk2/ovmf/OVMF_CODE.secboot.fd" template_path = "/usr/share/edk2/ovmf/OVMF_VARS.secboot.fd" - os_dict = {'secure': 'yes', 'loader_readonly': 'yes', 'loader_type': 'pflash', 'loader': '${loader_path}'} + os_secure = "yes" firmware_type = "ovmf" - nvram_attrs = {'nvram_attrs': {'template': '${template_path}', 'type': '%s'}} func_supported_since_libvirt_ver = (8, 5, 0) - only q35 - only x86_64 + only q35, aarch64 + aarch64: + loader_path = "/usr/share/edk2/aarch64/QEMU_EFI-silent-pflash.qcow2" + template_path = "/usr/share/edk2/aarch64/vars-template-pflash.qcow2" + os_secure = "no" + nvram_attrs = {'nvram_attrs': {'template': '${template_path}', 'type': '%s', 'format': 'qcow2'}} + os_dict = {'secure': '${os_secure}', 'loader_readonly': 'yes', 'loader_type': 'pflash', 'loader': '${loader_path}'} + variants source_type: - file: nvram_source = {'nvram_source': {'attrs': {'file': '%s'}}} + nvram_attrs = {'nvram_attrs': {'template': '${template_path}', 'type': 'file'}} + - block: + nvram_source = {'nvram_source': {'attrs': {'dev': '%s'}}} + nvram_attrs = {'nvram_attrs': {'template': '${template_path}', 'type': 'block', 'format': 'qcow2'}} diff --git a/libvirt/tests/cfg/guest_os_booting/ovmf_firmware/ovmf_firmware_feature.cfg b/libvirt/tests/cfg/guest_os_booting/ovmf_firmware/ovmf_firmware_feature.cfg index c83da06e461..85653780fac 100644 --- a/libvirt/tests/cfg/guest_os_booting/ovmf_firmware/ovmf_firmware_feature.cfg +++ b/libvirt/tests/cfg/guest_os_booting/ovmf_firmware/ovmf_firmware_feature.cfg @@ -4,15 +4,17 @@ loader_path = "/usr/share/edk2/ovmf/OVMF_CODE.secboot.fd" nvram_template = "/usr/share/edk2/ovmf/OVMF_VARS.secboot.fd" firmware_type = "ovmf" - only q35 + only q35, aarch64 variants: - positive_test: status_error = "no" variants: - enable_secure_boot: + no aarch64 firmware_dict = {'os_firmware': 'efi', 'firmware': {'feature': [{'enabled': 'yes', 'name': 'enrolled-keys'}, {'enabled': 'yes', 'name': 'secure-boot'}]}} firmware_xpath = [{'element_attrs': ["./os/nvram[@template='${nvram_template}']"]}, {'element_attrs': ["./os/loader[@type='pflash']"], 'text': '${loader_path}'}] - disable_secure_boot: + no aarch64 nvram_template = "/usr/share/edk2/ovmf/OVMF_VARS.fd" firmware_dict = {'os_firmware': 'efi', 'firmware': {'feature': [{'enabled': 'no', 'name': 'enrolled-keys'}, {'enabled': 'yes', 'name': 'secure-boot'}]}} firmware_xpath = [{'element_attrs': ["./os/nvram[@template='${nvram_template}']"]}, {'element_attrs': ["./os/loader[@type='pflash']"], 'text': '${loader_path}'}] @@ -20,6 +22,9 @@ func_supported_since_libvirt_ver = (9, 0, 0) loader_path = "/usr/share/edk2/ovmf/OVMF_CODE.fd" nvram_template = "/usr/share/edk2/ovmf/OVMF_VARS.fd" + aarch64: + loader_path = "/usr/share/edk2/aarch64/QEMU_EFI-silent-pflash.qcow2" + nvram_template = "/usr/share/edk2/aarch64/vars-template-pflash.qcow2" firmware_dict = {'os_firmware': 'efi', 'firmware': {'feature': [{'enabled': 'no', 'name': 'enrolled-keys'}, {'enabled': 'no', 'name': 'secure-boot'}]}} firmware_xpath = [{'element_attrs': ["./os/nvram[@template='${nvram_template}']"]}, {'element_attrs': ["./os/loader[@readonly='yes']"], 'text': '${loader_path}'}] - negative_test: diff --git a/libvirt/tests/cfg/guest_os_booting/ovmf_firmware/ovmf_loader.cfg b/libvirt/tests/cfg/guest_os_booting/ovmf_firmware/ovmf_loader.cfg index 540d0c6c828..0ba2ac78936 100644 --- a/libvirt/tests/cfg/guest_os_booting/ovmf_firmware/ovmf_loader.cfg +++ b/libvirt/tests/cfg/guest_os_booting/ovmf_firmware/ovmf_loader.cfg @@ -4,17 +4,24 @@ loader_path = "/usr/share/edk2/ovmf/OVMF_CODE.secboot.fd" smm_state = "on" firmware_type = "ovmf" - only q35 + os_secure = "yes" + aarch64: + os_secure = "no" + smm_state = + loader_path = "/usr/share/edk2/aarch64/QEMU_EFI-silent-pflash.qcow2" + only q35, aarch64 variants: - positive_test: variants: - default_value: - loader_dict = {'secure': 'yes', 'loader_readonly': 'yes', 'loader_type': 'pflash', 'loader': '${loader_path}'} + loader_dict = {'secure': '${os_secure}', 'loader_readonly': 'yes', 'loader_type': 'pflash', 'loader': '${loader_path}'} - secure_no: + no aarch64 nvram_path = "/var/lib/libvirt/qemu/nvram/nvram_VARS.fd" nvram_template = "/usr/share/edk2/ovmf/OVMF_VARS.fd" loader_dict = {'loader': '${loader_path}', 'nvram': '${nvram_path}', 'nvram_attrs': {'template': '${nvram_template}'}, 'secure': 'no', 'loader_readonly': 'yes', 'loader_type': 'pflash'} - stateless_yes: + no aarch64 stateless = "yes" func_supported_since_libvirt_ver = (8, 6, 0) loader_path = "/usr/share/edk2/ovmf/OVMF.amdsev.fd" @@ -24,13 +31,14 @@ variants: - readonly_no: func_supported_since_libvirt_ver = (9, 5, 0) - loader_dict = {'secure': 'yes', 'loader_readonly': 'no', 'loader_type': 'pflash', 'loader': '${loader_path}'} + loader_dict = {'secure': '${os_secure}', 'loader_readonly': 'no', 'loader_type': 'pflash', 'loader': '${loader_path}'} error_msg = "Could not open .+: Permission denied" - type_rom: - loader_dict = {'secure': 'yes', 'loader_readonly': 'yes', 'loader_type': 'rom', 'loader': '${loader_path}'} + no aarch64 + loader_dict = {'secure': '${os_secure}', 'loader_readonly': 'yes', 'loader_type': 'rom', 'loader': '${loader_path}'} error_msg = "could not load PC BIOS" - incorrect_loader_path: use_file = "yes" incorrect_loader_path = "/tmp/test" - loader_dict = {'secure': 'yes', 'loader_readonly': 'yes', 'loader_type': 'pflash', 'loader': '${incorrect_loader_path}'} + loader_dict = {'secure': '${os_secure}', 'loader_readonly': 'yes', 'loader_type': 'pflash', 'loader': '${incorrect_loader_path}'} error_msg = "Could not open .+: Permission denied" || "unable to find any master var store for loader" diff --git a/libvirt/tests/cfg/guest_os_booting/ovmf_firmware/ovmf_nvram.cfg b/libvirt/tests/cfg/guest_os_booting/ovmf_firmware/ovmf_nvram.cfg index bc5486e9c64..0b041ddc827 100644 --- a/libvirt/tests/cfg/guest_os_booting/ovmf_firmware/ovmf_nvram.cfg +++ b/libvirt/tests/cfg/guest_os_booting/ovmf_firmware/ovmf_nvram.cfg @@ -3,21 +3,29 @@ start_vm = no smm_state = "on" loader_path = "/usr/share/edk2/ovmf/OVMF_CODE.secboot.fd" - nvram_dict = {'secure': 'yes', 'loader_readonly': 'yes', 'loader_type': 'pflash', 'loader': '${loader_path}', 'nvram_attrs': {'template': '%s'}} + os_secure = "yes" + aarch64: + smm_state = + os_secure = "no" + loader_path = "/usr/share/edk2/aarch64/QEMU_EFI-silent-pflash.qcow2" + nvram_dict = {'secure': '${os_secure}', 'loader_readonly': 'yes', 'loader_type': 'pflash', 'loader': '${loader_path}', 'nvram_attrs': {'template': '%s'}} firmware_type = "ovmf" - only q35 + only q35, aarch64 variants: - positive_test: variants: - template_enable_secure: + no aarch64 template_path = "/usr/share/edk2/ovmf/OVMF_VARS.secboot.fd" - template_disable_secure: template_path = "/usr/share/edk2/ovmf/OVMF_VARS.fd" + aarch64: + template_path = "/usr/share/edk2/aarch64/vars-template-pflash.qcow2" - manual_nvram_file: nvram_file = "/tmp/nvram" - nvram_dict = {'secure': 'yes', 'loader_readonly': 'yes', 'loader_type': 'pflash', 'loader': '${loader_path}', 'nvram': '${nvram_file}'} + nvram_dict = {'secure': '${os_secure}', 'loader_readonly': 'yes', 'loader_type': 'pflash', 'loader': '${loader_path}', 'nvram': '${nvram_file}'} - negative_test: variants: - nonexist_template: template_path = "nonexist" - error_msg = "error: Failed to open file.+: No such file or directory" + error_msg = "error: Failed to open file.+: No such file or directory|conversion of the nvram template to another target format" diff --git a/libvirt/tests/cfg/guest_os_booting/ovmf_firmware/ovmf_seclabel_in_nvram.cfg b/libvirt/tests/cfg/guest_os_booting/ovmf_firmware/ovmf_seclabel_in_nvram.cfg new file mode 100644 index 00000000000..adeac1a01b7 --- /dev/null +++ b/libvirt/tests/cfg/guest_os_booting/ovmf_firmware/ovmf_seclabel_in_nvram.cfg @@ -0,0 +1,39 @@ +- guest_os_booting.ovmf_seclabel_in_nvram: + type = ovmf_seclabel_in_nvram + start_vm = no + loader_path = "/usr/share/edk2/ovmf/OVMF_CODE.secboot.fd" + template_path = "/usr/share/edk2/ovmf/OVMF_VARS.secboot.fd" + os_secure = "yes" + nvram_attrs = {'nvram_attrs': {'template': '${template_path}', 'type': 'file'}} + aarch64: + loader_path = "/usr/share/edk2/aarch64/QEMU_EFI-silent-pflash.qcow2" + template_path = "/usr/share/edk2/aarch64/vars-template-pflash.qcow2" + os_secure = "no" + nvram_attrs = {'nvram_attrs': {'template': '${template_path}', 'type': 'file', 'format': 'qcow2'}} + nvram_source = {'nvram_source': {'seclabels': [{'label': '%s', 'model': '%s', 'relabel': 'yes'}], 'attrs': {'file': '%s'}}} + os_dict = {'secure': '${os_secure}', 'loader_readonly': 'yes', 'loader_type': 'pflash', 'loader': '${loader_path}'} + firmware_type = "ovmf" + func_supported_since_libvirt_ver = (8, 5, 0) + only q35, aarch64 + variants: + - positive_test: + variants: + - with_selinux_seclabel: + seclabel_model = "selinux" + seclabel_label = "system_u:object_r:svirt_image_t:s0" + - with_dac_seclabel: + seclabel_model = "dac" + seclabel_label = "qemu:qemu" + - negative_test: + error_msg = "Could not open .*: Permission denied" + variants: + - invalid_selinux_seclabel: + seclabel_model = "selinux" + seclabel_label = "unconfined_u:object_r:virt_image_t:s0" + - invalid_dac_seclabel: + seclabel_model = "dac" + seclabel_label = "test:test" + - with_no_relabel: + without_label = "yes" + seclabel_model = "selinux" + nvram_source = {'nvram_source': {'seclabels': [{'model': '%s', 'relabel': 'no'}], 'attrs': {'file': '%s'}}} diff --git a/libvirt/tests/cfg/guest_os_booting/seabios_firmware/seabios_loader.cfg b/libvirt/tests/cfg/guest_os_booting/seabios_firmware/seabios_loader.cfg index 9586cd37d42..2c3d4319b52 100644 --- a/libvirt/tests/cfg/guest_os_booting/seabios_firmware/seabios_loader.cfg +++ b/libvirt/tests/cfg/guest_os_booting/seabios_firmware/seabios_loader.cfg @@ -5,6 +5,7 @@ loader_type = "rom" loader_dict = {'loader_type': '%s', 'loader': '%s'} firmware_type = "seabios" + only x86_64 variants: - positive_test: variants: diff --git a/libvirt/tests/cfg/guest_os_booting/useserial/useserial.cfg b/libvirt/tests/cfg/guest_os_booting/useserial/useserial.cfg index b1b39538ce2..0545c98be3d 100644 --- a/libvirt/tests/cfg/guest_os_booting/useserial/useserial.cfg +++ b/libvirt/tests/cfg/guest_os_booting/useserial/useserial.cfg @@ -13,5 +13,6 @@ only q35 firmware_type = "ovmf" - by_seabios: + only x86_64 firmware_type = "seabios" check_prompt = "Press ESC for boot menu" diff --git a/libvirt/tests/cfg/virsh_cmd/domain/virsh_blkiotune.cfg b/libvirt/tests/cfg/guest_resource_control/virsh_blkiotune.cfg similarity index 100% rename from libvirt/tests/cfg/virsh_cmd/domain/virsh_blkiotune.cfg rename to libvirt/tests/cfg/guest_resource_control/virsh_blkiotune.cfg diff --git a/libvirt/tests/cfg/host_hypervisor/domcapabilities_output.cfg b/libvirt/tests/cfg/host_hypervisor/domcapabilities_output.cfg index b8f073ee88a..98c13f08122 100644 --- a/libvirt/tests/cfg/host_hypervisor/domcapabilities_output.cfg +++ b/libvirt/tests/cfg/host_hypervisor/domcapabilities_output.cfg @@ -3,3 +3,5 @@ start_vm = no variants test_case: - rm_ovmf_path: + - check_iface_backend: + func_supported_since_libvirt_ver = (10, 8, 0) diff --git a/libvirt/tests/cfg/in_place_upgrade_guest.cfg b/libvirt/tests/cfg/in_place_upgrade_guest.cfg new file mode 100644 index 00000000000..1530ff81b1a --- /dev/null +++ b/libvirt/tests/cfg/in_place_upgrade_guest.cfg @@ -0,0 +1,11 @@ +- in_place_upgrade_guest: + type = in_place_upgrade_guest + backup_image_before_testing = "yes" + restore_image_after_testing = "yes" + release_check_cmd = "cat /etc/redhat-release" + kernel_check_cmd = "uname -r" + pagesize_check_cmd = "getconf PAGESIZE" + compose_url = "EXAMPLE.COMPOSE.URL" + upgrade_repos_path = "/etc/leapp/files/leapp_upgrade_repositories.repo" + leapp_preupgrade_cmd = "leapp preupgrade --debug --no-rhsm" + leapp_upgrade_cmd = "leapp upgrade --debug --no-rhsm" diff --git a/libvirt/tests/cfg/incremental_backup/incremental_backup_backing_chain.cfg b/libvirt/tests/cfg/incremental_backup/incremental_backup_backing_chain.cfg index e8c5ba6f936..1db8b51b826 100644 --- a/libvirt/tests/cfg/incremental_backup/incremental_backup_backing_chain.cfg +++ b/libvirt/tests/cfg/incremental_backup/incremental_backup_backing_chain.cfg @@ -4,6 +4,13 @@ original_disk_size = "100M" backup_data_size = "1M" backup_rounds = 4 + variants: + - without_datastore: + - with_datastore: + only blockcommit.top_to_base,blockpull.mid_to_top,blockcopy.reuse_external + with_data_file = "yes" + func_supported_since_libvirt_ver = (10, 10, 0) + data_file_option = " -o data_file=%s" variants: - scratch_to_file: scratch_type = "file" diff --git a/libvirt/tests/cfg/incremental_backup/incremental_backup_checkpoint_cmd.cfg b/libvirt/tests/cfg/incremental_backup/incremental_backup_checkpoint_cmd.cfg index 70777d63982..784f0cf2619 100644 --- a/libvirt/tests/cfg/incremental_backup/incremental_backup_checkpoint_cmd.cfg +++ b/libvirt/tests/cfg/incremental_backup/incremental_backup_checkpoint_cmd.cfg @@ -3,6 +3,13 @@ start_vm = "no" required_checkpoints = 1 status_error = "no" + variants: + - without_datastore: + - with_datastore: + only checkpoint-create + with_data_file = "yes" + func_supported_since_libvirt_ver = (10, 10, 0) + data_file_option = " -o data_file=%s" variants checkpoint_cmd: - checkpoint-create: variants: @@ -67,3 +74,4 @@ flag = "--with-checkpoint" - without-checkpoint: flag = "--without-checkpoint" + - checkpoint_edit: diff --git a/libvirt/tests/cfg/incremental_backup/incremental_backup_event_monitor.cfg b/libvirt/tests/cfg/incremental_backup/incremental_backup_event_monitor.cfg index 6409a4cf41a..45052b964d3 100644 --- a/libvirt/tests/cfg/incremental_backup/incremental_backup_event_monitor.cfg +++ b/libvirt/tests/cfg/incremental_backup/incremental_backup_event_monitor.cfg @@ -3,6 +3,13 @@ start_vm = "no" original_disk_size = "100M" backup_data_size = "1M" + variants: + - without_datastore: + - with_datastore: + only scratch_luks_encrypted + with_data_file = "yes" + func_supported_since_libvirt_ver = (10, 10, 0) + data_file_option = " -o data_file=%s" variants: - nbd_unix: nbd_protocol = "unix" diff --git a/libvirt/tests/cfg/incremental_backup/incremental_backup_multidisk.cfg b/libvirt/tests/cfg/incremental_backup/incremental_backup_multidisk.cfg index 7c378d0fda9..621754de92b 100644 --- a/libvirt/tests/cfg/incremental_backup/incremental_backup_multidisk.cfg +++ b/libvirt/tests/cfg/incremental_backup/incremental_backup_multidisk.cfg @@ -4,6 +4,12 @@ test_disk_size = "100M" backup_data_size = "1M" total_test_disk = 3 + variants: + - without_datastore: + - with_datastore: + with_data_file = "yes" + func_supported_since_libvirt_ver = (10, 10, 0) + data_file_option = " -o data_file=%s" variants: - custom_export_name: set_export_name = "yes" diff --git a/libvirt/tests/cfg/incremental_backup/incremental_backup_pull_mode.cfg b/libvirt/tests/cfg/incremental_backup/incremental_backup_pull_mode.cfg index 314f04ecb09..40c2f168b78 100644 --- a/libvirt/tests/cfg/incremental_backup/incremental_backup_pull_mode.cfg +++ b/libvirt/tests/cfg/incremental_backup/incremental_backup_pull_mode.cfg @@ -7,6 +7,14 @@ local_ip = "ENTER.YOUR.IPV4ADDR" local_user_name = "ENTER.YOUR.USER.NAME" local_user_password = "ENTER.YOUR.USER.PASSWORD" + only original_disk_local + variants: + - without_datastore: + - with_datastore: + only default_exportbitmap.default_exportname + with_data_file = "yes" + func_supported_since_libvirt_ver = (10, 10, 0) + data_file_option = " -o data_file=%s" variants: - scratch_luks_encrypted: only custom_exportname..custom_exportbitmap..hotplug_disk..original_disk_local diff --git a/libvirt/tests/cfg/incremental_backup/incremental_backup_push_mode.cfg b/libvirt/tests/cfg/incremental_backup/incremental_backup_push_mode.cfg index 82c31862016..3775d0dcf28 100644 --- a/libvirt/tests/cfg/incremental_backup/incremental_backup_push_mode.cfg +++ b/libvirt/tests/cfg/incremental_backup/incremental_backup_push_mode.cfg @@ -3,6 +3,13 @@ start_vm = "no" original_disk_size = "100M" backup_data_size = "1M" + variants: + - without_datastore: + - with_datastore: + only original_disk_local + with_data_file = "yes" + func_supported_since_libvirt_ver = (10, 10, 0) + data_file_option = " -o data_file=%s" variants: - backup_to_file: target_type = "file" @@ -17,8 +24,22 @@ variants: - target_file_not_exist: prepare_target_file = "no" + - destroy_vm: + only original_disk_local.coldplug_disk.backup_to_raw.backup_to_file + error_operation = "destroy_vm" + expect_backup_canceled = "yes" + original_disk_size = "5000M" + dd_count = "2000" - positive_test: - not_reuse_target_file: + variants: + - normal_disk: + - readonly_disk: + only original_disk_local.coldplug_disk.backup_to_qcow2 + with_readonly = "yes" + backup_rounds = 2 + original_disk_size = 1024M + dd_count = "100" - backup_to_block: target_type = "block" backup_rounds = 1 @@ -30,14 +51,11 @@ backup_error = "yes" prepare_target_blkdev = "no" target_blkdev_path = "/dev/not/exist" - - destroy_vm: - only original_disk_local.coldplug_disk.backup_to_raw.backup_to_block - expect_backup_canceled = "yes" - original_disk_size = "1000M" - kill_qemu: only original_disk_local.hotplug_disk.backup_to_qcow2.backup_to_block expect_backup_canceled = "yes" - original_disk_size = "1000M" + original_disk_size = "5000M" + dd_count = "2000" - positive_test: variants: - backup_to_qcow2: diff --git a/libvirt/tests/cfg/libvirt_hooks.cfg b/libvirt/tests/cfg/libvirt_hooks.cfg index f109e54e778..29c75fccb5e 100644 --- a/libvirt/tests/cfg/libvirt_hooks.cfg +++ b/libvirt/tests/cfg/libvirt_hooks.cfg @@ -24,6 +24,7 @@ variants: - start_stop: test_start_stop = "yes" + release_reason = "shutdown" - libvirtd_t: test_libvirtd = "yes" - save_restore: diff --git a/libvirt/tests/cfg/libvirt_mem.cfg b/libvirt/tests/cfg/libvirt_mem.cfg index ca55880c45c..69db0e75506 100644 --- a/libvirt/tests/cfg/libvirt_mem.cfg +++ b/libvirt/tests/cfg/libvirt_mem.cfg @@ -10,6 +10,9 @@ host_known_unplug_errors = "'Memory unplug already in progress for device'" vcpu = 4 wait_before_save_secs = 0 + cpu_mode = "host-model" + aarch64: + cpu_mode = "host-passthrough" pseries: wait_before_save_secs = 10 variants: @@ -80,6 +83,7 @@ - no_attach: test_qemu_cmd = "no" - with_source: + max_mem_rt = 2621440 test_qemu_cmd = "no" tg_size = 524288 tg_node = 0 @@ -92,18 +96,14 @@ test_qemu_cmd = "no" test_mem_binding = "no" setup_hugepages = "yes" - huge_page_num = 2000 - pseries: - huge_page_num = 200 max_mem_rt = 25600000 max_mem = "2609152" current_mem = "2609152" numa_cells = "{'id':'0','cpus':'0-1','memory':'1048576','unit':'KiB'} {'id':'1','cpus':'2-3','memory':'1048576','unit':'KiB'}" - cpu_mode = "host-model" model_fallback = "forbid" tg_size = 524288 tg_node = 0 - page_size = 2048 + total_huge_page_size = 4194304 page_unit = "KiB" node_mask = 0 huge_pages = "{'size':'2048','unit':'KiB','nodeset':'0'}" @@ -132,6 +132,7 @@ memory_addr = "{'type':'dimm','slot':'0','base':'0x100000000'}" node_mask = 0 - without_numa_save_restore: + no x86_64,aarch64,ppc64le max_mem_rt = 20971520 numa_cells = "" tg_node = "" @@ -171,12 +172,19 @@ - invalid_address: memory_addr = "{'type':'dimm','slot':'1','base':'0x11fffffffff'}" - invalid_vm_node: + define_error = "yes" tg_node = 7 - invalid_host_node: node_mask = 1-3 tg_nddode = 1 page_size = 4 page_unit = "KiB" + - without_numa: + only x86_64,aarch64,ppc64le + define_error = "yes" + max_mem_rt = 20971520 + numa_cells = "" + tg_node = "" - attach_error: attach_device = "yes" attach_error = "yes" @@ -185,6 +193,7 @@ max_mem_rt = max_mem = numa_cells = + current_mem = 2048000 attach_option = "--config" - attach_invalid_type: memory_addr = "{'type':'diee','slot':'16','base':'0x11fffffffff'}" @@ -235,3 +244,4 @@ - with_numa: set_max_mem = "2560001" max_mem_option = "--config" + diff --git a/libvirt/tests/cfg/memory/gmap.cfg b/libvirt/tests/cfg/memory/gmap.cfg new file mode 100644 index 00000000000..87005acaad3 --- /dev/null +++ b/libvirt/tests/cfg/memory/gmap.cfg @@ -0,0 +1,10 @@ +- gmap: + type = gmap + start_vm = no + only s390-virtio + kvm_module_parameters = 'nested=1' + variants: + - l3_shadow_table_counters: + l2_mem = 3906250 + target_tag = "mount_tag0" + fs_dict = {'accessmode': 'passthrough', 'source': {'dir': 'replace_in_code'}, "target": {'dir': '${target_tag}'}, 'driver': {'type': 'virtiofs'}} diff --git a/libvirt/tests/cfg/memory/hmat.cfg b/libvirt/tests/cfg/memory/hmat.cfg index 750c971ca78..6bb0276c0f1 100644 --- a/libvirt/tests/cfg/memory/hmat.cfg +++ b/libvirt/tests/cfg/memory/hmat.cfg @@ -2,6 +2,8 @@ type = hmat start_vm = no cpuxml_cpu_mode = "host-model" + aarch64: + cpuxml_cpu_mode = "host-passthrough" cpuxml_mode = "qemu64" cpuxml_fallback = "allow" cpuxml_numa_cell = [{'id': '0', 'cpus': '0-5', 'memory': '512', 'unit': 'M'}, {'id': '1', 'memory': '512', 'unit': 'M'}] diff --git a/libvirt/tests/cfg/memory/memory_allocation/define_value_unit.cfg b/libvirt/tests/cfg/memory/memory_allocation/define_value_unit.cfg index 7fd6f4dcb00..0e5e8a5de8e 100644 --- a/libvirt/tests/cfg/memory/memory_allocation/define_value_unit.cfg +++ b/libvirt/tests/cfg/memory/memory_allocation/define_value_unit.cfg @@ -6,9 +6,6 @@ default_unit = "KiB" status_error = "no" result_dict = {'memory_unit': 'KiB', 'current_mem_unit': 'KiB', 'max_mem_rt_slots': ${max_mem_slots}, "max_mem_rt_unit":"KiB","numa_unit":"KiB"} - default_pagesize = 4 - aarch64: - default_pagesize = 64 variants case: - positive_test: variants: @@ -79,3 +76,4 @@ vm_attrs = {'max_mem_rt': ${max_mem}, 'max_mem_rt_slots': ${max_mem_slots}, 'max_mem_rt_unit': "${max_mem_unit}",'memory_unit':"${mem_unit}",'memory':${mem_value},'current_mem':${current_mem},'current_mem_unit':'${current_mem_unit}',"cpu":${numa_cpu}} xpaths = [[{'element_attrs':['.//memory[@unit="${default_unit}"]'],'text':'%s'}],[{'element_attrs':['.//currentMemory[@unit="${default_unit}"]'],'text':'%s'}],[{'element_attrs':['.//maxMemory[@unit="${default_unit}"]'],'text':'%s'}],[{'element_attrs':['.//cell[@unit="${default_unit}"]','.//cell[@memory="%s"]']}]] numa_dict = {'numa_cell': [{'id': '0', 'cpus': '0-1', 'memory': '${mem_value}'}]} + diff --git a/libvirt/tests/cfg/memory/memory_allocation/lifecycle_with_memory_allocation.cfg b/libvirt/tests/cfg/memory/memory_allocation/lifecycle_with_memory_allocation.cfg index 0e3e1cbb2fb..dfe04550418 100644 --- a/libvirt/tests/cfg/memory/memory_allocation/lifecycle_with_memory_allocation.cfg +++ b/libvirt/tests/cfg/memory/memory_allocation/lifecycle_with_memory_allocation.cfg @@ -5,7 +5,7 @@ current_mem = 1843200 current_mem_unit = 'KiB' max_mem_slots = 16 - max_mem = 15242880 + max_mem = 15360000 max_mem_unit = 'KiB' numa_mem = 1048576 variants case: @@ -24,6 +24,8 @@ - negative_test: variants mem_config: - with_maxmemory: + no s390-virtio max_mem_attr = "'max_mem_rt': ${max_mem}, 'max_mem_rt_slots': ${max_mem_slots}, 'max_mem_rt_unit': '${max_mem_unit}'" vm_attrs = {${max_mem_attr},'memory_unit':'${mem_unit}','memory':${mem_value},'current_mem':${current_mem},'current_mem_unit':'${current_mem_unit}'} error_msg = "At least one numa node has to be configured when enabling memory hotplug" + expect_xpath = [{'element_attrs':[".//currentMemory[@unit='${current_mem_unit}']"],'text':'${current_mem}'}, {'element_attrs':[".//memory[@unit='${mem_unit}']"],'text':'${mem_value}'}, {'element_attrs':[".//cell[@memory='${mem_value}']"]}] diff --git a/libvirt/tests/cfg/memory/memory_attach_device.cfg b/libvirt/tests/cfg/memory/memory_attach_device.cfg index 701031386b9..a6680cf1907 100644 --- a/libvirt/tests/cfg/memory/memory_attach_device.cfg +++ b/libvirt/tests/cfg/memory/memory_attach_device.cfg @@ -13,8 +13,8 @@ guest_required_kernel = [5.8.0,) func_supported_since_libvirt_ver = (8, 0, 0) func_supported_since_qemu_kvm_ver = (6, 2, 0) - vm_attrs = {'max_mem_rt': 10485760, 'max_mem_rt_slots': 16, 'max_mem_rt_unit': 'KiB', 'vcpu': 4, 'cpu': {'numa_cell': [{'id': '0', 'cpus': '0-1', 'memory': '1048576', 'unit': 'KiB'}]}} + vm_attrs = {'max_mem_rt': 10485760, 'max_mem_rt_slots': 16, 'max_mem_rt_unit': 'KiB', 'current_mem': 2097152, 'current_mem_unit':'KiB', 'vcpu': 4, 'cpu': {'numa_cell': [{'id': '0', 'cpus': '0-1', 'memory': '2097152', 'unit': 'KiB'}]}} mem_device_attrs = {'mem_model': 'virtio-mem', 'target': {'requested_unit': 'KiB', 'size': 262144, 'node': 0, 'size_unit': 'KiB', 'requested_size': 131072, 'block_unit': 'KiB', 'block_size': 2048}} aarch64: - vm_attrs = {'max_mem_rt': 10485760, 'max_mem_rt_slots': 16, 'max_mem_rt_unit': 'KiB', 'vcpu': 4, 'cpu': {'mode': 'host-passthrough', 'numa_cell': [{'id': '0', 'cpus': '0-3', 'memory': '524288', 'unit': 'KiB'}]}} + vm_attrs = {'max_mem_rt': 20971520, 'max_mem_rt_slots': 16, 'max_mem_rt_unit': 'KiB', 'current_mem': 8388608, 'current_mem_unit':'KiB', 'vcpu': 4, 'cpu': {'mode': 'host-passthrough', 'numa_cell': [{'id': '0', 'cpus': '0-3', 'memory': '8388608', 'unit': 'KiB'}]}} mem_device_attrs = {'mem_model': 'virtio-mem', 'target': {'requested_unit': 'KiB', 'size': 1048576, 'node': 0, 'size_unit': 'KiB', 'requested_size': 524288, 'block_unit': 'KiB', 'block_size': 524288}} diff --git a/libvirt/tests/cfg/memory/memory_backing/discard_memory_content_setting.cfg b/libvirt/tests/cfg/memory/memory_backing/discard_memory_content_setting.cfg index 76f6e73db05..aab732d515b 100644 --- a/libvirt/tests/cfg/memory/memory_backing/discard_memory_content_setting.cfg +++ b/libvirt/tests/cfg/memory/memory_backing/discard_memory_content_setting.cfg @@ -1,10 +1,28 @@ - memory.backing.discard: type = discard_memory_content_setting start_vm = "no" - set_pagesize = 2048 - set_pagenum = 1024 numa_mem = 2097152 qemu_line = '"discard-data":%s' + variants kernel_pagesize: + - 4k: + default_page_size = 4 + variants huge_pagesize: + - 2048: + no s390-virtio + set_pagesize = 2048 + set_pagenum = 1024 + - 1024: + only s390-virtio + set_pagesize = 1024 + set_pagenum = 2048 + kvm_module_parameters = + - 64k: + only aarch64 + default_page_size = 64 + variants huge_pagesize: + - 524288: + set_pagesize = 524288 + set_pagenum = 4 variants source: - file: source_type = 'file' @@ -19,9 +37,6 @@ source_attr = "'source_type':'${source_type}'" source_path = {'element_attrs': ['./memoryBacking/source/[@type="${source_type}"]']} - hugepaged_file: - aarch64: - set_pagesize = 524288 - set_pagenum = 4 source_type = 'hugepage' hugepages_attr = "'hugepages': {}" hugepages_path = {'element_attrs': ['./memoryBacking/hugepages']} @@ -53,3 +68,4 @@ current_mem = "2097152" mem_value = "2097152" mem_attrs = {'memory_unit':'${mem_unit}','memory':${mem_value},'current_mem':${current_mem},'current_mem_unit':'${current_mem_unit}'} + diff --git a/libvirt/tests/cfg/memory/memory_backing/hugepage_mount_path.cfg b/libvirt/tests/cfg/memory/memory_backing/hugepage_mount_path.cfg index 978e7267351..2ac746b0a63 100644 --- a/libvirt/tests/cfg/memory/memory_backing/hugepage_mount_path.cfg +++ b/libvirt/tests/cfg/memory/memory_backing/hugepage_mount_path.cfg @@ -1,47 +1,56 @@ - memory.backing.mount_path: type = hugepage_mount_path + no s390-virtio mem_value = 2097152 - set_pagesize_1 = "1048576" - set_pagenum_1 = "2" - set_pagesize_2 = "2048" - set_pagenum_2 = "3072" - aarch64: - set_pagesize_1 = "2048" - set_pagenum_1 = "1024" - set_pagesize_2 = "524288" - set_pagenum_2 = "6" security_context = "drwxr-xr-x. 3 root root system_u:object_r:hugetlbfs_t:s0" log_path = "/var/log/libvirt/qemu/%s.log" guest_log_error1 = "hugepage is not mounted" guest_log_error2 = "unable to create backing store for hugepages: Permission denied" page_unit = "KiB" - page_size = "2048" - aarch64: - page_size = "524288" numa_size = 1048576 mem_unit = "KiB" mem_value = 2097152 current_mem = 2097152 max_mem = 15242880 - memory_backing_dict = "'mb': {'hugepages': {'pages': [{'unit': '${page_unit}', 'size': '${page_size}'}]}}" - numa_cpu = {'numa_cell': [{'id': '0', 'cpus': '0-1', 'memory': '${numa_size}', 'unit': 'KiB'}, {'id': '1', 'cpus': '2-3', 'memory': '${numa_size}', 'unit': 'KiB'}]} - vm_attrs = {${memory_backing_dict},"cpu":${numa_cpu},'vcpu': 4,'max_mem_rt_slots': 16,'memory_unit':"${mem_unit}",'memory':${mem_value},'current_mem':${current_mem},'current_mem_unit':'KiB','max_mem_rt': ${max_mem}, 'max_mem_rt_unit': "KiB"} start_vm = "no" - consume_value = 204800 + remain_mem = 204800 + variants kernel_pagesize: + - 4k: + default_page_size = 4 + variants huge_pagesize: + - 2M: + page_size = "2048" + set_pagesize_2 = "2048" + set_pagenum_2 = "3072" + variants ext_huge_pagesize: + - 1G: + other_huge_pagesize = 1048576 + vm_hugepage_mountpoint = "/dev/hugepages1G" + mount_pagesize = "1G" + set_pagesize_1 = "1048576" + set_pagenum_1 = "2" + - 64k: + only aarch64 + default_page_size = 64 + variants huge_pagesize: + - 512M: + page_size = "524288" + set_pagesize_2 = "524288" + set_pagenum_2 = "6" + variants ext_huge_pagesize: + - 2M: + other_huge_pagesize = 2048 + vm_hugepage_mountpoint = "/dev/hugepages2M" + mount_pagesize = "2M" + set_pagesize_1 = "2048" + set_pagenum_1 = "1024" variants case: - default: path = "/dev/hugepages" - vm_hugepage_mountpoint = "/dev/hugepages1G" - mount_pagesize = "1G" - aarch64: - vm_hugepage_mountpoint = "/dev/hugepages2M" - mount_pagesize = "2M" expect_active = "True" expect_state = "active" check_qemu = ['"mem-path":"${path}/libvirt/qemu/','"prealloc":true'] - attach_dict = {'mem_model': 'dimm', 'source': {"pagesize":1048576, "pagesize_unit":"KiB"},'target': {'size': 1048576, 'size_unit': 'KiB','node':0}} - aarch64: - attach_dict = {'mem_model': 'dimm', 'source': {"pagesize":2048, "pagesize_unit":"KiB"},'target': {'size': 1048576, 'size_unit': 'KiB','node':0}} + attach_dict = {'mem_model': 'dimm', 'source': {"pagesize":${other_huge_pagesize}, "pagesize_unit":"KiB"},'target': {'size': 1048576, 'size_unit': 'KiB','node':0}} check_security_cmd = "ls -l -Z ${path}/libvirt/qemu/ -d" - disabled: hugetlbfs_mount = '""' @@ -56,3 +65,7 @@ expect_state = "active" check_security_cmd = "ls -l -Z ${path}/libvirt/qemu -d" check_qemu = ['"mem-path":"${path}/libvirt/qemu/','"prealloc":true'] + memory_backing_dict = "'mb': {'hugepages': {'pages': [{'unit': '${page_unit}', 'size': '${page_size}'}]}}" + numa_cpu = {'numa_cell': [{'id': '0', 'cpus': '0-1', 'memory': '${numa_size}', 'unit': 'KiB'}, {'id': '1', 'cpus': '2-3', 'memory': '${numa_size}', 'unit': 'KiB'}]} + vm_attrs = {${memory_backing_dict},"cpu":${numa_cpu},'vcpu': 4,'max_mem_rt_slots': 16,'memory_unit':"${mem_unit}",'memory':${mem_value},'current_mem':${current_mem},'current_mem_unit':'KiB','max_mem_rt': ${max_mem}, 'max_mem_rt_unit': "KiB"} + diff --git a/libvirt/tests/cfg/memory/memory_backing/hugepage_nodeset.cfg b/libvirt/tests/cfg/memory/memory_backing/hugepage_nodeset.cfg index 314b863cc7e..1e48871dbc6 100644 --- a/libvirt/tests/cfg/memory/memory_backing/hugepage_nodeset.cfg +++ b/libvirt/tests/cfg/memory/memory_backing/hugepage_nodeset.cfg @@ -2,21 +2,30 @@ type = hugepage_nodeset no s390-virtio start_vm = no - page_size = "2048" page_unit = "KiB" - current_mem = 2072576 - mem_value = 2072576 mem_unit = "KiB" current_mem_unit = "KiB" - set_pagesize = "2048" - set_pagenum = "1024" expect_str = "huge" - aarch64: - page_size = "524288" - current_mem = 1572864 - mem_value = 1572864 - set_pagesize = "524288" - set_pagenum = "4" + variants kernel_pagesize: + - 4k: + default_page_size = 4 + variants huge_pagesize: + - 2048: + page_size = "2048" + current_mem = 2072576 + mem_value = 2072576 + set_pagesize = "2048" + set_pagenum = "1024" + - 64k: + default_page_size = 64 + only aarch64 + variants huge_pagesize: + - 524288: + page_size = "524288" + current_mem = 1572864 + mem_value = 1572864 + set_pagesize = "524288" + set_pagenum = "4" variants: - nodeset_0: nodeset = "0" @@ -26,11 +35,11 @@ memory_backing_dict = "'mb': {'hugepages': {'pages': [{'unit': '${page_unit}', 'size': '${page_size}','nodeset':'${nodeset}'}]}}" with_numa_error = "error: hugepages: node 2 not found" without_numa_error = "error: hugepages: node 0 not found" - variants config: + variants numa_config: - with_numa: numa_size_1 = 1048576 numa_size_2 = 1024000 - aarch64: + 524288: numa_size_2 = 524288 numa_cpu = {'numa_cell': [{'id': '0', 'cpus': '0-1', 'memory': '${numa_size_1}', 'unit': 'KiB'}, {'id': '1', 'cpus': '2-3', 'memory': '${numa_size_2}', 'unit': 'KiB'}]} vm_attrs = {${memory_backing_dict},"cpu":${numa_cpu},'vcpu': 4,'max_mem_rt_slots': 16,'memory_unit':"${mem_unit}",'memory':${mem_value},'current_mem':${current_mem},'current_mem_unit':'${current_mem_unit}','max_mem_rt': 3145728, 'max_mem_rt_unit': "KiB"} @@ -40,5 +49,6 @@ vm_attrs = {${memory_backing_dict}, 'memory_unit':'${mem_unit}','memory':${mem_value},'current_mem':${current_mem},'current_mem_unit':'${current_mem_unit}'} expect_xpath = [{'element_attrs':[".//page[@size='${page_size}']", ".//page[@unit='${page_unit}']"]}] allocated_mem = "2072576" - aarch64: + 524288: allocated_mem = "1572864" + diff --git a/libvirt/tests/cfg/memory/memory_backing/lifecycle_for_hugepage.cfg b/libvirt/tests/cfg/memory/memory_backing/lifecycle_for_hugepage.cfg index 9db45e9d58f..c63fe910152 100644 --- a/libvirt/tests/cfg/memory/memory_backing/lifecycle_for_hugepage.cfg +++ b/libvirt/tests/cfg/memory/memory_backing/lifecycle_for_hugepage.cfg @@ -1,17 +1,20 @@ - memory.backing.lifecycle: type = lifecycle_for_hugepage - vm_nr_hugepages = 1024 + start_vm = no + total_hugepage_mem = 8388608 + vm_nr_hugepages = 4096 mount_size = "1048576" - current_mem = 2097152 - mem_value = 2097152 + current_mem = 8388608 + mem_value = 8388608 mem_unit = "KiB" current_mem_unit = "KiB" - target_hugepages = 2 + target_hugepages = 8 set_pagesize ="1048576" - set_pagenum = "2" - free_hugepages_cmd= "cat /sys/kernel/mm/hugepages/hugepages-1048576kB/free_hugepages" + set_pagenum = "8" s390-virtio: - free_hugepages_cmd= "cat /sys/kernel/mm/hugepages/hugepages-1024kB/free_hugepages" + total_hugepage_mem = 2097152 + current_mem = 2097152 + mem_value = 2097152 set_pagesize = "1024" mount_size = "1024" set_pagenum = "2048" @@ -19,34 +22,80 @@ kvm_module_parameters = variants: - memory_hugepage: - variants: - - 4k: + variants scenario: + - default_page_size: no s390-virtio page_size = "4" page_unit = "KiB" memory_backing_dict = "'mb': {'hugepages': {'pages': [{'unit': '${page_unit}', 'size': '${page_size}'}]}}" vm_attrs = {${memory_backing_dict}, 'memory_unit':'${mem_unit}','memory':${mem_value},'current_mem':${current_mem},'current_mem_unit':'${current_mem_unit}'} - HugePages_Free = "1024" - free_hugepages = "2" + HugePages_Free = ${vm_nr_hugepages} + free_hugepages = ${set_pagenum} - 1M: only s390-virtio memory_backing_dict = "'mb': {'hugepages': {}}" vm_attrs = {${memory_backing_dict}, 'memory_unit':'${mem_unit}','memory':${mem_value},'current_mem':${current_mem},'current_mem_unit':'${current_mem_unit}'} HugePages_Free = "0" free_hugepages = "0" - - 2M: + - default_hugepage_size: no s390-virtio memory_backing_dict = "'mb': {'hugepages': {}}" vm_attrs = {${memory_backing_dict}, 'memory_unit':'${mem_unit}','memory':${mem_value},'current_mem':${current_mem},'current_mem_unit':'${current_mem_unit}'} HugePages_Free = "0" - free_hugepages = "2" + free_hugepages = ${set_pagenum} - 1G: no s390-virtio page_size = "1" page_unit = "G" memory_backing_dict = "'mb': {'hugepages': {'pages': [{'unit': '${page_unit}', 'size': '${page_size}'}]}}" vm_attrs = {${memory_backing_dict}, 'memory_unit':'${mem_unit}','memory':${mem_value},'current_mem':${current_mem},'current_mem_unit':'${current_mem_unit}'} - HugePages_Free = "1024" + HugePages_Free = ${vm_nr_hugepages} + free_hugepages = "0" + - 2M: + only aarch64 + page_size = "2" + page_unit = "M" + set_pagesize ="2048" + set_pagenum = "4096" + mount_size = ${set_pagesize} + memory_backing_dict = "'mb': {'hugepages': {'pages': [{'unit': '${page_unit}', 'size': '${page_size}'}]}}" + vm_attrs = {${memory_backing_dict}, 'memory_unit':'${mem_unit}','memory':${mem_value},'current_mem':${current_mem},'current_mem_unit':'${current_mem_unit}'} + HugePages_Free = + free_hugepages = "0" + - 16G: + only aarch64 + page_size = "16" + page_unit = "G" + set_pagesize ="16777216" + set_pagenum = "1" + mount_size = ${set_pagesize} + mem_value = 16777216 + current_mem = 16777216 + memory_backing_dict = "'mb': {'hugepages': {'pages': [{'unit': '${page_unit}', 'size': '${page_size}'}]}}" + vm_attrs = {${memory_backing_dict}, 'memory_unit':'${mem_unit}','memory':${mem_value},'current_mem':${current_mem},'current_mem_unit':'${current_mem_unit}'} + HugePages_Free = + free_hugepages = "0" + - 64K: + only aarch64 + page_size = "64" + page_unit = "KiB" + set_pagesize ="64" + set_pagenum = "131072" + mount_size = ${set_pagesize} + memory_backing_dict = "'mb': {'hugepages': {'pages': [{'unit': '${page_unit}', 'size': '${page_size}'}]}}" + vm_attrs = {${memory_backing_dict}, 'memory_unit':'${mem_unit}','memory':${mem_value},'current_mem':${current_mem},'current_mem_unit':'${current_mem_unit}'} + HugePages_Free = + free_hugepages = "0" + - 32M: + only aarch64 + page_size = "32" + page_unit = "M" + set_pagesize ="32768" + set_pagenum = "256" + mount_size = ${set_pagesize} + memory_backing_dict = "'mb': {'hugepages': {'pages': [{'unit': '${page_unit}', 'size': '${page_size}'}]}}" + vm_attrs = {${memory_backing_dict}, 'memory_unit':'${mem_unit}','memory':${mem_value},'current_mem':${current_mem},'current_mem_unit':'${current_mem_unit}'} + HugePages_Free = free_hugepages = "0" - 0: page_size = "0" @@ -55,8 +104,8 @@ vm_attrs = {${memory_backing_dict}, 'memory_unit':'${mem_unit}','memory':${mem_value},'current_mem':${current_mem},'current_mem_unit':'${current_mem_unit}'} define_error = "hugepage size can't be zero" - scarce_mem: - current_mem = 3145728 - mem_value = 3145728 + current_mem = 9437184 + mem_value = 9437184 memory_backing_dict = "'mb': {'hugepages': {}}" vm_attrs = {${memory_backing_dict}, 'memory_unit':'${mem_unit}','memory':${mem_value},'current_mem':${current_mem},'current_mem_unit':'${current_mem_unit}'} start_error = "unable to map backing store for guest RAM: Cannot allocate memory" diff --git a/libvirt/tests/cfg/memory/memory_backing/memory_access_mode.cfg b/libvirt/tests/cfg/memory/memory_backing/memory_access_mode.cfg index 70842ab5b4f..3c7f3efb7c3 100644 --- a/libvirt/tests/cfg/memory/memory_backing/memory_access_mode.cfg +++ b/libvirt/tests/cfg/memory/memory_backing/memory_access_mode.cfg @@ -1,16 +1,31 @@ - memory.backing.access_mode: type = memory_access_mode - set_pagesize = 2048 - set_pagenum = 1024 numa_mem = 2097152 - aarch64: - set_pagesize = 524288 - set_pagenum = 4 start_vm = no qemu_monitor_option = '--hmp' qemu_monitor_cmd = 'info memdev' pattern_share = "share:\s*{}" mem_backend = "memory backend: ram-node0" + variants kernel_pagesize: + - 4k: + default_page_size = 4 + variants huge_pagesize: + - 2048: + no s390-virtio + set_pagesize = 2048 + set_pagenum = 1024 + - 1024: + only s390-virtio + set_pagesize = 1024 + set_pagenum = 2048 + kvm_module_parameters = + - 64k: + only aarch64 + default_page_size = 64 + variants huge_pagesize: + - 524288: + set_pagesize = 524288 + set_pagenum = 4 variants source: - file: source_type = 'file' @@ -37,19 +52,24 @@ - mem_access_default: variants numa_access: - numa_access_private: + no s390-virtio numa_access_mode = 'private' numa_attrs = {'vcpu': 4,'cpu': {'numa_cell': [{'id': '0', 'cpus': '0-3', 'memory': '${numa_mem}', 'unit': 'KiB', 'memAccess':'${numa_access_mode}'}]}} numa_access_path = {'element_attrs': ['./cpu/numa/cell/[@memAccess="${numa_access_mode}"]', './cpu/numa/cell/[@memory="${numa_mem}"]']} - numa_access_shared: + no s390-virtio numa_access_mode = 'shared' numa_attrs = {'vcpu': 4,'cpu': {'numa_cell': [{'id': '0', 'cpus': '0-3', 'memory': '${numa_mem}', 'unit': 'KiB', 'memAccess':'${numa_access_mode}'}]}} numa_access_path = {'element_attrs': ['./cpu/numa/cell/[@memAccess="${numa_access_mode}"]', './cpu/numa/cell/[@memory="${numa_mem}"]']} - numa_access_default: + no s390-virtio numa_attrs = {'vcpu': 4,'cpu': {'numa_cell': [{'id': '0', 'cpus': '0-3', 'memory': '${numa_mem}', 'unit': 'KiB'}]}} - no_numa: mem_backend = "memory backend: pc.ram" aarch64: mem_backend = "memory backend: mach-virt.ram" + s390-virtio: + mem_backend = "memory backend: s390.ram" variants mem_pagesize: - without_hugepage: - with_hugepage: @@ -63,3 +83,4 @@ current_mem = "2097152" mem_value = "2097152" mem_attrs = {'memory_unit':'${mem_unit}','memory':${mem_value},'current_mem':${current_mem},'current_mem_unit':'${current_mem_unit}'} + diff --git a/libvirt/tests/cfg/memory/memory_backing/memory_source_and_allocation.cfg b/libvirt/tests/cfg/memory/memory_backing/memory_source_and_allocation.cfg index 2e6699fd470..5eff829f764 100644 --- a/libvirt/tests/cfg/memory/memory_backing/memory_source_and_allocation.cfg +++ b/libvirt/tests/cfg/memory/memory_backing/memory_source_and_allocation.cfg @@ -2,15 +2,31 @@ type = memory_source_and_allocation start_vm = no check_allocated_cmd = "grep -A20 '^Size:.*2097152' /proc/`pidof qemu-kvm`/smaps" - set_pagesize = 2048 - set_pagenum = 1024 monitor_option = "--hmp" monitor_cmd = "info memdev" memory_name_pattern = 'memory backend: (\S+)' check_thread = '{"execute":"qom-get", "arguments":{"path": "/objects/%s", "property":"%s"}}' - aarch64: - set_pagesize = 524288 - set_pagenum = 4 + variants kernel_pagesize: + -4k: + default_page_size = 4 + variants huge_pagesize: + - 2048: + no s390-virtio + set_pagesize = 2048 + set_pagenum = 1024 + - 1024: + only s390-virtio + set_pagesize = 1024 + set_pagenum = 1024 + kvm_module_parameters = + check_allocated_cmd = "grep -A20 '^Size:.*1048576' /proc/`pidof qemu-kvm`/smaps" + -64k: + only aarch64 + default_page_size = 64 + variants huge_pagesize: + - 524288: + set_pagesize = 524288 + set_pagenum = 4 variants source: - file: source_type = 'file' @@ -59,6 +75,7 @@ alloc_mode_path = {'element_attrs': ["./memoryBacking/allocation[@mode=${mode}]", "./memoryBacking/allocation[@threads=${threads}]"]} variants numa_discard: - with_numa: + no s390-virtio numa_mem = 2097152 numa_attrs = {'vcpu': 4,'cpu': {'numa_cell': [{'id': '0', 'cpus': '0-3', 'memory': '${numa_mem}', 'unit': 'KiB'}]}} - without_numa: @@ -69,3 +86,8 @@ current_mem = "2097152" mem_value = "2097152" mem_attrs = {'memory_unit':'${mem_unit}','memory':${mem_value},'current_mem':${current_mem},'current_mem_unit':'${current_mem_unit}'} + s390-virtio: + current_mem = "1048576" + mem_value = "1048576" + mem_attrs = {'memory_unit':'${mem_unit}','memory':${mem_value},'current_mem':${current_mem},'current_mem_unit':'${current_mem_unit}'} + diff --git a/libvirt/tests/cfg/memory/memory_backing/page_locking_and_shared_pages.cfg b/libvirt/tests/cfg/memory/memory_backing/page_locking_and_shared_pages.cfg index cce39d35813..d379af0248c 100644 --- a/libvirt/tests/cfg/memory/memory_backing/page_locking_and_shared_pages.cfg +++ b/libvirt/tests/cfg/memory/memory_backing/page_locking_and_shared_pages.cfg @@ -1,9 +1,27 @@ - memory.backing.page_locking_and_shared_pages: type = page_locking_and_shared_pages start_vm = no - pagesize = 2048 - pagenum = 1024 expect_exist = True + variants default_pagesize: + - 4k: + kernel_pagesize = 4 + variants huge_pagesize: + - 1024: + only s390-virtio + pagesize = 1024 + pagenum = 2048 + - 2048: + no s390-virtio + pagesize = 2048 + pagenum = 1024 + - 64k: + only aarch64 + kernel_pagesize = 64 + variants huge_pagesize: + - 524288: + only aarch64 + pagesize = 524288 + pagenum = 4 variants lock_config: - lock_default: only ksm_disabled @@ -28,6 +46,8 @@ - page_default: - hugepage: hugepages_dict = "'hugepages': {}" + s390-virtio: + kvm_module_parameters = variants: - memory_allocation: mem_unit = "KiB" @@ -36,3 +56,4 @@ mem_value = "2097152" mem_attrs = {'memory_unit':'${mem_unit}','memory':${mem_value},'current_mem':${current_mem},'current_mem_unit':'${current_mem_unit}'} qemu_line = ["${lock_qemu_line}", "${ksm_qemu_line}"] + diff --git a/libvirt/tests/cfg/memory/memory_balloon/guest_without_mem_balloon.cfg b/libvirt/tests/cfg/memory/memory_balloon/guest_without_mem_balloon.cfg index 77c0e3a5933..ecdc4faa6d9 100644 --- a/libvirt/tests/cfg/memory/memory_balloon/guest_without_mem_balloon.cfg +++ b/libvirt/tests/cfg/memory/memory_balloon/guest_without_mem_balloon.cfg @@ -13,8 +13,10 @@ - virtio_model: memballoon_model = "virtio" - virtio_trans_model: + no s390-virtio memballoon_model = "virtio-transitional" - virtio_non_trans_model: + no s390-virtio memballoon_model = "virtio-non-transitional" device_dict = "{'model':'${memballoon_model}'}" variants: diff --git a/libvirt/tests/cfg/memory/memory_balloon/mem_balloon_autodeflate.cfg b/libvirt/tests/cfg/memory/memory_balloon/mem_balloon_autodeflate.cfg index aa29005715e..684607d75f0 100644 --- a/libvirt/tests/cfg/memory/memory_balloon/mem_balloon_autodeflate.cfg +++ b/libvirt/tests/cfg/memory/memory_balloon/mem_balloon_autodeflate.cfg @@ -11,8 +11,10 @@ - virtio_model: memballoon_model = "virtio" - virtio_trans_model: + no s390-virtio memballoon_model = "virtio-transitional" - virtio_non_trans_model: + no s390-virtio memballoon_model = "virtio-non-transitional" variants: - autodeflate_undefined: diff --git a/libvirt/tests/cfg/memory/memory_balloon/memory_balloon_freepagereporting.cfg b/libvirt/tests/cfg/memory/memory_balloon/memory_balloon_freepagereporting.cfg new file mode 100644 index 00000000000..7260b1d3a18 --- /dev/null +++ b/libvirt/tests/cfg/memory/memory_balloon/memory_balloon_freepagereporting.cfg @@ -0,0 +1,29 @@ +- memory.balloon.freepagereporting: + type = memory_balloon_freepagereporting + start_vm = no + current_mem = 4194304 + mem_value = 4194304 + set_memroy = 3145728 + mem_consume_cmd = "timeout 20s memhog -r80 %sk" + unconsumed_mem = 204800 + variants: + - virtio: + model = "virtio" + - virtio-non-transitional: + no s390-virtio + model = "virtio-non-transitional" + variants: + - undefined: + freepage_reporting_config = "" + max_memory_difference = 51200 + - off: + freepagereporting = off + freepage_reporting_config = ", 'freepage_reporting':'${freepagereporting}'" + max_memory_difference = 51200 + - on: + freepagereporting = on + freepage_reporting_config = ", 'freepage_reporting':'${freepagereporting}'" + min_memory_difference = 819200 + memballoon_dict ={'model':'${model}' ${freepage_reporting_config}} + mem_attrs = {'memory_unit':'KiB','memory':${mem_value},'current_mem':${current_mem},'current_mem_unit':'KiB'} + diff --git a/libvirt/tests/cfg/memory/memory_balloon/period_config_of_memory_balloon.cfg b/libvirt/tests/cfg/memory/memory_balloon/period_config_of_memory_balloon.cfg new file mode 100644 index 00000000000..2052f49ed8d --- /dev/null +++ b/libvirt/tests/cfg/memory/memory_balloon/period_config_of_memory_balloon.cfg @@ -0,0 +1,34 @@ +- memory.balloon.period: + type = period_config_of_memory_balloon + start_vm = no + mem_unit = "KiB" + current_mem_unit = "KiB" + current_mem = "2097152" + mem_value = "2097152" + mem_operation = "swapoff -a && dd if=/dev/zero of=/tmp/temp bs=1024K count=10 && timeout 5s memhog -r5000 500M" + variants: + - virtio_model: + memballoon_model = "virtio" + - virtio_trans_model: + no s390-virtio + memballoon_model = "virtio-transitional" + - virtio_non_trans_model: + no s390-virtio + memballoon_model = "virtio-non-transitional" + variants: + - undefined_period: + period_value_1 = "undefined" + period_attr = "" + xpath = [{'element_attrs': [".//memballoon/stats"]}] + period_value_2 = "2" + period_cmd = "--period ${period_value_2}" + - int_period: + period_value_1 = "2" + period_attr = ",'stats_period':'${period_value_1}'" + xpath = [{'element_attrs': [".//stats[@period='${period_value_1}']"]}] + period_value_2 = "0" + period_cmd = "--period ${period_value_2}" + device_dict = "{'model':'${memballoon_model}' ${period_attr}}" + variants: + - memory_allocation: + mem_attrs = {'memory_unit':'${mem_unit}','memory':${mem_value},'current_mem':${current_mem},'current_mem_unit':'${current_mem_unit}'} diff --git a/libvirt/tests/cfg/memory/memory_devices/change_virtio_mem_request_size.cfg b/libvirt/tests/cfg/memory/memory_devices/change_virtio_mem_request_size.cfg new file mode 100644 index 00000000000..7b3cb917e6e --- /dev/null +++ b/libvirt/tests/cfg/memory/memory_devices/change_virtio_mem_request_size.cfg @@ -0,0 +1,75 @@ +- memory.devices.virtio_mem.change_memory: + type = change_virtio_mem_request_size + start_vm = yes + mem_model = "virtio-mem" + allocate_huge_pages = "4194304KiB" + target_size = 1048576 + request_size = 524288 + requested_unit = "KiB" + basic_request = "${request_size}${requested_unit}" + basic_node = 0 + basic_device = "--node ${basic_node} --config" + virsh_opts = "%s --requested-size %s " + expected_event = "memory-device-size-change" + required_kernel = [5.14.0,) + guest_required_kernel = [5.8.0,) + func_supported_since_libvirt_ver = (8, 0, 0) + func_supported_since_qemu_kvm_ver = (6, 2, 0) + mem_value = 2097152 + memory_unit = 'KiB' + current_mem = 2097152 + max_mem = 10485760 + max_mem_slots = 16 + numa_mem = 1048576 + base_attrs = "'memory_unit':'${memory_unit}','memory':${mem_value},'current_mem':${current_mem},'current_mem_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'}]}" + max_attrs = "'max_mem_rt': ${max_mem}, 'max_mem_rt_slots': ${max_mem_slots}, 'max_mem_rt_unit': 'KiB'" + vm_attrs = {${base_attrs}, ${numa_attrs}, ${max_attrs}} + with_numa = yes + s390-virtio: + with_numa = no + vm_attrs = {${base_attrs}, ${max_attrs}} + expect_xpath = [{'element_attrs':[".//memory[@unit='${memory_unit}']"],'text':'%d'},{'element_attrs':[".//currentMemory[@unit='KiB']"],'text':'%d'}] + variants guest_state: + - shutoff_guest: + no s390-virtio + no file hugepages memfd + mem_basic = {'mem_model': '${mem_model}', 'target': {'requested_unit': '${requested_unit}', 'size': %s, 'node': ${basic_node}, 'size_unit': 'KiB', 'requested_size': %s, 'block_unit': 'KiB', 'block_size': %s}} + - running_guest: + kernel_params_add = "memhp_default_state=online_movable" + kernel_params_remove = "memhp_default_state" + attach_node = 1 + attached_device = "--node ${attach_node}" + basic_device_alias = "--alias virtiomem0" + mem_basic = {'mem_model': '${mem_model}', 'target': {'requested_unit': '${requested_unit}', 'size': %s, 'node': ${basic_node}, 'size_unit': 'KiB', 'requested_size': %s, 'block_unit': 'KiB', 'block_size': %s}} + mem_attach = {'mem_model': '${mem_model}', 'target': {'requested_unit': '${requested_unit}', 'size': %s, 'node': ${attach_node}, 'size_unit': 'KiB', 'requested_size': %s, 'block_unit': 'KiB', 'block_size': %s}} + s390-virtio: + attached_device = "--alias virtiomem1" + mem_basic = {'mem_model': '${mem_model}', 'target': {'requested_unit': '${requested_unit}', 'size': %s, 'size_unit': 'KiB', 'requested_size': %s, 'block_unit': 'KiB', 'block_size': %s}} + mem_attach = {'mem_model': '${mem_model}', 'target': {'requested_unit': '${requested_unit}', 'size': %s, 'size_unit': 'KiB', 'requested_size': %s, 'block_unit': 'KiB', 'block_size': %s}} + variants requested_setting: + - normal_requested: + update_request_size = '1024MiB' + - zero_requested: + update_request_size = "0MiB" + - bigger_requested: + update_request_size = '2048MiB' + error_msg = "requested size must be smaller than or equal to" + - not_mutiple_of_block_requested: + update_request_size = '513MiB' + s390-virtio: + update_request_size = '524800KiB' + error_msg = "requested size must be an integer multiple of block size" + variants memory_backing: + - file: + source_type = 'file' + source_attr = "'source_type':'${source_type}'" + - hugepages: + s390-virtio: + kvm_module_parameters = "hpage=1" + hugepages_attr = "'hugepages': {}" + - memfd: + source_type = 'memfd' + source_attr = "'source_type':'${source_type}'" + - undefined: + diff --git a/libvirt/tests/cfg/memory/memory_devices/dimm_memory_hot_unplug.cfg b/libvirt/tests/cfg/memory/memory_devices/dimm_memory_hot_unplug.cfg new file mode 100644 index 00000000000..cb5cfb7bc1b --- /dev/null +++ b/libvirt/tests/cfg/memory/memory_devices/dimm_memory_hot_unplug.cfg @@ -0,0 +1,56 @@ +- memory.devices.dimm.hot_unplug: + no s390-virtio + type = dimm_memory_hot_unplug + start_vm = yes + mem_model = 'dimm' + allocate_size = "1048576" + allocate_memory = "${allocate_size}KiB" + target_size = "524288" + size_unit = 'KiB' + node = 0 + mem_value = 3670016 + current_mem = 3670016 + numa_mem = 1572864 + max_mem = 4194304 + max_mem_slots = 16 + slot = '0' + audit_cmd = "grep VIRT_RESOURCE /var/log/audit/audit.log | grep 'mem' | tail -n 20" + ausearch_check = 'old-mem=%d new-mem=%d' + expected_log = "ACPI_DEVICE_OST|device_del" + kernel_hp_file = '/sys/devices/system/node/node0/hugepages/hugepages-%skB/nr_hugepages' + max_dict = '"max_mem_rt": ${max_mem}, "max_mem_rt_slots": ${max_mem_slots}, "max_mem_rt_unit": "KiB"' + numa_dict = "'vcpu': 4,'cpu':{'numa_cell': [{'id': '0', 'cpus': '0-1', 'memory': '${numa_mem}'}, {'id': '1', 'cpus': '2-3', 'memory': '${numa_mem}'}]}" + vm_attrs = {${numa_dict},${max_dict},'memory_unit':'KiB','memory':${mem_value},'current_mem':${current_mem},'current_mem_unit':'KiB'} + variants plug_dimm_type: + - target_and_address: + base = "0x140000000" + addr_dict = "'address':{'attrs': {'type':'dimm','slot':'${slot}','base':'${base}'}}" + dimm_dict = {'mem_model':'${mem_model}',${addr_dict},'target': {'size':${target_size}, 'size_unit':'${size_unit}', 'node':${node}}} + unplug_dimm_dict = ${dimm_dict} + - source_and_mib: + target_size = "512" + size_unit = 'MiB' + node = 0 + source_dict = "'source':{'nodemask': '0','pagesize': %d, 'pagesize_unit':'KiB'}" + dimm_dict = {'mem_model':'${mem_model}',${source_dict},'target': {'size':${target_size}, 'size_unit':'${size_unit}', 'node':${node}}} + unplug_dimm_dict = ${dimm_dict} + - unexisted_device: + unplug_node = 1 + dimm_dict = {'mem_model':'${mem_model}','target': {'size':${target_size}, 'size_unit':'${size_unit}', 'node':${node}}} + unplug_dimm_dict = {'mem_model':'${mem_model}','target': {'size':${target_size}, 'size_unit':'${size_unit}', 'node':${unplug_node}}} + base_xpath = [{'element_attrs':[".//memory[@unit='KiB']"],'text':'%d'},{'element_attrs':[".//currentMemory[@unit='KiB']"],'text':'%d'}] + dimm_xpath = [{'element_attrs':[".//target/size[@unit='KiB']"],'text':'%s'},{'element_attrs':[".//address[@slot='%s']"]}] + variants mem_state: + - default_mem: + target_and_address: + unplug_event = "device-removal-failed" + unplug_error = "unplug of device was rejected by the guest" + source_and_mib: + unplug_event = "device-removal-failed" + unplug_error = "unplug of device was rejected by the guest" + unexisted_device: + unplug_error = "model 'dimm' memory device not present in the domain configuration" + - online_movable_mem: + no unexisted_device + unplug_event = "device-removed" + kernel_extra_params_add = "memhp_default_state=online_movable" diff --git a/libvirt/tests/cfg/memory/memory_devices/dimm_memory_hotplug.cfg b/libvirt/tests/cfg/memory/memory_devices/dimm_memory_hotplug.cfg new file mode 100644 index 00000000000..a9ea437e7e2 --- /dev/null +++ b/libvirt/tests/cfg/memory/memory_devices/dimm_memory_hotplug.cfg @@ -0,0 +1,68 @@ +- memory.devices.dimm.hotplug: + no s390-virtio + type = dimm_memory_hotplug + start_vm = yes + mem_model = 'dimm' + allocate_size = "1572864" + allocate_memory = "${allocate_size}KiB" + target_size = "524288" + size_unit = 'KiB' + slot = '0' + node = 0 + plug_node = 0 + plug_slot = 1 + mem_value = 2097152 + current_mem = 2097152 + numa_mem = 1048576 + max_mem = 4194304 + max_mem_slots = 16 + plug_event = "device-added" + audit_cmd = "grep VIRT_RESOURCE /var/log/audit/audit.log | grep 'mem' | tail -n 20" + ausearch_check = 'old-mem=%d new-mem=%d' + expected_log = "ACPI_DEVICE_OST|device_add" + kernel_hp_file = '/sys/devices/system/node/node0/hugepages/hugepages-%skB/nr_hugepages' + max_dict = '"max_mem_rt": ${max_mem}, "max_mem_rt_slots": ${max_mem_slots}, "max_mem_rt_unit": "KiB"' + numa_dict = "'vcpu': 4,'cpu':{'numa_cell': [{'id': '0', 'cpus': '0-1', 'memory': '${numa_mem}'}, {'id': '1', 'cpus': '2-3', 'memory': '${numa_mem}'}]}" + vm_attrs = {${numa_dict},${max_dict},'memory_unit':'KiB','memory':${mem_value},'current_mem':${current_mem},'current_mem_unit':'KiB'} + variants plug_dimm_type: + - target_and_address: + plug_node = 1 + plug_target_size = '1048576' + addr_dict = {'attrs': {'type':'dimm','slot':'${slot}'}} + plug_addr = {'attrs': {'type':'dimm','slot':'${plug_slot}'}} + plug_size_unit = "${size_unit}" + - source_and_mib: + target_size = "1024" + size_unit = 'MiB' + node = 1 + plug_node = 1 + plug_target_size = "512" + plug_size_unit = "MiB" + source_dict = {'nodemask': '0','pagesize': %d, 'pagesize_unit':'KiB'} + - plug_exceeded_max_mem: + plug_size_unit = "G" + plug_target_size = "2" + plug_error = "exceed domain's maxMemory config size '${max_mem}'" + - duplicate_addr: + plug_size_unit = "${size_unit}" + plug_target_size = "${target_size}" + base = "0x100000000" + addr_dict = {'attrs': {'type':'dimm','base': '${base}', 'slot':'${slot}'}} + plug_addr = {'attrs': {'type':'dimm','base': '${base}', 'slot':'${plug_slot}'}} + plug_error = "same address|overlaps" + - duplicate_slot: + base = "0x100000000" + plug_size_unit = "${size_unit}" + plug_slot = 0 + plug_target_size = "${target_size}" + addr_dict = {'attrs': {'type':'dimm','slot':'${slot}'}} + plug_addr = {'attrs': {'type':'dimm','base': '${base}', 'slot':'${plug_slot}'}} + plug_error = "memory device slot '0' is already being used by another memory device" + - zero_memory_unit_gb: + plug_size_unit = "G" + plug_target_size = "0" + plug_error = "property 'size' of memory-backend-ram doesn't take value '0'" + dimm_dict = {'mem_model':'${mem_model}','target': {'size':${target_size}, 'size_unit':'${size_unit}', 'node':${node}}} + plug_dimm_dict = {'mem_model':'${mem_model}','target': {'size':${plug_target_size}, 'size_unit':'${plug_size_unit}', 'node':${plug_node}}} + base_xpath = [{'element_attrs':[".//memory[@unit='KiB']"],'text':'%d'},{'element_attrs':[".//currentMemory[@unit='KiB']"],'text':'%d'}] + dimm_xpath = [{'element_attrs':[".//target/size[@unit='KiB']"],'text':'%s'},{'element_attrs':[".//address[@slot='%s']"]}] diff --git a/libvirt/tests/cfg/memory/memory_devices/dimm_memory_lifecycle.cfg b/libvirt/tests/cfg/memory/memory_devices/dimm_memory_lifecycle.cfg new file mode 100644 index 00000000000..3835ac721b5 --- /dev/null +++ b/libvirt/tests/cfg/memory/memory_devices/dimm_memory_lifecycle.cfg @@ -0,0 +1,81 @@ +- memory.devices.dimm.lifecycle: + type = dimm_memory_lifecycle + no s390-virtio + start_vm = no + check_path_secure_cmd = "ls /dev/hugepages/libvirt/qemu/ -dlZ" + path_secure_context = " root root system_u:object_r:hugetlbfs_t:s0" + check_guest_secure_cmd = "ls /dev/hugepages/libvirt/qemu/%s-%s -dlZ" + guest_secure_context = " qemu qemu system_u:object_r:svirt_image_t:s0" + numa_mem_val = 1048576 + memory_val = 2228224 + current_mem_val = 2228224 + init_size = 131072 + plug_size = 262144 + aarch64: + numa_mem_val = 4194304 + memory_val = 8912896 + current_mem_val = 8912896 + init_size = 524288 + plug_size = 1572864 + vm_attrs = {'max_mem_rt': 15428800, 'max_mem_rt_slots': 16,'max_mem_rt_unit': 'KiB','memory_unit':"KiB", 'memory':${memory_val}, 'current_mem':${current_mem_val}, 'current_mem_unit':'KiB', 'vcpu': 4,'cpu': {'numa_cell': [{'id': '0', 'cpus': '0-1', 'memory': '${numa_mem_val}', 'unit': 'KiB'},{'id':'1','cpus': '2-3','memory':'${numa_mem_val}','unit':'KiB'}]}} + init_target_dict = {'size':${init_size}, 'size_unit':'KiB', 'node':0} + init_target_xpath = [{'element_attrs':[".//target/size[@unit='KiB']"],'text':'${init_size}'}, {'element_attrs':[".//target/node"],'text':'0'}] + plug_target_dict = {'size':${plug_size}, 'size_unit':'KiB', 'node':1} + plug_target_xpath = [{'element_attrs':[".//target/size[@unit='KiB']"],'text':'${plug_size}'}, {'element_attrs':[".//target/node"],'text':'1'}] + x86_64: + bios_check = 'yes' + sysinfo_attrs = {'type': 'smbios', 'bios_entry': [{'entry': 'LENOVO', 'entry_name': 'vendor'}]} + idmap_attrs = {'uid': {'start': '0', 'target': '1000', 'count': '10'}, 'gid': {'start': '0', 'target': '1000', 'count': '10'}} + os_attrs = {'smbios_mode': 'sysinfo'} + bios_check_xpath = [{'element_attrs':[".//os/smbios[@mode='sysinfo']"]}, {'element_attrs':[".//sysinfo[@type='smbios']"]}, {'element_attrs':[".//sysinfo/bios/entry[@name='vendor']"],'text':'LENOVO'}, {'element_attrs':[".//idmap/uid[@start='0']", ".//idmap/uid[@target='1000']", ".//idmap/uid[@count='10']"]}, {'element_attrs':[".//idmap/gid[@start='0']", ".//idmap/gid[@target='1000']", ".//idmap/gid[@count='10']"]}] + variants kernel_pagesize: + - 4k: + only x86_64, aarch64 + page_size = 4 + default_hp_size = 2048 + - 64k: + only aarch64 + page_size = 64 + default_hp_size = 524288 + variants memory_source: + - no_source: + source_dict = {} + source_xpath = [] + - nodemask: + nodeset_num = 1 + source_dict = {'nodemask':'%s'} + source_xpath = [{'element_attrs':[".//source/nodemask"],'text':'%s'}] + - pagesize: + source_dict = {'pagesize':${page_size}, 'pagesize_unit':'KiB'} + source_xpath = [{'element_attrs':[".//source/pagesize[@unit='KiB']"],'text':'${page_size}'}] + - nodemask_pagesize: + nodeset_num = 2 + use_huge_page = "yes" + source_dict = {'nodemask':'%s', 'pagesize':${default_hp_size}, 'pagesize_unit':'KiB'} + source_xpath = [{'element_attrs':[".//source/nodemask"],'text':'%s'}, {'element_attrs':[".//source/pagesize[@unit='KiB']"],'text':'${default_hp_size}'}] + variants address_config: + - no_address: + init_alias_name = "dimm0" + plug_alias_name = "dimm1" + init_address_dict = {} + plug_address_dict = {} + init_address_xpath= [{'element_attrs':[".//address[@slot='0']", ".//address[@base]"]}] + plug_address_xpath= [{'element_attrs':[".//address[@slot='1']", ".//address[@base]"]}] + - slot_base: + init_address = '0x200000000' + plug_address = '0x400000000' + aarch64: + init_address = '0x300000000' + init_slot = '1' + plug_slot = '2' + init_alias_name = "dimm${init_slot}" + plug_alias_name = "dimm${plug_slot}" + init_address_dict = {'attrs':{'base':'${init_address}', 'type':'dimm', 'slot':'${init_slot}'}} + init_address_xpath= [{'element_attrs':[".//address[@slot='${init_slot}']", ".//address[@base='${init_address}']"]}] + plug_address_dict = {'attrs':{'base':'${plug_address}', 'type':'dimm', 'slot':'${plug_slot}'}} + plug_address_xpath= [{'element_attrs':[".//address[@slot='${plug_slot}']", ".//address[@base='${plug_address}']"]}] + init_mem_device_dict = {'mem_model':'dimm', 'source':${source_dict}, 'target':${init_target_dict}, 'address':${init_address_dict}} + init_xpath_list = [${source_xpath}, ${init_target_xpath}, ${init_address_xpath}] + plug_mem_device_dict = {'mem_model':'dimm', 'source':${source_dict}, 'target':${plug_target_dict}, 'address':${plug_address_dict}} + plug_xpath_list = [${source_xpath}, ${plug_target_xpath}, ${plug_address_xpath}] + diff --git a/libvirt/tests/cfg/memory/memory_devices/dimm_memory_with_access_and_discard.cfg b/libvirt/tests/cfg/memory/memory_devices/dimm_memory_with_access_and_discard.cfg new file mode 100644 index 00000000000..9ba22d069a6 --- /dev/null +++ b/libvirt/tests/cfg/memory/memory_devices/dimm_memory_with_access_and_discard.cfg @@ -0,0 +1,61 @@ +- memory.devices.dimm.access_and_discard: + type = dimm_memory_with_access_and_discard + no s390-virtio + start_vm = yes + mem_model = "dimm" + dimm_mem_num = 6 + share_0 = 'false' + discard_0 = 'False' + check_path = "ls -l /var/lib/libvirt/qemu/ram/%s" + target_size = 524288 + requested_size = 1048576 + dimm_basic = {'mem_model': '${mem_model}', 'target': {'requested_unit': 'KiB', 'size': ${target_size}, 'size_unit': 'KiB', 'requested_size': ${requested_size}, 'block_unit': 'KiB', 'block_size': %s}} + kernel_params_add = "memhp_default_state=online_movable" + max_mem = 10485760 + aarch64: + max_mem = 20971520 + base_attrs = "'vcpu': 6, 'placement': 'static', 'memory_unit':'KiB','memory':3145728,'current_mem':3145728,'current_mem_unit':'KiB'" + numa_attrs = "'cpu': {'numa_cell': [{'id': '0', 'cpus': '0-1', 'memory': '1048576', 'unit': 'KiB'}, {'id': '1', 'cpus': '2-3', 'memory': '1048576', 'unit': 'KiB', 'memAccess':'shared','discard':'yes'},{'id':'2','cpus': '4-5','memory':'1048576','unit':'KiB', 'memAccess':'private','discard':'no'}]}" + max_attrs = "'max_mem_rt': ${max_mem}, 'max_mem_rt_slots': 16, 'max_mem_rt_unit': 'KiB'" + vm_attrs = {${base_attrs}, ${numa_attrs}, ${max_attrs}} + variants memory_backing: + - file: + source_type = 'file' + - anonymous: + source_type = 'anonymous' + - memfd: + source_type = 'memfd' + discard_error = 'yes' + discard_error_msg = "Property 'memory-backend-memfd.discard-data' not found" + variants: + - undefined: + memfd: + share_0 = 'true' + file: + discard_0 = 'False' + anonymous: + discard_error = 'yes' + discard_error_msg = "Property 'memory-backend-ram.discard-data' not found" + - shared_and_discard: + discard_attr = "'discard':'yes'" + access_attr = "'access_mode':'shared'" + share_0 = 'true' + file: + discard_0 = 'True' + anonymous: + discard_0 = 'True' + - private_and_no_discard: + access_attr = "'access_mode':'private'" + file: + discard_0 = 'False' + anonymous: + discard_0 = 'False' + source_attr = "'source_type':'${source_type}'" + expected_share = ['${share_0}', 'true', 'true', 'false', 'false', 'true'] + check_discard = '{"execute":"qom-get", "arguments":{"path":"/objects/%s", "property":"discard-data"}}' + expected_discard = ['${discard_0}', 'True', 'True', 'False', 'False', 'True'] + variants operation: + - cold_plug: + attach_option = "--config" + - hot_plug: + attach_option = " " diff --git a/libvirt/tests/cfg/memory/memory_devices/dimm_memory_with_auto_placement_numatune.cfg b/libvirt/tests/cfg/memory/memory_devices/dimm_memory_with_auto_placement_numatune.cfg new file mode 100644 index 00000000000..a974fd409b6 --- /dev/null +++ b/libvirt/tests/cfg/memory/memory_devices/dimm_memory_with_auto_placement_numatune.cfg @@ -0,0 +1,36 @@ +- memory.devices.dimm.auto_placement: + type = dimm_memory_with_auto_placement_numatune + start_vm = "no" + placement = "auto" + mem_model = "dimm" + set_size = 131072 + dimm_dict = {'mem_model': '${mem_model}', 'target': {'size': ${set_size}, 'node': 0, 'size_unit': 'KiB'}} + attach_dimm = {'mem_model': '${mem_model}', 'target': {'size': ${set_size}, 'node': 1, 'size_unit': 'KiB'}} + no s390-virtio + aarch64: + set_size = 1048576 + variants: + - strict: + tuning_mode = "strict" + mode_attrs = "'mode': '${tuning_mode}'," + - interleave: + tuning_mode = "interleave" + mode_attrs = "'mode': '${tuning_mode}'," + - preferred: + tuning_mode = "preferred" + mode_attrs = "'mode': '${tuning_mode}'," + - restrictive: + tuning_mode = "restrictive" + mode_attrs = "'mode': '${tuning_mode}'," + - undefined: + mode_attrs = "" + tuning_attrs = "'numa_memory': {${mode_attrs} 'placement': '${placement}'}" + variants: + - with_numa: + numa_mem = 1048576 + mem_value = 2490368 + current_mem = 2490368 + base_attrs = "'vcpu': 4, 'placement': '${placement}', 'memory_unit':'KiB','memory':${mem_value},'current_mem':${current_mem},'current_mem_unit':'KiB'" + numa_attrs = "'cpu': {'numa_cell': [{'id': '0', 'cpus': '0-1', 'memory': '${numa_mem}', 'unit': 'KiB'},{'id':'1','cpus': '2-3','memory':'${numa_mem}','unit':'KiB'}]}" + max_attrs = "'max_mem_rt': 15242880, 'max_mem_rt_slots': 16, 'max_mem_rt_unit': 'KiB'" + vm_attrs = {${base_attrs}, ${numa_attrs}, ${max_attrs}, ${tuning_attrs}} diff --git a/libvirt/tests/cfg/memory/memory_devices/dimm_memory_with_memory_alloccation_and_numa.cfg b/libvirt/tests/cfg/memory/memory_devices/dimm_memory_with_memory_alloccation_and_numa.cfg new file mode 100644 index 00000000000..c1c1f018add --- /dev/null +++ b/libvirt/tests/cfg/memory/memory_devices/dimm_memory_with_memory_alloccation_and_numa.cfg @@ -0,0 +1,67 @@ +- memory.devices.dimm.memory_allocation_and_numa: + type = dimm_memory_with_memory_alloccation_and_numa + no s390-virtio + start_vm = no + mem_model = "dimm" + mem_value = 2097152 + current_mem = 2097152 + numa_mem = 2097152 + mem_dict = "'memory_unit':'KiB','memory':${mem_value},'current_mem':${current_mem},'current_mem_unit':'KiB'" + target_size = 524288 + target_size_big = 3145728 + format_size = "params.get('target_size')" + basic_xpath = [{'element_attrs':[".//memory[@unit='KiB']"],'text':'${mem_value}'},{'element_attrs':[".//currentMemory[@unit='KiB']"],'text':'${current_mem}'}] + dimm_numa_xpath = [{'element_attrs':[".//cell[@memory='%s']"]},{'element_attrs':[".//memory/target/size[@unit='KiB']"],'text':'%s'},{'element_attrs':[".//memory/target/node"],'text':'0'}] + dimm_dict = "{'mem_model':'${mem_model}','target': {'size': %s, 'size_unit': 'KiB'}}" + dimm_node_dict = "{'mem_model':'${mem_model}','target': {'size': %s, 'size_unit': 'KiB','node':0}}" + variants memory_allocation: + - no_maxmemory: + max_dict = "" + define_error = "cannot use/hotplug a memory device when domain 'maxMemory' is not defined" + hotplug_error = "${define_error}" + hotplug_error_2 = "can't add memory backend as guest has no NUMA nodes configured" + - no_slot: + max_mem = 10485760 + max_dict = '"max_mem_rt": ${max_mem}, "max_mem_rt_unit": "KiB"' + define_error = "failed to find an empty memory slot" + redefine_error = "both maximum memory size and memory slot count must be specified" + coldplug_error = "no free memory device slot available" + - with_slot: + max_mem = 10485760 + max_mem_slots = 16 + max_dict = '"max_mem_rt": ${max_mem}, "max_mem_rt_slots": ${max_mem_slots}, "max_mem_rt_unit": "KiB"' + variants numa_setting: + - no_numa: + numa_dict = "" + with_slot: + define_error = "At least one numa node has to be configured when enabling memory hotplug" + big_size_msg = "Total size of memory devices exceeds the total memory size" + no_maxmemory: + coldplug_error = "can't add memory backend as guest has no NUMA nodes configured" + - with_numa: + numa_dict = "'vcpu': 6,'cpu':{'numa_cell': [{'id': '0', 'cpus': '0-3', 'memory': '${numa_mem}'}]}" + with_slot: + define_error = "target NUMA node needs to be specified for memory device" + no_maxmemory: + coldplug_error = "cannot use/hotplug a memory device when domain 'maxMemory' is not defined" + variants device_operation: + - init_define_with_dimm: + - init_define_with_big_dimm: + only with_slot..no_numa + format_size = "" + dimm_dict = "{'mem_model':'${mem_model}','target': {'size': ${target_size_big}, 'size_unit': 'KiB'}, %s}" + - hotplug_without_node: + no_slot: + hotplug_error = "target NUMA node needs to be specified for memory device" + with_slot: + hotplug_error = "target NUMA node needs to be specified for memory device" + - hotplug_with_node: + dimm_dict = ${dimm_node_dict} + no_slot: + hotplug_error = "count of memory devices requiring memory slots '1' exceeds slots count '0'" + - coldplug_without_node: + coldplug_error_2 = "cannot use/hotplug a memory device when domain 'maxMemory' is not defined" + with_slot: + coldplug_error_2 = "target NUMA node needs to be specified for memory device" + - coldplug_with_node: + dimm_dict = ${dimm_node_dict} diff --git a/libvirt/tests/cfg/memory/memory_devices/invalid_dimm_memory_device_config.cfg b/libvirt/tests/cfg/memory/memory_devices/invalid_dimm_memory_device_config.cfg new file mode 100644 index 00000000000..9e71974045b --- /dev/null +++ b/libvirt/tests/cfg/memory/memory_devices/invalid_dimm_memory_device_config.cfg @@ -0,0 +1,48 @@ +- memory.devices.invalid_dimm: + type = invalid_dimm_memory_device_config + node_mask = '1' + target_size = 524288 + guest_node = 0 + slot = 0 + addr_type = 'dimm' + addr_base = '0x100000000' + pagesize_cmd = "getconf PAGE_SIZE" + pagesize_unit = 'b' + mem_value = 2097152 + mem_unit = 'KiB' + current_mem = 2097152 + current_mem_unit = 'KiB' + numa_mem = 1048576 + max_mem_slots = 16 + max_mem = 10485760 + max_mem_unit = 'KiB' + max_dict = '"max_mem_rt": ${max_mem}, "max_mem_rt_slots": ${max_mem_slots}, "max_mem_rt_unit": "${max_mem_unit}"' + 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" + - 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_nodemask: + node_mask = '7' + start_vm_error = "NUMA node ${node_mask} is unavailable" + - invalid_pagesize: + invalid_pagesize = '9216' + pagesize_unit = 'b' + start_vm_error = "Unable to find any usable hugetlbfs mount for 9 KiB" + - 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}'" + addr_dict = "'address':{'attrs': {'type': '${addr_type}', 'base': '${addr_base}', 'slot': '${slot}'}}" + source_dict = "'source': {'nodemask': '${node_mask}','pagesize': %d, 'pagesize_unit':'${pagesize_unit}'}" + dimm_dict = {'mem_model':'dimm', ${source_dict}, ${addr_dict}, 'target': {'size':${target_size}, 'size_unit':'KiB','node':${guest_node}}} + variants basic_memory: + - with_numa: + no s390-virtio + 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/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 00000000000..f8fe0e34cf3 --- /dev/null +++ b/libvirt/tests/cfg/memory/memory_devices/invalid_nvdimm_memory_device_config.cfg @@ -0,0 +1,70 @@ +- 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", "backing store size 0x20000000 is too small for '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/cfg/memory/memory_devices/invalid_virtio_mem_config.cfg b/libvirt/tests/cfg/memory/memory_devices/invalid_virtio_mem_config.cfg new file mode 100644 index 00000000000..367ecedc4c2 --- /dev/null +++ b/libvirt/tests/cfg/memory/memory_devices/invalid_virtio_mem_config.cfg @@ -0,0 +1,71 @@ +- memory.devices.invalid_virtio_mem: + type = invalid_virtio_mem_config + start_vm = 'no' + mem_model = 'virtio-mem' + node_mask = '0' + target_size = 524288 + request_size = 262144 + block_size = 2048 + with_numa = yes + aarch64: + request_size = 524288 + block_size = 524288 + s390-virtio: + with_numa = no + request_size = 262144 + block_size = 1024 + guest_node = 0 + addr_base = '0x100000000' + pagesize_cmd = "getconf PAGE_SIZE" + pagesize_unit = 'b' + mem_value = 2097152 + mem_unit = 'KiB' + current_mem = 2097152 + current_mem_unit = 'KiB' + numa_mem = 1048576 + max_mem_slots = 16 + max_mem = 10485760 + max_mem_unit = 'KiB' + max_dict = '"max_mem_rt": ${max_mem}, "max_mem_rt_slots": ${max_mem_slots}, "max_mem_rt_unit": "${max_mem_unit}"' + 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"} + s390-virtio: + vm_attrs = {${max_dict}, 'memory_unit':'KiB','memory':${mem_value},'current_mem':${current_mem},'current_mem_unit':"KiB"} + required_kernel = [5.14.0,) + guest_required_kernel = [5.8.0,) + func_supported_since_libvirt_ver = (8, 0, 0) + func_supported_since_qemu_kvm_ver = (6, 2, 0) + variants invalid_setting: + - over_request_mem: + request_size = 1048576 + define_error = "requested size must be smaller than or equal to @size" + - max_addr: + addr_base = '0xffffffffffffffff' + define_error = "memory device address must be aligned to blocksize" + - unexisted_node: + no s390-virtio + guest_node = '6' + define_error = "can't add memory backend for guest node '${guest_node}' as the guest has only '2' NUMA nodes configured" + - unexisted_nodemask: + no s390-virtio + node_mask = '7' + start_vm_error = "NUMA node ${node_mask} is unavailable" + - invalid_pagesize: + invalid_pagesize = '9216' + pagesize_unit = 'b' + start_vm_error = "Unable to find any usable hugetlbfs mount for 9 KiB" + - small_block: + block_size = '1024' + s390-virtio: + block_size = '512' + define_error = "block size too small, must be at least" + - invalid_block: + block_size = "3072" + define_error = "block size must be a power of two" + addr_dict = "'address':{'attrs': {'base': '${addr_base}','slot': '0'}}" + source_dict = "'source': {'nodemask': '${node_mask}','pagesize': %d, 'pagesize_unit':'${pagesize_unit}'}" + mem_dict = {'mem_model':'${mem_model}', ${source_dict}, 'target': {'size':${target_size}, 'size_unit':'KiB', ${addr_dict}, 'node':${guest_node},'requested_size': ${request_size}, 'block_size': ${block_size}}} + s390-virtio: + source_dict = "'source': {'pagesize': %d, 'pagesize_unit':'${pagesize_unit}'}" + mem_dict = {'mem_model':'${mem_model}', ${source_dict}, 'target': {'size':${target_size}, 'size_unit':'KiB', ${addr_dict}, 'requested_size': ${request_size}, 'block_size': ${block_size}}} + diff --git a/libvirt/tests/cfg/memory/memory_devices/lifecycle_for_file_backed_nvdimm_memory.cfg b/libvirt/tests/cfg/memory/memory_devices/lifecycle_for_file_backed_nvdimm_memory.cfg new file mode 100644 index 00000000000..7ba8e42fb99 --- /dev/null +++ b/libvirt/tests/cfg/memory/memory_devices/lifecycle_for_file_backed_nvdimm_memory.cfg @@ -0,0 +1,70 @@ +- memory.devices.file_nvdimm.lifecycle: + no s390-virtio + type = lifecycle_for_file_backed_nvdimm_memory + start_vm = no + target_size = 524288 + nvdimm_file_size = "512M" + source_path = "/tmp/nvdimm1" + source_path_attach = "/tmp/nvdimm2" + addr_slot = "1" + addr_slot_attach = "2" + addr_base = "0x200000000" + addr_base_attach = "0x240000000" + check_alignment = '{"execute":"qom-get", "arguments":{"path": "/objects/mem%s", "property":"align"}}' + nvdimm_devices = "/dev/pmem0 /dev/pmem1" + check_nvdimm_devices = "ls ${nvdimm_devices}" + file_content = "test_text" + target_node = 0 + target_node_attach = 1 + nvdimm_path = "/mnt/nvdimm1" + nvdimm_path_attach = "/mnt/nvdimm2" + mount_file_1 = "${nvdimm_path}/file1" + mount_file_2 = "${nvdimm_path_attach}/file2" + paths = ["${nvdimm_path}", "${nvdimm_path_attach}"] + nodes = ["${target_node}", "${target_node_attach}"] + save_file = "/tmp/guest.save" + variants source_config: + - access_shared: + access = "shared" + access_attrs = "" + expected_align = "0" + content_existed = True + - access_private_alignsize: + alignsize = 2048 + access = "private" + access_attrs = "'alignsize':${alignsize},'alignsize_unit': 'KiB'," + expected_align = "2097152" + content_existed = "" + variants target_config: + - target_label: + label_size = 128 + label_attrs = "'label':{'size_unit':'KiB','size':${label_size}}," + readonly_attrs = "" + - target_readonly: + label_attrs = "" + readonly_attrs = "'readonly':True" + error_msg = "Operation not permitted" + variants address_config: + - addr_undefined: + addr_attrs = "" + addr_attach_attrs = "" + alias_name = ["nvdimm0", "nvdimm1"] + - addr_slot_base: + addr_attrs = "'address':{'attrs': {'base': '${addr_base}','slot': '${addr_slot}'}}" + addr_attach_attrs = "'address':{'attrs': {'base': '${addr_base_attach}','slot': '${addr_slot_attach}'}}" + alias_name = ["nvdimm${addr_slot}", "nvdimm${addr_slot_attach}"] + source_attrs = "'source': {${access_attrs} 'path': '${source_path}'}" + target_attrs = "'target': {'size': ${target_size},'size_unit': 'KiB','node':${target_node_attach}, ${label_attrs}${readonly_attrs}}" + nvdimm_dict = {'mem_model':'nvdimm', 'mem_access':'${access}',${source_attrs},${target_attrs},${addr_attrs}} + source_attach_attrs = "'source': {${access_attrs} 'path': '${source_path_attach}'}" + target_attach_attrs = "'target': {'size': ${target_size},'size_unit': 'KiB','node':${target_node}, ${label_attrs}${readonly_attrs}}" + nvdimm_attach_dict = {'mem_model':'nvdimm', 'mem_access':'${access}',${source_attach_attrs},${target_attach_attrs},${addr_attach_attrs}} + variants: + - with_numa: + numa_mem = 1048576 + mem_value = 2097152 + current_mem = 2097152 + base_attrs = "'vcpu': 4, 'memory_unit':'KiB','memory':${mem_value},'current_mem':${current_mem},'current_mem_unit':'KiB'" + numa_attrs = "'cpu': {'numa_cell': [{'id': '0', 'cpus': '0-1', 'memory': '${numa_mem}', 'unit': 'KiB'},{'id':'1','cpus': '2-3','memory':'${numa_mem}','unit':'KiB'}]}" + max_attrs = "'max_mem_rt': 15242880, 'max_mem_rt_slots': 16, 'max_mem_rt_unit': 'KiB'" + vm_attrs = {${base_attrs}, ${numa_attrs}, ${max_attrs}} diff --git a/libvirt/tests/cfg/memory/memory_devices/lifecycle_of_mixed_memory_devices.cfg b/libvirt/tests/cfg/memory/memory_devices/lifecycle_of_mixed_memory_devices.cfg index a259785a326..8485223986f 100644 --- a/libvirt/tests/cfg/memory/memory_devices/lifecycle_of_mixed_memory_devices.cfg +++ b/libvirt/tests/cfg/memory/memory_devices/lifecycle_of_mixed_memory_devices.cfg @@ -8,26 +8,26 @@ nvdimm_path_1 = "/tmp/nvdimm1" nvdimm_path_2 = "/tmp/nvdimm2" save_file = "/tmp/guest.save" - nr_hugepages = 256 + total_hugepage_size = 1048576 kernel_hp_file = "/proc/sys/vm/nr_hugepages" truncate_cmd = "truncate -s 512M ${nvdimm_path_1} && truncate -s 512M ${nvdimm_path_2}" kernel_params_remove = "memhp_default_state" kernel_params_add = "memhp_default_state=online_movable" page_size = 2048 - dimm_1 = [262144, 262144, 1, "", 1, "dimm_dict_1"] + dimm_1 = [524288, 524288, 1, "", 1, "dimm_dict_1"] nvdimm_1 = [524288, 0, 2, "", "", "nvdimm_dict_1"] virtio_mem_1 = [2097152, 1048576, 3, "", "", "virtio_mem_dict_1"] - dimm_2 = [262144, 262144,"", 1, "", "dimm_dict_2"] + dimm_2 = [524288, 524288,"", 1, "", "dimm_dict_2"] nvdimm_2 = [524288, 0, "", 2, "", "nvdimm_dict_2"] - virtio_mem_2 = [262144, 262144, "", 3, "","virtio_mem_dict_2"] + virtio_mem_2 = [524288, 524288, "", 3, "","virtio_mem_dict_2"] set_items = ["memory_affected", "current_mem_affected","init_seq","hotplug_seq","hotunplug_seq", "dev_dict"] set_value = [${dimm_1}, ${nvdimm_1}, ${virtio_mem_1}, ${dimm_2}, ${nvdimm_2}, ${virtio_mem_2}] - dimm_target_dize = 262144 - nvdimm_target_dize = 524288 + dimm_target_size = 524288 + nvdimm_target_size = 524288 virtio_mem_target_size = 2097152 - dimm_dict_1 = {'mem_model': 'dimm', 'mem_access':'private','mem_discard':'no','source': {"pagesize":${page_size}, "pagesize_unit":"KiB"},'target': {'size': ${dimm_target_dize}, 'size_unit': 'KiB','node':0}} - nvdimm_dict_1 = {'mem_model': 'nvdimm', 'source': {"path":"${nvdimm_path_1}"}, 'target': {'size': ${nvdimm_target_dize}, 'size_unit': 'KiB','node':1 }} - virtio_mem_dict_1 = {'mem_model': 'virtio-mem', 'target': {'size': ${virtio_mem_target_size}, 'size_unit': 'KiB','node':0, 'block_unit':'KiB','block_size':2048,'requested_size':1048576, 'requested_unit':'KiB'}} + dimm_dict_1 = {'mem_model': 'dimm', 'mem_access':'private','mem_discard':'no','source': {"pagesize":${page_size}, "pagesize_unit":"KiB"},'target': {'size': ${dimm_target_size}, 'size_unit': 'KiB','node':0}} + nvdimm_dict_1 = {'mem_model': 'nvdimm', 'source': {"path":"${nvdimm_path_1}"}, 'target': {'size': ${nvdimm_target_size}, 'size_unit': 'KiB','node':1 }} + virtio_mem_dict_1 = {'mem_model': 'virtio-mem', 'target': {'size': ${virtio_mem_target_size}, 'size_unit': 'KiB','node':0, 'block_unit':'KiB','block_size':${page_size},'requested_size':1048576, 'requested_unit':'KiB'}} variants: - mutiple_mem: no s390-virtio @@ -35,12 +35,13 @@ guest_required_kernel = [5.8.0,) func_supported_since_libvirt_ver = (8, 0, 0) func_supported_since_qemu_kvm_ver = (6, 2, 0) - dimm_dict_2 = {'mem_model': 'dimm', 'mem_access':'shared','mem_discard':'yes','target': {'size': ${dimm_target_dize}, 'size_unit': 'KiB','node':1}} - nvdimm_dict_2 = {'mem_model': 'nvdimm', 'source': {"path":"${nvdimm_path_2}"}, 'target': {'size': ${nvdimm_target_dize}, 'size_unit': 'KiB','node':1, 'label':{'size':128, 'size_unit':'KiB'} }} - virtio_mem_dict_2 = {'mem_model': 'virtio-mem','source': {"pagesize":${page_size}, "pagesize_unit":"KiB"}, 'target': {'size': 262144, 'size_unit': 'KiB','node':0, 'block_unit':'KiB','block_size':2048,'requested_size':262144, 'requested_unit':'KiB'}} - xpath_basic = {'element_attrs': [".//memory[@unit='${default_unit}']"],'text': '%s'},{'element_attrs': [".//currentMemory[@unit='${default_unit}']"],'text': '%s'},{'element_attrs': [".//alias[@name='dimm0']"]},{'element_attrs': [".//address[@slot='0']",".//address[@type='dimm']"]},{'element_attrs': [".//alias[@name='nvdimm1']"]},{'element_attrs': [".//address[@slot='1']",".//address[@type='dimm']"]},{'element_attrs': [".//alias[@name='virtiomem0']"]} + dimm_dict_2 = {'mem_model': 'dimm', 'mem_access':'shared','mem_discard':'yes','target': {'size': ${dimm_target_size}, 'size_unit': 'KiB','node':1}} + nvdimm_dict_2 = {'mem_model': 'nvdimm', 'source': {"path":"${nvdimm_path_2}"}, 'target': {'size': ${nvdimm_target_size}, 'size_unit': 'KiB','node':1, 'label':{'size':128, 'size_unit':'KiB'} }} + virtio_mem_dict_2 = {'mem_model': 'virtio-mem','source': {"pagesize":${page_size}, "pagesize_unit":"KiB"}, 'target': {'size': 524288, 'size_unit': 'KiB','node':0, 'block_unit':'KiB','block_size':${page_size},'requested_size':524288, 'requested_unit':'KiB'}} + xpath_basic = {'element_attrs': [".//memory[@unit='${default_unit}']"],'text':'%s'},{'element_attrs': [".//currentMemory[@unit='${default_unit}']"],'text': '%s'},{'element_attrs': [".//alias[@name='dimm0']"]},{'element_attrs': [".//address[@slot='0']",".//address[@type='dimm']"]},{'element_attrs': [".//alias[@name='nvdimm1']"]},{'element_attrs': [".//address[@slot='1']",".//address[@type='dimm']"]},{'element_attrs': [".//alias[@name='virtiomem0']"]} xpath_after_start = [${xpath_basic}] xpath_after_attached = [${xpath_basic},{'element_attrs': [".//alias[@name='dimm2']"]},{'element_attrs': [".//address[@slot='2']",".//address[@type='dimm']"]},{'element_attrs': [".//alias[@name='nvdimm3']"]}, {'element_attrs': [".//address[@slot='3']",".//address[@type='dimm']"]},{'element_attrs': [".//alias[@name='virtiomem1']"]}] xpath_after_detached = [${xpath_basic}, {'element_attrs': [".//alias[@name='dimm2']"]},{'element_attrs': [".//address[@slot='2']",".//address[@type='dimm']"]},{'element_attrs': [".//alias[@name='nvdimm3']"]},{'element_attrs': [".//address[@slot='3']",".//address[@type='dimm']"]},{'element_attrs': [".//alias[@name='virtiomem1']"]}] del_head = 2 del_tail = 4 + diff --git a/libvirt/tests/cfg/memory/memory_devices/nvdimm_memory_turn_to_dram.cfg b/libvirt/tests/cfg/memory/memory_devices/nvdimm_memory_turn_to_dram.cfg new file mode 100644 index 00000000000..3159bc0dff4 --- /dev/null +++ b/libvirt/tests/cfg/memory/memory_devices/nvdimm_memory_turn_to_dram.cfg @@ -0,0 +1,23 @@ +- memory.devices.nvdimm.turn_to_dram: + no s390-virtio + type = nvdimm_memory_turn_to_dram + start_vm = no + mem_model = 'nvdimm' + numa_dict = "'vcpu': 2,'cpu':{'check': 'partial', 'fallback': 'allow','numa_cell': [{'id': '0', 'cpus': '0-1', 'memory': '524288'}],'topology':{'sockets': '2', 'cores': '1', 'threads': '1'}}" + vm_attrs = {${numa_dict},"max_mem_rt": 15242880, "max_mem_rt_slots": 16,'memory':4194304,'current_mem':4194304,} + nvdimm_path = "/tmp/nvdimm" + nvdimm_dict = {'mem_model':'${mem_model}',"mem_access":"shared",'target': {'size':1048576, 'size_unit':'KiB', 'node':0}, 'source':{'path': "${nvdimm_path}"},'address':{'attrs': {'type':'dimm','slot':'1'}}} + truncate_cmd = "truncate -s 1024M ${nvdimm_path}" + expected_qemu_cmdline = ["nvdimm=on",'"mem-path":"/tmp/nvdimm"','"share":true'] + repeat_times = 20 + devdax_mode = "devdax" + dram_mode = "system-ram" + create_namespace = "ndctl create-namespace --mode devdax -f -e namespace0.0" + check_dev = "ls -al /dev/dax0.0" + list_nvdimm_namespace = 'ndctl list -N' + persistence_config = 'daxctl migrate-device-model' + add_kmem = "modprobe kmem" + update_to_dram = 'daxctl reconfigure-device --mode=system-ram --region=0 all' + check_list = ['CONFIG_LIBNVDIMM=m', 'CONFIG_BLK_DEV_PMEM=m', 'CONFIG_ACPI_NFIT=m'] + + diff --git a/libvirt/tests/cfg/memory/memory_devices/virtio_mem_access_and_discard.cfg b/libvirt/tests/cfg/memory/memory_devices/virtio_mem_access_and_discard.cfg new file mode 100644 index 00000000000..e1c05a622e3 --- /dev/null +++ b/libvirt/tests/cfg/memory/memory_devices/virtio_mem_access_and_discard.cfg @@ -0,0 +1,79 @@ +- memory.devices.virtio_mem.access_and_discard: + type = virtio_mem_access_and_discard + start_vm = no + mem_model = "virtio-mem" + share_0 = 'false' + discard_0 = 'False' + check_path = "ls -l /var/lib/libvirt/qemu/ram/%s" + target_size = 131072 + requested_size = 131072 + block_size = 2048 + mem_value = 3145728 + current_mem = 3145728 + max_mem = 10485760 + aarch64: + max_mem = 20971520 + target_size = 1048576 + requested_size = 524288 + block_size = 524288 + mem_basic = {'mem_model': '${mem_model}', 'target': {'requested_unit': 'KiB', 'size': ${target_size}, 'size_unit': 'KiB', 'requested_size': ${requested_size}, 'block_unit': 'KiB', 'block_size': ${block_size}}} + base_attrs = "'vcpu': 6, 'placement': 'static', 'memory_unit':'KiB','memory':${mem_value},'current_mem':${current_mem},'current_mem_unit':'KiB'" + max_attrs = "'max_mem_rt': ${max_mem}, 'max_mem_rt_slots': 16, 'max_mem_rt_unit': 'KiB'" + required_kernel = [5.14.0,) + guest_required_kernel = [5.8.0,) + func_supported_since_libvirt_ver = (8, 0, 0) + func_supported_since_qemu_kvm_ver = (6, 2, 0) + variants: + - with_numa: + no s390-virtio + numa_mem = 1048576 + mem_access_1 = "shared" + discard_1 = "yes" + mem_access_2 = "private" + discard_2 = "no" + numa_attrs = "'cpu': {'numa_cell': [{'id': '0', 'cpus': '0-1', 'memory': '${numa_mem}', 'unit': 'KiB'}, {'id': '1', 'cpus': '2-3', 'memory': '${numa_mem}', 'unit': 'KiB', 'memAccess':'${mem_access_1}','discard':'${discard_1}'},{'id':'2','cpus': '4-5','memory':'${numa_mem}','unit':'KiB', 'memAccess':'${mem_access_2}','discard':'${discard_2}'}]}" + vm_attrs = {${base_attrs}, ${numa_attrs}, ${max_attrs}} + mem_conf_list = [(None, None, 0), ('shared', 'yes', 0), (None, None, 1), ('private', 'no', 1), (None, None, 2), ('shared', 'yes', 2)] + - without_numa: + only s390-virtio + vm_attrs = {${base_attrs}, ${max_attrs}} + mem_conf_list = [(None, None, None), ('shared', 'yes', None)] + variants memory_backing: + - file: + source_type = 'file' + source_attr = "'source_type':'${source_type}'" + - anonymous: + source_type = 'anonymous' + source_attr = "'source_type':'${source_type}'" + - memfd: + source_type = 'memfd' + source_attr = "'source_type':'${source_type}'" + discard_error = 'yes' + discard_error_msg = "Property 'memory-backend-memfd.discard-data' not found" + variants: + - undefined: + memfd: + share_0 = 'true' + file: + discard_0 = 'False' + anonymous: + discard_error = 'yes' + discard_error_msg = "Property 'memory-backend-ram.discard-data' not found" + - shared_and_discard: + discard_attr = "'discard':'yes'" + access_attr = "'access_mode':'shared'" + share_0 = 'true' + file: + discard_0 = 'True' + anonymous: + discard_0 = 'True' + - private_and_no_discard: + access_attr = "'access_mode':'private'" + file: + discard_0 = 'False' + anonymous: + discard_0 = 'False' + expected_share = ['${share_0}', 'true', 'true', 'false', 'false', 'true'] + check_discard = '{"execute":"qom-get", "arguments":{"path":"/objects/%s", "property":"discard-data"}}' + expected_discard = ['${discard_0}', 'True', 'True', 'False', 'False', 'True'] + diff --git a/libvirt/tests/cfg/memory/memory_devices/virtio_mem_auto_placement.cfg b/libvirt/tests/cfg/memory/memory_devices/virtio_mem_auto_placement.cfg new file mode 100644 index 00000000000..d1fc1cd9110 --- /dev/null +++ b/libvirt/tests/cfg/memory/memory_devices/virtio_mem_auto_placement.cfg @@ -0,0 +1,45 @@ +- memory.devices.virtio_mem.auto_placement: + type = virtio_mem_auto_placement + no s390-virtio + start_vm = "no" + placement = "auto" + mem_model = "virtio-mem" + block_size = 2048 + set_size = 131072 + requested_size = 131072 + aarch64: + block_size = 524288 + set_size = 1048576 + requested_size = 524288 + virtio_mem_dict = {'mem_model': '${mem_model}', 'target': {'requested_unit': 'KiB', 'size': ${requested_size}, 'node': 0, 'size_unit': 'KiB', 'requested_size': ${requested_size}, 'block_unit': 'KiB', 'block_size': ${block_size}}} + required_kernel = [5.14.0,) + guest_required_kernel = [5.8.0,) + func_supported_since_libvirt_ver = (8, 0, 0) + func_supported_since_qemu_kvm_ver = (6, 2, 0) + variants: + - strict: + tuning_mode = "strict" + mode_attrs = "'mode': '${tuning_mode}'," + - interleave: + tuning_mode = "interleave" + mode_attrs = "'mode': '${tuning_mode}'," + - preferred: + tuning_mode = "preferred" + mode_attrs = "'mode': '${tuning_mode}'," + - restrictive: + tuning_mode = "restrictive" + mode_attrs = "'mode': '${tuning_mode}'," + - undefined: + mode_attrs = "" + tuning_attrs = "'numa_memory': {${mode_attrs} 'placement': '${placement}'}" + variants: + - with_numa: + numa_mem = 1048576 + mem_value = 2097152 + current_mem = 2097152 + max_mem = 15242880 + max_mem_slots = 16 + base_attrs = "'vcpu': 4, 'placement': '${placement}', 'memory_unit':'KiB','memory':${mem_value},'current_mem':${current_mem},'current_mem_unit':'KiB'" + numa_attrs = "'cpu': {'numa_cell': [{'id': '0', 'cpus': '0-1', 'memory': '${numa_mem}', 'unit': 'KiB'},{'id':'1','cpus': '2-3','memory':'${numa_mem}','unit':'KiB'}]}" + max_attrs = "'max_mem_rt': ${max_mem}, 'max_mem_rt_slots': ${max_mem_slots}, 'max_mem_rt_unit': 'KiB'" + vm_attrs = {${base_attrs}, ${numa_attrs}, ${max_attrs}, ${tuning_attrs}} diff --git a/libvirt/tests/cfg/memory/memory_devices/virtio_mem_coldplug_and_unplug.cfg b/libvirt/tests/cfg/memory/memory_devices/virtio_mem_coldplug_and_unplug.cfg new file mode 100644 index 00000000000..f96558a44c0 --- /dev/null +++ b/libvirt/tests/cfg/memory/memory_devices/virtio_mem_coldplug_and_unplug.cfg @@ -0,0 +1,107 @@ +- memory.devices.virtio_mem.coldplug_and_unplug: + type = virtio_mem_coldplug_and_unplug + start_vm = "no" + mem_model = "virtio-mem" + target_size = 524288 + request_size = 524288 + size_unit = 'KiB' + request_unit = 'KiB' + block_unit = 'KiB' + plug_size_unit = 'KiB' + plug_request_unit = 'KiB' + plug_block_unit = 'KiB' + mem_value = 2097152 + current_mem = 2097152 + numa_mem = 1048576 + max_mem = 4194304 + max_mem_slots = 16 + max_dict = '"max_mem_rt": ${max_mem}, "max_mem_rt_slots": ${max_mem_slots}, "max_mem_rt_unit": "KiB"' + numa_dict = "'vcpu': 4,'cpu':{'numa_cell': [{'id': '0', 'cpus': '0-1', 'memory': '${numa_mem}'}, {'id': '1', 'cpus': '2-3', 'memory': '${numa_mem}'}]}" + vm_attrs = {${numa_dict},${max_dict},'memory_unit':'KiB','memory':${mem_value},'current_mem':${current_mem},'current_mem_unit':'KiB'} + numa_xpath = [{'element_attrs':[".//cell[@unit='KiB']",".//cell[@id='0']",".//cell[@memory='${numa_mem}']"]}] + s390-virtio: + vm_attrs = {${max_dict},'memory_unit':'KiB','memory':${mem_value},'current_mem':${current_mem},'current_mem_unit':'KiB'} + numa_xpath = [] + base = '0x100000000' + plug_option = " --config" + required_kernel = [5.14.0,) + guest_required_kernel = [5.8.0,) + func_supported_since_libvirt_ver = (8, 0, 0) + func_supported_since_qemu_kvm_ver = (6, 2, 0) + variants case: + - with_addr: + plug_target_size = 1048576 + plug_request_size = 1048576 + addr_dict = "'address':{'attrs': {'base': '${base}'}}" + virtio_dict = {'mem_model':'${mem_model}','target': {${addr_dict},'size':${target_size}, 'size_unit':'${size_unit}', 'node':0,'requested_size': ${request_size},'requested_unit':'${request_unit}', 'block_size': %s, 'block_unit':'${block_unit}'}} + unplug_dict = ${virtio_dict} + plug_dict = {'mem_model':'${mem_model}','target': {${addr_dict},'size':${plug_target_size},'requested_size': ${plug_request_size}, 'block_size': %s, 'size_unit':'${plug_size_unit}','requested_unit':'${plug_request_unit}','block_unit':'${plug_block_unit}','node':0}} + virtio_xpath = [{'element_attrs':["./devices/memory/target/size[@unit='${size_unit}']"],'text':'${target_size}'},{'element_attrs':[".//memory/target/block[@unit='${block_unit}']"],'text':'%s'}, {'element_attrs':[".//memory/target/requested[@unit='${request_unit}']"],'text':'${request_size}'},{'element_attrs':[".//memory/target/address[@base='${base}']"]}] + unplug_xpath = ${virtio_xpath} + plug_xpath = [{'element_attrs':[".//memory/target/size[@unit='${plug_size_unit}']"],'text':'${plug_target_size}'},{'element_attrs':[".//memory/target/block[@unit='${block_unit}']"],'text':'%s'}, {'element_attrs':[".//memory/target/requested[@unit='${plug_request_unit}']"],'text':'${plug_request_size}'},{'element_attrs':[".//memory/target/address[@base='${base}']"]}] + s390-virtio: + virtio_dict = {'mem_model':'${mem_model}','target': {${addr_dict},'size':${target_size}, 'size_unit':'${size_unit}', 'requested_size': ${request_size},'requested_unit':'${request_unit}', 'block_size': %s, 'block_unit':'${block_unit}'}} + unplug_dict = ${virtio_dict} + plug_dict = {'mem_model':'${mem_model}','target': {${addr_dict},'size':${plug_target_size},'requested_size': ${plug_request_size}, 'block_size': %s, 'size_unit':'${plug_size_unit}','requested_unit':'${plug_request_unit}','block_unit':'${plug_block_unit}'}} + - source_and_mib: + target_size = 512 + request_size = 512 + size_unit = 'MiB' + request_unit = 'MiB' + plug_target_size = 1024 + plug_request_size = 1024 + plug_size_unit = 'MiB' + plug_request_unit = 'MiB' + plug_block_unit = 'KiB' + nodemask = '0' + source_dict = "'source': {'nodemask': '0','pagesize': 4, 'pagesize_unit':'KiB'}" + virtio_dict = {'mem_model':'${mem_model}',${source_dict}, 'target': {'size':${target_size}, 'size_unit':'${size_unit}','requested_unit':'${request_unit}','block_unit':'${block_unit}','node':1,'requested_size': ${request_size}, 'block_size': %s}} + unplug_dict = ${virtio_dict} + plug_dict = {'mem_model':'${mem_model}',${source_dict},'target': {'size':${plug_target_size},'requested_size': ${plug_request_size}, 'block_size': %s, 'size_unit':'${plug_size_unit}','requested_unit':'${plug_request_unit}','block_unit':'${plug_block_unit}','node':1}} + virtio_xpath = [{'element_attrs':[".//memory/target/size[@unit='KiB']"],'text':'%s'},{'element_attrs':[".//memory/target/block[@unit='KiB']"],'text':'%s'}, {'element_attrs':[".//memory/target/requested[@unit='KiB']"],'text':'%s'}, {'element_attrs':[".//memory/source/pagesize"]}, {'element_attrs':[".//memory/source/nodemask"],'text':'${nodemask}'}] + unplug_xpath = ${virtio_xpath} + s390-virtio: + source_dict = "'source': {'pagesize': 4, 'pagesize_unit':'KiB'}" + virtio_dict = {'mem_model':'${mem_model}',${source_dict}, 'target': {'size':${target_size}, 'size_unit':'${size_unit}','requested_unit':'${request_unit}','block_unit':'${block_unit}','requested_size': ${request_size}, 'block_size': %s}} + unplug_dict = ${virtio_dict} + plug_dict = {'mem_model':'${mem_model}',${source_dict},'target': {'size':${plug_target_size},'requested_size': ${plug_request_size}, 'block_size': %s, 'size_unit':'${plug_size_unit}','requested_unit':'${plug_request_unit}','block_unit':'${plug_block_unit}'}} + virtio_xpath = [{'element_attrs':[".//memory/target/size[@unit='KiB']"],'text':'%s'},{'element_attrs':[".//memory/target/block[@unit='KiB']"],'text':'%s'}, {'element_attrs':[".//memory/target/requested[@unit='KiB']"],'text':'%s'}, {'element_attrs':[".//memory/source/pagesize"]}] + unplug_xpath = ${virtio_xpath} + plug_xpath = [{'element_attrs':[".//memory/target/size[@unit='KiB']"],'text':'%s'},{'element_attrs':[".//memory/target/block[@unit='KiB']"],'text':'%s'}, {'element_attrs':[".//memory/target/requested[@unit='KiB']"],'text':'%s'}] + - unplug_none_dev: + addr_dict = "'address':{'attrs': {'base': '${base}'}}" + virtio_dict = {'mem_model':'${mem_model}', 'target': {'size':${target_size}, 'size_unit':'KiB', ${addr_dict}, 'node':0,'requested_size': ${request_size}, 'block_size': %s}} + unplug_request_size = 0 + unplug_dict = {'mem_model':'${mem_model}', 'target': {'requested_size': ${unplug_request_size}, 'size':${target_size}, 'size_unit':'KiB', ${addr_dict}, 'node':0,'block_size': %s}} + s390-virtio: + virtio_dict = {'mem_model':'${mem_model}', 'target': {'size':${target_size}, 'size_unit':'KiB', ${addr_dict}, 'requested_size': ${request_size}, 'block_size': %s}} + unplug_dict = {'mem_model':'${mem_model}', 'target': {'requested_size': ${unplug_request_size}, 'size':${target_size}, 'size_unit':'KiB', ${addr_dict}, 'block_size': %s}} + unplug_error = "matching memory device was not found" + virtio_xpath = [{'element_attrs':[".//memory/target/size[@unit='${size_unit}']"],'text':'${target_size}'},{'element_attrs':[".//memory/target/block[@unit='${block_unit}']"],'text':'%s'}, {'element_attrs':[".//memory/target/requested[@unit='${request_unit}']"],'text':'${request_size}'},{'element_attrs':[".//memory/target/address[@base='${base}']"]}] + unplug_xpath = [{'element_attrs':[".//memory/target/size[@unit='${size_unit}']"],'text':'${target_size}'},{'element_attrs':[".//memory/target/block[@unit='${plug_block_unit}']"],'text':'%s'}, {'element_attrs':[".//memory/target/requested[@unit='${plug_request_unit}']"],'text':'${unplug_request_size}'},{'element_attrs':[".//memory/target/address[@base='${base}']"]}] + - plug_exceeded_max_mem: + target_size = 1572864 + request_size = 1572864 + plug_target_size = 1024 + plug_request_size = 1024 + virtio_dict = {'mem_model':'${mem_model}', 'target': {'size':${target_size}, 'size_unit':'KiB','node':1,'requested_size': ${request_size}, 'block_size': %s}} + plug_size_unit = 'MiB' + plug_request_unit = 'MiB' + plug_dict = {'mem_model':'${mem_model}','target': {'size':${plug_target_size},'requested_size': ${plug_request_size}, 'block_size': %s, 'size_unit':'${plug_size_unit}','requested_unit':'${plug_request_unit}','block_unit':'${plug_block_unit}','node':1}} + virtio_xpath = [{'element_attrs':[".//memory/target/size[@unit='${size_unit}']"],'text':'${target_size}'},{'element_attrs':[".//memory/target/block[@unit='${block_unit}']"],'text':'%s'}, {'element_attrs':[".//memory/target/requested[@unit='${request_unit}']"],'text':'${request_size}'}] + plug_xpath = [{'element_attrs':[".//memory/target/size[@unit='${size_unit}']"],'text':'%s'},{'element_attrs':[".//memory/target/block[@unit='${block_unit}']"],'text':'%s'}, {'element_attrs':[".//memory/target/requested[@unit='${request_unit}']"],'text':'%s'}] + plug_error = "Attaching memory device with size '\S+' would exceed domain's maxMemory config size '${max_mem}'" + s390-virtio: + virtio_dict = {'mem_model':'${mem_model}', 'target': {'size':${target_size}, 'size_unit':'KiB','requested_size': ${request_size}, 'block_size': %s}} + plug_dict = {'mem_model':'${mem_model}','target': {'size':${plug_target_size},'requested_size': ${plug_request_size}, 'block_size': %s, 'size_unit':'${plug_size_unit}','requested_unit':'${plug_request_unit}','block_unit':'${plug_block_unit}'}} + - duplicate_addr: + addr_dict = "'address':{'attrs': {'base': '0x100000000'}}" + virtio_dict = {'mem_model':'${mem_model}', 'target': {${addr_dict},'size':${target_size}, 'size_unit':'KiB', ${addr_dict}, 'node':0,'requested_size': ${request_size}, 'block_size': %s}} + plug_dict = ${virtio_dict} + plug_error = "unsupported configuration: memory device address [0x100000000:0x108000000] overlaps with other memory device (0x100000000)" + virtio_xpath = [{'element_attrs':[".//memory/target/size[@unit='${size_unit}']"],'text':'${target_size}'},{'element_attrs':[".//memory/target/block[@unit='${block_unit}']"],'text':'%s'}, {'element_attrs':[".//memory/target/requested[@unit='${request_unit}']"],'text':'${request_size}'},{'element_attrs':[".//memory/target/address[@base='${base}']"]}] + plug_xpath = ${virtio_xpath} + s390-virtio: + virtio_dict = {'mem_model':'${mem_model}', 'target': {${addr_dict},'size':${target_size}, 'size_unit':'KiB', ${addr_dict}, 'requested_size': ${request_size}, 'block_size': %s}} + plug_dict = ${virtio_dict} + diff --git a/libvirt/tests/cfg/memory/memory_devices/virtio_mem_device_lifecycle.cfg b/libvirt/tests/cfg/memory/memory_devices/virtio_mem_device_lifecycle.cfg new file mode 100644 index 00000000000..7332f6d661e --- /dev/null +++ b/libvirt/tests/cfg/memory/memory_devices/virtio_mem_device_lifecycle.cfg @@ -0,0 +1,84 @@ +- memory.devices.virtio_mem.lifecycle: + type = virtio_mem_device_lifecycle + start_vm = no + state_file = "/tmp/%s.save" + numa_mem_val = 1048576 + memory_val = 2097152 + current_mem_val = 2097152 + aarch64: + numa_mem_val = 4194304 + memory_val = 8388608 + current_mem_val = 8388608 + vm_attrs = {'max_mem_rt': 15428800, 'max_mem_rt_unit': 'KiB','memory_unit':"KiB", 'memory':${memory_val}, 'current_mem':${current_mem_val}, 'current_mem_unit':'KiB', 'vcpu': 4,'cpu': {'numa_cell': [{'id': '0', 'cpus': '0-1', 'memory': '${numa_mem_val}', 'unit': 'KiB'},{'id':'1','cpus': '2-3','memory':'${numa_mem_val}','unit':'KiB'}]}} + init_alias_name = virtiomem0 + plug_alias_name = virtiomem1 + required_kernel = [5.14.0,) + guest_required_kernel = [5.8.0,) + func_supported_since_libvirt_ver = (8, 0, 0) + func_supported_since_qemu_kvm_ver = (6, 2, 0) + s390-virtio: + vm_attrs = {'max_mem_rt': 15428800, 'max_mem_rt_unit': 'KiB','memory_unit':"KiB", 'memory':${memory_val}, 'current_mem':${current_mem_val}, 'current_mem_unit':'KiB', 'vcpu': 4} + variants kernel_pagesize: + - 4k: + page_size = 4 + default_hp_size = 2048 + s390-virtio: + default_hp_size = 1024 + - 64k: + only aarch64 + page_size = 64 + default_hp_size = 524288 + variants memory_source: + - no_source: + source_dict = {} + source_xpath = [] + - nodemask: + no s390-virtio + nodeset_num = 1 + source_dict = {'nodemask':'%s'} + source_xpath = [{'element_attrs':[".//source/nodemask"],'text':'%s'}] + - pagesize: + source_dict = {'pagesize':${page_size}, 'pagesize_unit':'KiB'} + source_xpath = [{'element_attrs':[".//source/pagesize[@unit='KiB']"],'text':'${page_size}'}] + - nodemask_pagesize: + no s390-virtio + nodeset_num = 2 + use_huge_page = "yes" + source_dict = {'nodemask':'%s', 'pagesize':${default_hp_size}, 'pagesize_unit':'KiB'} + source_xpath = [{'element_attrs':[".//source/nodemask"],'text':'%s'}, {'element_attrs':[".//source/pagesize[@unit='KiB']"],'text':'${default_hp_size}'}] + variants memory_target: + - all_requested_and_address: + init_size = 524288 + init_requested = ${init_size} + init_address = '0x240000000' + plug_size = 1048576 + plug_requested = ${plug_size} + plug_address = '0x300000000' + init_target_dict = {'size':${init_size}, 'size_unit':'KiB', 'node':0, 'requested_size':${init_requested}, 'requested_unit':'KiB', 'block_size':${default_hp_size}, 'address':{'attrs':{'base':'${init_address}'}}} + init_target_xpath = [{'element_attrs':[".//target/size[@unit='KiB']"],'text':'${init_size}'}, {'element_attrs':[".//target/requested[@unit='KiB']"],'text':'${init_requested}'}, {'element_attrs':[".//target/block[@unit='KiB']"],'text':'${default_hp_size}'}, {'element_attrs':[".//target/current[@unit='KiB']"],'text':'${init_requested}'}, {'element_attrs':[".//target/node"],'text':'0'}, {'element_attrs':[".//target/address[@base='${init_address}']"]}] + plug_target_dict = {'size':${plug_size}, 'size_unit':'KiB', 'node':1, 'requested_size':${plug_requested}, 'requested_unit':'KiB', 'block_size':${default_hp_size}, 'address':{'attrs':{'base':'${plug_address}'}}} + plug_target_xpath = [{'element_attrs':[".//target/size[@unit='KiB']"],'text':'${plug_size}'}, {'element_attrs':[".//target/requested[@unit='KiB']"],'text':'${plug_requested}'}, {'element_attrs':[".//target/block[@unit='KiB']"],'text':'${default_hp_size}'}, {'element_attrs':[".//target/current[@unit='KiB']"],'text':'${plug_requested}'}, {'element_attrs':[".//target/node"],'text':'1'}, {'element_attrs':[".//target/address[@base='${plug_address}']"]}] + s390-virtio: + init_target_dict = {'size':${init_size}, 'size_unit':'KiB', 'requested_size':${init_requested}, 'requested_unit':'KiB', 'block_size':${default_hp_size}, 'address':{'attrs':{'base':'${init_address}'}}} + init_target_xpath = [{'element_attrs':[".//target/size[@unit='KiB']"],'text':'${init_size}'}, {'element_attrs':[".//target/requested[@unit='KiB']"],'text':'${init_requested}'}, {'element_attrs':[".//target/block[@unit='KiB']"],'text':'${default_hp_size}'}, {'element_attrs':[".//target/current[@unit='KiB']"],'text':'${init_requested}'}, {'element_attrs':[".//target/address[@base='${init_address}']"]}] + plug_target_dict = {'size':${plug_size}, 'size_unit':'KiB', 'requested_size':${plug_requested}, 'requested_unit':'KiB', 'block_size':${default_hp_size}, 'address':{'attrs':{'base':'${plug_address}'}}} + plug_target_xpath = [{'element_attrs':[".//target/size[@unit='KiB']"],'text':'${plug_size}'}, {'element_attrs':[".//target/requested[@unit='KiB']"],'text':'${plug_requested}'}, {'element_attrs':[".//target/block[@unit='KiB']"],'text':'${default_hp_size}'}, {'element_attrs':[".//target/current[@unit='KiB']"],'text':'${plug_requested}'}, {'element_attrs':[".//target/address[@base='${plug_address}']"]}] + - part_requested_and_no_address: + init_size = 1048576 + init_requested = 524288 + plug_size = 2097152 + plug_requested = 1048576 + init_target_dict = {'size':${init_size}, 'size_unit':'KiB', 'node':0, 'requested_size':${init_requested}, 'requested_unit':'KiB', 'block_size':${default_hp_size}} + init_target_xpath = [{'element_attrs':[".//target/size[@unit='KiB']"],'text':'${init_size}'}, {'element_attrs':[".//target/requested[@unit='KiB']"],'text':'${init_requested}'}, {'element_attrs':[".//target/block[@unit='KiB']"],'text':'${default_hp_size}'}, {'element_attrs':[".//target/current[@unit='KiB']"],'text':'${init_requested}'}, {'element_attrs':[".//target/node"],'text':'0'}, {'element_attrs':[".//target/address"]}] + plug_target_dict = {'size':${plug_size}, 'size_unit':'KiB', 'node':1, 'requested_size':${plug_requested}, 'requested_unit':'KiB', 'block_size':${default_hp_size}} + plug_target_xpath = [{'element_attrs':[".//target/size[@unit='KiB']"],'text':'${plug_size}'}, {'element_attrs':[".//target/requested[@unit='KiB']"],'text':'${plug_requested}'}, {'element_attrs':[".//target/block[@unit='KiB']"],'text':'${default_hp_size}'}, {'element_attrs':[".//target/current[@unit='KiB']"],'text':'${plug_requested}'}, {'element_attrs':[".//target/node"],'text':'1'}, {'element_attrs':[".//target/address"]}] + s390-virtio: + init_target_dict = {'size':${init_size}, 'size_unit':'KiB', 'requested_size':${init_requested}, 'requested_unit':'KiB', 'block_size':${default_hp_size}} + init_target_xpath = [{'element_attrs':[".//target/size[@unit='KiB']"],'text':'${init_size}'}, {'element_attrs':[".//target/requested[@unit='KiB']"],'text':'${init_requested}'}, {'element_attrs':[".//target/block[@unit='KiB']"],'text':'${default_hp_size}'}, {'element_attrs':[".//target/current[@unit='KiB']"],'text':'${init_requested}'}, {'element_attrs':[".//target/address"]}] + plug_target_dict = {'size':${plug_size}, 'size_unit':'KiB', 'requested_size':${plug_requested}, 'requested_unit':'KiB', 'block_size':${default_hp_size}} + plug_target_xpath = [{'element_attrs':[".//target/size[@unit='KiB']"],'text':'${plug_size}'}, {'element_attrs':[".//target/requested[@unit='KiB']"],'text':'${plug_requested}'}, {'element_attrs':[".//target/block[@unit='KiB']"],'text':'${default_hp_size}'}, {'element_attrs':[".//target/current[@unit='KiB']"],'text':'${plug_requested}'}, {'element_attrs':[".//target/address"]}] + init_mem_device_dict = {'mem_model':'virtio-mem', 'source':${source_dict}, 'target':${init_target_dict}} + init_xpath_list = [${source_xpath}, ${init_target_xpath}] + plug_mem_device_dict = {'mem_model':'virtio-mem', 'source':${source_dict}, 'target':${plug_target_dict}} + plug_xpath_list = [${source_xpath}, ${plug_target_xpath}] + diff --git a/libvirt/tests/cfg/memory/memory_devices/virtio_mem_dynamic_slots.cfg b/libvirt/tests/cfg/memory/memory_devices/virtio_mem_dynamic_slots.cfg new file mode 100644 index 00000000000..47787107024 --- /dev/null +++ b/libvirt/tests/cfg/memory/memory_devices/virtio_mem_dynamic_slots.cfg @@ -0,0 +1,52 @@ +- memory.devices.virtio_mem.dynamic_slots: + type = virtio_mem_dynamic_slots + start_vm = "no" + mem_model = "virtio-mem" + allocate_size = "3145728" + allocate_memory = "${allocate_size}KiB" + mem_value = 2097152 + current_mem = 2097152 + max_mem = 4194304 + numa_mem = 1048576 + base_attrs = "'vcpu': 4, 'memory_unit':'KiB','memory':${mem_value},'current_mem':${current_mem},'current_mem_unit':'KiB'" + numa_attrs = "'cpu': {'numa_cell': [{'id': '0', 'cpus': '0-1', 'memory': '${numa_mem}', 'unit': 'KiB'},{'id':'1','cpus': '2-3','memory':'${numa_mem}','unit':'KiB'}]}" + max_attrs = "'max_mem_rt': ${max_mem}, 'max_mem_rt_slots': 16, 'max_mem_rt_unit': 'KiB'" + vm_attrs = {${base_attrs}, ${numa_attrs}, ${max_attrs}} + s390-virtio: + vm_attrs = {${base_attrs}, ${max_attrs}} + required_kernel = [5.14.0,) + guest_required_kernel = [5.8.0,) + func_supported_since_libvirt_ver = (10, 0, 0) + func_supported_since_qemu_kvm_ver = (8, 2, 0) + machine_version = "9.4.0" + monitor_cmd = " info mtree" + monitor_option = " --hmp" + variants: + - basic_virtio: + target_size = 524288 + request_size = 524288 + virtio_mem_dict = {'mem_model':'${mem_model}','target': {'size':${target_size}, 'requested_size': ${request_size},'block_size': %s, 'node':0}} + s390-virtio: + virtio_mem_dict = {'mem_model':'${mem_model}','target': {'size':${target_size}, 'requested_size': ${request_size},'block_size': %s}} + variants dynamic_memory_slots: + - undefined_dynamic_memory_slots: + slots_pattern = ["alias memslot-0 @memvirtiomem0", "alias memslot-0 @memvirtiomem1"] + - enable_dynamic_memory_slots: + dynamic_slot_attr = {"dynamicMemslots":"yes"} + slots_pattern = ["alias memslot-0 @memvirtiomem0", "alias memslot-0 @memvirtiomem1"] + - disable_dynamic_memory_slots: + dynamic_slot_attr = {"dynamicMemslots":"no"} + slots_pattern = ["memvirtiomem0", "memvirtiomem1"] + variants memory_backing: + - default_mb: + - file_mb: + source_type = 'file' + source_attr = "'source_type':'${source_type}'" + - hugepages_mb: + s390-virtio: + kvm_module_parameters = "hpage=1" + hugepages_attr = "'hugepages': {}" + - memfd_mb: + source_type = 'memfd' + source_attr = "'source_type':'${source_type}'" + diff --git a/libvirt/tests/cfg/memory/memory_devices/virtio_mem_hot_unplug.cfg b/libvirt/tests/cfg/memory/memory_devices/virtio_mem_hot_unplug.cfg new file mode 100644 index 00000000000..4938070000f --- /dev/null +++ b/libvirt/tests/cfg/memory/memory_devices/virtio_mem_hot_unplug.cfg @@ -0,0 +1,104 @@ +- memory.devices.virtio_mem.hot_unplug: + type = virtio_mem_hot_unplug + start_vm = yes + mem_model = "virtio-mem" + allocate_size = "1048576" + allocate_memory = "${allocate_size}KiB" + target_size = "1048576" + request_size = "1048576" + unplug_target_size = '1048576' + unplug_request_size = '1048576' + size_unit = 'KiB' + block_unit = 'KiB' + request_unit = 'KiB' + unplug_size_unit = 'KiB' + unplug_block_unit = 'KiB' + unplug_request_unit = 'KiB' + node = 0 + unplug_node = 0 + slot = 0 + mem_value = 2097152 + current_mem = 2097152 + numa_mem = 1048576 + max_mem = 4194304 + max_mem_slots = 16 + base = "0x100000000" + with_numa = yes + s390-virtio: + with_numa = no + base = "0x40000000" + addr_dict = "'address':{'attrs': {'base': '${base}'}}" + kernel_params_add = "memhp_default_state=online_movable" + kernel_params_remove = "memhp_default_state" + unplug_event = "device-removed" + audit_cmd = "grep VIRT_RESOURCE /var/log/audit/audit.log | grep 'mem' | tail -n 20" + ausearch_check = 'old-mem=%d new-mem=%d' + expected_log = "device_del" + kernel_hp_file = '/sys/devices/system/node/node0/hugepages/hugepages-%skB/nr_hugepages' + max_dict = '"max_mem_rt": ${max_mem}, "max_mem_rt_slots": ${max_mem_slots}, "max_mem_rt_unit": "KiB"' + numa_dict = "'vcpu': 4,'cpu':{'numa_cell': [{'id': '0', 'cpus': '0-1', 'memory': '${numa_mem}'}, {'id': '1', 'cpus': '2-3', 'memory': '${numa_mem}'}]}" + vm_attrs = {${numa_dict},${max_dict},'memory_unit':'KiB','memory':${mem_value},'current_mem':${current_mem},'current_mem_unit':'KiB'} + s390-virtio: + vm_attrs = {${max_dict},'memory_unit':'KiB','memory':${mem_value},'current_mem':${current_mem},'current_mem_unit':'KiB'} + required_kernel = [5.14.0,) + guest_required_kernel = [5.8.0,) + func_supported_since_libvirt_ver = (10, 0, 0) + func_supported_since_qemu_kvm_ver = (8, 2, 0) + machine_version = "9.4.0" + zero_size_error_msg = "virtio-mem device cannot get unplugged while 'size' != '0'" + zero_request_error_msg = "virtio-mem device cannot get unplugged while 'requested-size' != '0'" + basic_error_msg = "virtio-mem device cannot get unplugged while some of its memory is still plugged" + variants case: + - target_and_address: + unplug_request_size = '0' + updated_request_option = "--requested-size 0" + - source_mib_and_hugepages: + no s390-virtio + target_size = "1024" + request_size = "512" + size_unit = 'MiB' + request_unit = "MiB" + node = 1 + unplug_target_size = "1024" + unplug_request_size = "0" + unplug_size_unit = "MiB" + unplug_request_unit = "MiB" + unplug_node = 1 + source_dict = {'nodemask': '0','pagesize': %d, 'pagesize_unit':'KiB'} + updated_request_option = "--requested-size 0" + - nonexistent_mem: + node = 1 + unplug_node = 1 + target_size = "524288" + request_size = "524288" + unplug_target_size = "1048576" + unplug_request_size = "524288" + s390-virtio: + base = "0x80000000" + addr_dict = "'address':{'attrs': {'base': '${base}'}}" + - none_zero_current: + - none_zero_request: + no s390-virtio + source_dict = {'nodemask': '0','pagesize': %d, 'pagesize_unit':'KiB'} + virtio_dict = {'mem_model':'${mem_model}','alias': {'name': '%s'},'target': {${addr_dict},'size':${target_size}, 'size_unit':'${size_unit}', 'node':${node},'requested_size': ${request_size},'requested_unit':'${request_unit}', 'block_size': %s, 'block_unit':'${block_unit}'}} + unplug_dict = {'mem_model':'${mem_model}','alias': {'name': '%s'},'target': {${addr_dict},'size':${unplug_target_size},'requested_size': ${unplug_request_size}, 'block_size': %s, 'size_unit':'${unplug_size_unit}','requested_unit':'${unplug_request_unit}','block_unit':'${unplug_block_unit}','node':${unplug_node}}} + s390-virtio: + virtio_dict = {'mem_model':'${mem_model}','alias': {'name': '%s'},'target': {${addr_dict},'size':${target_size}, 'size_unit':'${size_unit}', 'requested_size': ${request_size},'requested_unit':'${request_unit}', 'block_size': %s, 'block_unit':'${block_unit}'}} + unplug_dict = {'mem_model':'${mem_model}','alias': {'name': '%s'},'target': {${addr_dict},'size':${unplug_target_size},'requested_size': ${unplug_request_size}, 'block_size': %s, 'size_unit':'${unplug_size_unit}','requested_unit':'${unplug_request_unit}','block_unit':'${unplug_block_unit}'}} + variants plug_way: + - detach: + detach_method = "detach" + nonexistent_mem: + unplug_error = "model 'virtio-mem' memory device not present in the domain configuration" + none_zero_current: + unplug_error = "${zero_size_error_msg}|${basic_error_msg}" + none_zero_request: + unplug_error = "${zero_request_error_msg}|${basic_error_msg}" + - detach_alias: + no nonexistent_mem + detach_method = "detach_alias" + none_zero_current: + unplug_error = "${zero_size_error_msg}|${basic_error_msg}" + none_zero_request: + unplug_error = "${zero_request_error_msg}|${basic_error_msg}" + diff --git a/libvirt/tests/cfg/memory/memory_devices/virtio_mem_hotplug.cfg b/libvirt/tests/cfg/memory/memory_devices/virtio_mem_hotplug.cfg new file mode 100644 index 00000000000..20760cc1933 --- /dev/null +++ b/libvirt/tests/cfg/memory/memory_devices/virtio_mem_hotplug.cfg @@ -0,0 +1,85 @@ +- memory.devices.virtio_mem.hotplug: + type = virtio_mem_hotplug + start_vm = no + mem_model = "virtio-mem" + allocate_size = "1048576" + allocate_memory = "${allocate_size}KiB" + target_size = "1048576" + request_size = "1048576" + size_unit = 'KiB' + block_unit = 'KiB' + request_unit = 'KiB' + plug_size_unit = 'KiB' + plug_block_unit = 'KiB' + plug_request_unit = 'KiB' + node = 0 + plug_node = 0 + slot = 0 + base = "0x100000000" + mem_value = 2097152 + current_mem = 2097152 + numa_mem = 1048576 + max_mem = 4194304 + max_mem_slots = 16 + plug_event = "device-added" + audit_cmd = "grep VIRT_RESOURCE /var/log/audit/audit.log | grep 'mem' | tail -n 20" + ausearch_check = 'old-mem=%d new-mem=%d' + expected_log = "device_add" + kernel_hp_file = '/sys/devices/system/node/node0/hugepages/hugepages-%skB/nr_hugepages' + max_dict = '"max_mem_rt": ${max_mem}, "max_mem_rt_slots": ${max_mem_slots}, "max_mem_rt_unit": "KiB"' + numa_dict = "'vcpu': 4,'cpu':{'numa_cell': [{'id': '0', 'cpus': '0-1', 'memory': '${numa_mem}'}, {'id': '1', 'cpus': '2-3', 'memory': '${numa_mem}'}]}" + vm_attrs = {${numa_dict},${max_dict},'memory_unit':'KiB','memory':${mem_value},'current_mem':${current_mem},'current_mem_unit':'KiB'} + s390-virtio: + base = "0x80000000" + mem_value = 3145728 + current_mem = 3145728 + numa_dict = + vm_attrs = {${max_dict},'memory_unit':'KiB','memory':${mem_value},'current_mem':${current_mem},'current_mem_unit':'KiB'} + required_kernel = [5.14.0,) + guest_required_kernel = [5.8.0,) + func_supported_since_libvirt_ver = (8, 0, 0) + func_supported_since_qemu_kvm_ver = (6, 2, 0) + variants case: + - target_and_address: + plug_target_size = '524288' + plug_request_size = '524288' + addr_dict = {'attrs': {'base':'${base}'}} + plug_base = "0x140000000" + s390-virtio: + plug_base = "0xc0000000" + plug_addr_dict = {'attrs': {'base':'${plug_base}'}} + - source_mib_and_hugepages: + no s390-virtio + target_size = "512" + request_size = "512" + size_unit = 'MiB' + request_unit = "MiB" + node = 1 + plug_target_size = "1024" + plug_request_size = "1024" + plug_size_unit = "MiB" + plug_request_unit = "MiB" + plug_node = 1 + source_dict = {'nodemask': '0','pagesize': %d, 'pagesize_unit':'KiB'} + - plug_exceeded_max_mem: + node = 1 + plug_node = 1 + plug_target_size = "2097152" + plug_request_size = "1048576" + plug_error = "exceed domain's maxMemory config size '${max_mem}'" + - duplicate_addr: + target_size = '524288' + request_size = '524288' + s390-virtio: + base = "0xc0000000" + addr_dict = {'attrs': {'base':'${base}'}} + plug_error = "address range conflicts|overlaps" + plug_target_size = ${target_size} + plug_request_size = ${request_size} + plug_addr_dict = ${addr_dict} + virtio_dict = {'mem_model':'${mem_model}','target': {'size':${target_size}, 'size_unit':'${size_unit}', 'node':${node},'requested_size': ${request_size},'requested_unit':'${request_unit}', 'block_size': %s, 'block_unit':'${block_unit}'}} + plug_dict = {'mem_model':'${mem_model}','target': {'size':${plug_target_size},'requested_size': ${plug_request_size}, 'block_size': %s, 'size_unit':'${plug_size_unit}','requested_unit':'${plug_request_unit}','block_unit':'${plug_block_unit}','node':${plug_node}}} + s390-virtio: + virtio_dict = {'mem_model':'${mem_model}','target': {'size':${target_size}, 'size_unit':'${size_unit}','requested_size': ${request_size},'requested_unit':'${request_unit}', 'block_size': %s, 'block_unit':'${block_unit}'}} + plug_dict = {'mem_model':'${mem_model}','target': {'size':${plug_target_size},'requested_size': ${plug_request_size}, 'block_size': %s, 'size_unit':'${plug_size_unit}','requested_unit':'${plug_request_unit}','block_unit':'${plug_block_unit}'}} + diff --git a/libvirt/tests/cfg/memory/memory_devices/virtio_mem_with_memory_allocation_and_numa.cfg b/libvirt/tests/cfg/memory/memory_devices/virtio_mem_with_memory_allocation_and_numa.cfg new file mode 100644 index 00000000000..99f1177d7f3 --- /dev/null +++ b/libvirt/tests/cfg/memory/memory_devices/virtio_mem_with_memory_allocation_and_numa.cfg @@ -0,0 +1,93 @@ +- memory.devices.virtio_mem.memory_allocation_and_numa: + type = virtio_mem_with_memory_allocation_and_numa + start_vm = no + mem_model = "virtio-mem" + mem_value = 8388608 + current_mem = 8388608 + request_size = "512" + target_size = "512" + target_size_unit = "MiB" + request_size_unit = "MiB" + take_regular_screendumps = no + base_attrs = "'memory_unit':'KiB','memory':${mem_value},'current_mem':${current_mem},'current_mem_unit':'KiB'," + err_msg1 = "cannot use/hotplug a memory device when domain 'maxMemory' is not defined" + err_msg2 = "target NUMA node needs to be specified for memory device" + err_msg3 = "can't add memory backend as guest has no NUMA nodes configured" + required_kernel = [5.14.0,) + guest_required_kernel = [5.8.0,) + func_supported_since_libvirt_ver = (8, 0, 0) + func_supported_since_qemu_kvm_ver = (6, 2, 0) + variants memory_allocation: + - no_maxmemory: + max_attrs = "" + define_error = "${err_msg1}" + - with_maxmemory: + max_mem = 20971520 + max_attrs = '"max_mem_rt": ${max_mem}, "max_mem_rt_unit": "KiB",' + variants numa_topology: + - without_numa: + numa_attrs = "" + - with_numa: + no s390-virtio + numa_mem = 8388608 + numa_attrs = "'vcpu': 4, 'cpu': {'numa_cell': [{'id': '0', 'cpus': '0-3', 'memory': '${numa_mem}', 'unit': 'KiB'}]}," + vm_attrs = {${base_attrs} ${max_attrs} ${numa_attrs}} + variants: + - virtio_mem_with_node: + no s390-virtio + node = 0 + virtio_mem_dict = {'mem_model': '${mem_model}', 'target': {'requested_unit': '${request_size_unit}', 'size': ${target_size}, 'node': ${node}, 'size_unit': '${target_size_unit}', 'requested_size': ${request_size}, 'block_unit': 'KiB', 'block_size': %s}} + no_maxmemory: + with_numa: + cold_plug_error = "${err_msg1}" + hot_plug_error = "${err_msg1}" + without_numa: + cold_plug_error = "${err_msg3}" + hot_plug_error = "${err_msg3}" + - virtio_mem_without_node: + virtio_mem_dict = {'mem_model': '${mem_model}', 'target': {'requested_unit': '${request_size_unit}', 'size': ${target_size}, 'size_unit': '${target_size_unit}', 'requested_size': ${request_size}, 'block_unit': 'KiB', 'block_size': %s}} + coldplug_start_error = "${err_msg1}" + with_numa: + cold_plug_error = "${err_msg1}" + with_maxmemory: + define_error = "${err_msg2}" + hot_plug_error = "${err_msg1}" + with_maxmemory: + x86_64, aarch64: + hot_plug_error = "${err_msg2}" + cold_plug_error = "${err_msg2}" + s390-virtio: + coldplug_start_error = + no_maxmemory: + cold_plug_error = "${err_msg1}" + without_numa,with_numa: + hot_plug_error = "${err_msg1}" + - virtio_mem_with_exceed_size: + only without_numa.with_maxmemory + target_size = "524288" + s390-virtio: + target_size = "15728640" + request_size = "512" + target_size_unit = "KiB" + virtio_mem_dict = {'mem_model': '${mem_model}', 'target': {'requested_unit': '${request_size_unit}', 'size': ${target_size}, 'size_unit': '${target_size_unit}', 'requested_size': ${request_size}, 'block_unit': 'KiB', 'block_size': %s}} + coldplug_start_error = "${err_msg2}" + with_maxmemory: + x86_64, aarch64: + hot_plug_error = "${err_msg2}" + cold_plug_error = "${err_msg2}" + s390-virtio: + coldplug_start_error = + cold_plug_error = "would exceed domain's maxMemory config size" + hot_plug_error = "${cold_plug_error}" + without_numa: + with_maxmemory: + define_error = "Total size of memory devices exceeds the total memory size" + variants plug_type: + - define_guest: + - cold_plug: + operation = "attach" + plug_option = " --config" + - hot_plug: + operation = "attach" + plug_option = " " + diff --git a/libvirt/tests/cfg/memory/memory_devices/virtio_mem_with_memory_backing_type.cfg b/libvirt/tests/cfg/memory/memory_devices/virtio_mem_with_memory_backing_type.cfg new file mode 100644 index 00000000000..52f371ec3b7 --- /dev/null +++ b/libvirt/tests/cfg/memory/memory_devices/virtio_mem_with_memory_backing_type.cfg @@ -0,0 +1,96 @@ +- memory.devices.virtio_mem.memory_backing_type: + type = virtio_mem_with_memory_backing_type + start_vm = no + mem_model = "virtio-mem" + virtio_mem_num = 2 + allocate_huge_pages = "3145728KiB" + remain_mem = 102400 + mem_value = 2097152 + current_mem = 2097152 + max_mem = 4194304 + numa_mem = 1048576 + aarch_max_mem = 20971520 + virtio_config = [(None, 0), ("huge_page", 1)] + base_attrs = "'vcpu': 4, 'memory_unit':'KiB','memory':${mem_value},'current_mem':${current_mem},'current_mem_unit':'KiB'" + numa_attrs = "'cpu': {'numa_cell': [{'id': '0', 'cpus': '0-1', 'memory': '${numa_mem}', 'unit': 'KiB'}, {'id': '1', 'cpus': '2-3', 'memory': '${numa_mem}', 'unit': 'KiB'}]}" + max_attrs = "'max_mem_rt': %s, 'max_mem_rt_slots': 16, 'max_mem_rt_unit': 'KiB'" + vm_attrs = {${base_attrs}, ${numa_attrs}, ${max_attrs}} + s390-virtio: + virtio_config = [(None,), (None,)] + vm_attrs = {${base_attrs}, ${max_attrs}} + target_size = 524288 + request_size = 524288 + type0 = "memory-backend-ram" + type1 = "memory-backend-file" + path0 = "" + path1 = "/dev/hugepages/libvirt/qemu/" + prealloc0 = "True" + prealloc1 = "True" + required_kernel = [5.14.0,) + guest_required_kernel = [5.8.0,) + func_supported_since_libvirt_ver = (8, 0, 0) + func_supported_since_qemu_kvm_ver = (6, 2, 0) + variants memory_backing: + - file: + source_type = 'file' + source_attr = "'source_type':'${source_type}'" + type0 = "memory-backend-file" + type1 = ${type0} + - anonymous: + no set_hugepage + source_type = 'anonymous' + source_attr = "'source_type':'${source_type}'" + - memfd: + source_type = 'memfd' + source_attr = "'source_type':'${source_type}'" + type0 = "memory-backend-memfd" + type1 = ${type0} + - undefined: + variants allocation_mode: + - alloc_ondemand: + prealloc0 = "False" + s390-virtio: + prealloc1 = "False" + mode = "ondemand" + alloc_attr = "'allocation':{'mode':'${mode}'}" + file: + path0 = "/var/lib/libvirt/qemu/ram/" + s390-virtio: + path1 = "/var/lib/libvirt/qemu/ram/" + anonymous, undefined: + s390-virtio: + type1 = "memory-backend-ram" + - alloc_immediate_with_threads: + func_supported_since_libvirt_ver = (8, 2, 0) + mode = "immediate" + threads = 8 + alloc_attr = "'allocation':{'mode':'${mode}', 'threads':${threads}}" + file: + path0 = "/var/lib/libvirt/qemu/ram/" + s390-virtio: + path1 = "/var/lib/libvirt/qemu/ram/" + anonymous, undefined: + s390-virtio: + type1 = "memory-backend-ram" + - set_hugepage: + s390-virtio: + kvm_module_parameters = "hpage=1" + hugepages_attr = "'hugepages': {}" + undefined: + type0 = "memory-backend-file" + type1 = ${type0} + file: + path0 = "/dev/hugepages/libvirt/qemu/" + undefined: + path0 = "/dev/hugepages/libvirt/qemu/" + check_backing_type = '{"execute":"qom-get", "arguments":{"path":"/objects/%s", "property":"type"}}' + check_mem_path = '{"execute":"qom-get", "arguments":{"path":"/objects/%s", "property":"mem-path"}}' + check_prealloc_config = '{"execute":"qom-get", "arguments":{"path":"/machine/peripheral/%s", "property":"prealloc"}}' + expected_prealloc_config = ['${prealloc0}', '${prealloc1}'] + expected_allocated = ['false', 'false'] + expected_backing_type = ['${type0}', '${type1}'] + expected_mem_path = ['${path0}', '${path1}'] + variants attach_type: + - hot_plug: + - cold_plug: + diff --git a/libvirt/tests/cfg/memory/memory_devices/virtio_memory_with_numa_node_tuning.cfg b/libvirt/tests/cfg/memory/memory_devices/virtio_memory_with_numa_node_tuning.cfg new file mode 100644 index 00000000000..332583d7f61 --- /dev/null +++ b/libvirt/tests/cfg/memory/memory_devices/virtio_memory_with_numa_node_tuning.cfg @@ -0,0 +1,60 @@ +- memory.devices.virtio.with_numa_tuning: + no s390-virtio + type = virtio_memory_with_numa_node_tuning + start_vm = "yes" + mem_model = "virtio-mem" + allocate_huge_mem = "1048576KiB" + allocate_huge_mem_1 = "2097152KiB" + hugepage_path = "/dev/hugepages-%s" + kernel_hp_tmpl_file = "/sys/devices/system/node/node%s/hugepages/hugepages-%skB/nr_hugepages" + memory_backing_dict = "'mb': {'hugepages': {'pages': [{'size': '%s','unit': 'KiB','nodeset':'0'}]}}" + base_attrs = "'vcpu': 4, 'memory_unit':'KiB','memory':2097152,'current_mem':2097152" + numa_attrs = "'cpu': {'numa_cell': [{'id': '0', 'cpus': '0-1', 'memory': '1048576', 'unit': 'KiB'},{'id':'1','cpus': '2-3','memory':'1048576','unit':'KiB'}]}" + max_attrs = "'max_mem_rt': 15242880, 'max_mem_rt_slots': 16" + required_kernel = [5.14.0,) + guest_required_kernel = [5.8.0,) + func_supported_since_libvirt_ver = (8, 0, 0) + func_supported_since_qemu_kvm_ver = (6, 2, 0) + variants numa_tuning: + - strict: + tuning_mode = "strict" + mode_attrs = "'numa_memory': {'mode': '${tuning_mode}','nodeset': '%s'}," + memnode_mode = "interleave" + numa_memnode = "'numa_memnode':[{'cellid': '0', 'mode': '${memnode_mode}', 'nodeset': '%s'}]" + - interleave: + tuning_mode = "interleave" + mode_attrs = "'numa_memory': {'mode': '${tuning_mode}','nodeset': '%s'}," + memnode_mode = "preferred" + numa_memnode = "'numa_memnode':[{'cellid': '0', 'mode': '${memnode_mode}', 'nodeset': '%s'}]" + - preferred: + tuning_mode = "preferred" + memnode_mode = "strict" + mode_attrs = "'numa_memory': {'mode': '${tuning_mode}','nodeset': '%s'}," + numa_memnode = "'numa_memnode':[{'cellid': '0', 'mode': '${memnode_mode}', 'nodeset': '%s'}]" + - undefined: + mode_attrs = "" + numa_memnode = "" + tuning_attrs = "${mode_attrs}${numa_memnode}" + vm_attrs = {${memory_backing_dict},${base_attrs}, ${numa_attrs}, ${max_attrs}, ${tuning_attrs}} + variants case: + - with_source_virtio_mem: + request_size = 1048576 + target_size = 1048576 + virtio_mem_1 = {'mem_model': '${mem_model}', 'source': {'nodemask': '1', 'pagesize': %s, 'pagesize_unit': 'KiB'},'target': {'size': ${target_size}, 'node': 1, 'requested_size': ${request_size}, 'block_size': %s}} + virtio_mem_2 = {'mem_model': '${mem_model}', 'source': {'nodemask': '0', 'pagesize': %s, 'pagesize_unit': 'KiB'},'target': {'size': ${target_size}, 'node': 0, 'requested_size': ${request_size}, 'block_size': %s}} + virtio_mem_list = [${virtio_mem_1}, ${virtio_mem_2}] + - no_source_virtio_mem: + target_size_1 = 524288 + kernel_extra_params_add = "memhp_default_state=online_movable" + virtio_mem_1 = {'mem_model': '${mem_model}', 'target': {'size': ${target_size_1}, 'node': 1, 'requested_size': 524288, 'block_size': %s}} + virtio_mem_2 = {'mem_model': '${mem_model}', 'target': {'size': 1048576, 'node': 0, 'requested_size': 1048576, 'block_size': %s}} + virtio_mem_list = [${virtio_mem_1}, ${virtio_mem_2}] + - requested_bigger_than_host_numa: + request_size = 2097152 + target_size = 2097152 + virtio_mem_list = [{'mem_model': '${mem_model}', 'target': {'size': ${target_size}, 'node': 0, 'requested_size': ${request_size}, 'block_size':%s}}] + variants operation: + - cold_plug: + attach_option = "--config" + - hot_plug: + attach_option = " " diff --git a/libvirt/tests/cfg/memory/memory_misc.cfg b/libvirt/tests/cfg/memory/memory_misc.cfg index 4d6d10679e5..3ac1c9f2478 100644 --- a/libvirt/tests/cfg/memory/memory_misc.cfg +++ b/libvirt/tests/cfg/memory/memory_misc.cfg @@ -27,9 +27,8 @@ kvm_module_parameters = "hpage=1" - memfd_backed: mem_backing_attrs = {'hugepages': {}, 'source_type': 'memfd' ,'allocation': {'threads': '${threads_num}'}} - qemu_check = '"qom-type":"memory-backend-memfd".*"hugetlbsize":2097152.*"prealloc-threads":${threads_num}' + qemu_check = '"qom-type":"memory-backend-memfd".*"hugetlbsize":%s.*"prealloc-threads":${threads_num}' s390-virtio: - qemu_check = '"qom-type":"memory-backend-memfd".*"hugetlbsize":1048576.*"prealloc-threads":${threads_num}' kvm_module_parameters = "hpage=1" - ram_backed: mem_backing_attrs = {'allocation': {'mode': 'immediate', 'threads': '${threads_num}'}} @@ -39,13 +38,36 @@ vm_attrs = {'max_mem_rt': 2124800, 'max_mem_rt_slots': 16, 'max_mem_rt_unit': 'KiB', 'memory': 1155072, 'memory_unit': 'KiB', 'current_mem': 1048576, 'current_mem_unit': 'KiB', 'vcpu': 16} numa_node_size = 512000 cpu_attrs = {'numa_cell': [{'id': '0', 'cpus': '0-7', 'memory': '${numa_node_size}', 'unit': 'KiB'}, {'id': '1', 'cpus': '8-15', 'memory': '${numa_node_size}', 'unit': 'KiB'}]} - mem_device_attrs = {'source': {'pagesize_unit': 'KiB', 'pagesize': 2048, 'nodemask': '0'}, 'mem_model': 'dimm', 'target': {'size': 131072, 'node': 1, 'size_unit': 'KiB'}} + variants kernel_pagesize: + - 4k: + default_page_size = 4 + variants huge_pagesize: + - 2048: + default_hugepage_size = 2048 + mem_device_attrs = {'source': {'pagesize_unit': 'KiB', 'pagesize': 2048, 'nodemask': '0'}, 'mem_model': 'dimm', 'target': {'size': 131072, 'node': 1, 'size_unit': 'KiB'}} + - 64k: + only aarch64 + default_page_size = 64 + variants huge_pagesize: + - 524288: + default_hugepage_size = 524288 + mem_device_attrs = {'source': {'pagesize_unit': 'KiB', 'pagesize': 524288, 'nodemask': '0'}, 'mem_model': 'dimm', 'target': {'size': 524288, 'node': 1, 'size_unit': 'KiB'}} - nodeset_specified: no s390-virtio - pagesize = 1048576 - aarch64: - pagesize = 524288 - pagenum = 10 + variants kernel_pagesize: + - 4k: + default_page_size = 4 + variants huge_pagesize: + - 1048576: + pagesize = 1048576 + pagenum = 10 + - 64k: + only aarch64 + default_page_size = 64 + variants huge_pagesize: + - 16777216: + pagesize = 16777216 + pagenum = 1 variants scenario: - nodeset_0: mem_backing_attrs = {'hugepages': {'pages': [{'unit': 'KiB', 'nodeset': '0', 'size': '${pagesize}'}]}, 'locked': True} @@ -56,21 +78,55 @@ expect_msg = 'hugepages: node 0 not found' - hp_from_2_numa_nodes: no s390-virtio - pagesize = 2048 - pagenum = 5120 - vm_attrs = {'max_mem_rt': 83886080, 'max_mem_rt_slots': 8, 'max_mem_rt_unit': 'KiB', 'memory': 20971520, 'memory_unit': 'KiB', 'current_mem': 20971520, 'current_mem_unit': 'KiB'} + variants kernel_pagesize: + - 4k: + default_page_size = 4 + variants huge_pagesize: + - 2048: + pagesize = 2048 + pagenum = 2560 + - 64k: + only aarch64 + default_page_size = 64 + variants huge_pagesize: + - 524288: + pagesize = 524288 + pagenum = 10 + vm_attrs = {'max_mem_rt': 83886080, 'max_mem_rt_slots': 8, 'max_mem_rt_unit': 'KiB', 'memory': 10485760, 'memory_unit': 'KiB', 'current_mem': 10485760, 'current_mem_unit': 'KiB'} mem_backing_attrs = {'hugepages': {}} - cpu_attrs = {'numa_cell': [{'id': '0', 'cpus': '0-1', 'memory': '19922944', 'unit': 'KiB', 'discard': 'yes'}]} - mem_device_attrs = {'source': {'pagesize_unit': 'KiB', 'pagesize': 2048, 'nodemask': '0'}, 'mem_model': 'dimm', 'target': {'size': 1048576, 'node': 0, 'size_unit': 'KiB'}} + cpu_attrs = {'numa_cell': [{'id': '0', 'cpus': '0-1', 'memory': '9437184', 'unit': 'KiB', 'discard': 'yes'}]} + mem_device_attrs = {'source': {'pagesize_unit': 'KiB', 'pagesize': ${pagesize}, 'nodemask': '0'}, 'mem_model': 'dimm', 'target': {'size': 1048576, 'node': 0, 'size_unit': 'KiB'}} - mount_hp_running_vm: no s390-virtio - pagesize = 2048 - hp_path = '/dev/hugepages1G' - vm_attrs = {'vcpu': 4, 'max_mem_rt': 15242880, 'max_mem_rt_slots': 16, 'max_mem_rt_unit': 'KiB'} + variants kernel_pagesize: + - 4k: + default_page_size = 4 + variants huge_pagesize: + - 2048: + pagesize = 2048 + variants ext_huge_pagesize: + - 1048576: + mount_pagesize = 1048576 + mount_path = '/dev/hugepages1G' + mount_option = 'pagesize=1G' + mem_device_size = 1048576 + - 64k: + only aarch64 + default_page_size = 64 + variants huge_pagesize: + - 524288: + pagesize = 524288 + variants ext_huge_pagesize: + - 16777216: + mount_pagesize = 16777216 + mount_path= '/dev/hugepages16G' + mount_option = 'pagesize=16G' + mem_device_size = 16777216 + vm_attrs = {'vcpu': 4, 'max_mem_rt': 20971520, 'max_mem_rt_slots': 16, 'max_mem_rt_unit': 'KiB'} numa_node_size = 1048576 cpu_attrs = {'numa_cell': [{'id': '0', 'cpus': '0-1', 'memory': '${numa_node_size}', 'unit': 'KiB'}, {'id': '1', 'cpus': '2-3', 'memory': '${numa_node_size}', 'unit': 'KiB'}]} mem_backing_attrs = {'hugepages': {'pages': [{'unit': 'KiB', 'size': '${pagesize}'}]}} - mem_device_attrs = {'source': {'pagesize': 1048576, 'pagesize_unit': 'KiB'}, 'mem_model': 'dimm', 'target': {'size': 1048576, 'node': 0, 'size_unit': 'KiB'}} + mem_device_attrs = {'source': {'pagesize': ${mount_pagesize}, 'pagesize_unit': 'KiB'}, 'mem_model': 'dimm', 'target': {'size': ${mem_device_size}, 'node': 0, 'size_unit': 'KiB'}} - edit_mem: variants case: - forbid_0: @@ -98,7 +154,7 @@ variants case: - disk_caches: membal_model = 'virtio' - membal_stats_period = 2 + membal_stats_period = 1 membal_alias_name = 'balloon0' allow_error = 15 - xml_check: @@ -140,12 +196,14 @@ vmxml_max_mem_unit = 'KiB' vmxml_max_mem = 1024000 vmxml_current_mem_unit = 'KiB' - vmxml_current_mem = 1024000 + vmxml_current_mem = 2048000 vmxml_vcpu = 4 cpu_attrs = {'mode': 'host-model', 'numa_cell': [{'id': '0', 'cpus': '0,2', 'memory': '${numa_node_size}', 'unit': 'KiB'}, {'id': '1', 'cpus': '1,3', 'memory': '${numa_node_size}', 'unit': 'KiB'}]} + aarch64: + cpu_attrs = {'mode': 'host-passthrough', 'numa_cell': [{'id': '0', 'cpus': '0,2', 'memory': '${numa_node_size}', 'unit': 'KiB'}, {'id': '1', 'cpus': '1,3', 'memory': '${numa_node_size}', 'unit': 'KiB'}]} dimm_device_1_attrs = {'mem_model': 'dimm', 'target': {'size': ${at_size}, 'size_unit': 'KiB', 'node': 1}} dimm_device_0_attrs = {'mem_model': 'dimm', 'target': {'size': 0, 'size_unit': 'KiB', 'node': 0}} - audit_cmd = ausearch -ts recent -m VIRT_RESOURCE| grep 'mem' + audit_cmd = grep VIRT_RESOURCE /var/log/audit/audit.log | grep 'mem' | tail -n 20 error_msg = "unable to execute QEMU command 'object-add':.*memory-backend-ram.* doesn't take value '0'" dominfo_check_0 = 'Max memory:\s+%d KiB\nUsed memory:\s+%d KiB' dominfo_check_1 = 'Max memory:\s+%d KiB\nUsed memory:\s+%d KiB' @@ -170,3 +228,4 @@ vmxml_memory = 3145760 vmxml_current_mem = 3045760 cpu_attrs = {'mode': 'host-passthrough', 'numa_cell': [{'id': '0', 'cpus': '0,2', 'memory': '${numa_node_size}', 'unit': 'KiB'}, {'id': '1', 'cpus': '1,3', 'memory': '${numa_node_size}', 'unit': 'KiB'}]} + diff --git a/libvirt/tests/cfg/memory/memory_tuning/memory_tuning_settings.cfg b/libvirt/tests/cfg/memory/memory_tuning/memory_tuning_settings.cfg new file mode 100644 index 00000000000..33e68b96ce7 --- /dev/null +++ b/libvirt/tests/cfg/memory/memory_tuning/memory_tuning_settings.cfg @@ -0,0 +1,22 @@ +- memory.tuning: + type = memory_tuning_settings + start_vm = no + memtune_cmd_parameter_seq = ['hard_limit', 'soft_limit', 'swap_hard_limit'] + max_limit_dict = {'hard_limit':-1, 'soft_limit':-1, 'swap_hard_limit':-1} + vm_attrs = {'memory_unit':"KiB", 'memory':2097152, 'current_mem':2097152, 'current_mem_unit':'KiB'} + cgroupv1_error_for_zero_hard_limit = "Unable to write to '.*memory.limit_in_bytes': Device or resource busy" + variants test_target: + - normal: + target_limit_dict = {'hard_limit':3072005, 'soft_limit':2048003, 'swap_hard_limit':4096010} + - zero: + target_limit_dict = {'soft_limit':0, 'hard_limit':0} + shutdown_timeout = 2 + - minus: + init_hard_limit = 3072005 + init_soft_limit = 2048003 + init_swap_hard_limit = 4096010 + init_limit_dict = {'hard_limit':${init_hard_limit}, 'soft_limit':${init_soft_limit}, 'swap_hard_limit':${init_swap_hard_limit}} + init_memory_tuning_dict = "'memtune': {'hard_limit':${init_hard_limit}, 'hard_limit_unit':'KiB', 'soft_limit':${init_soft_limit}, 'soft_limit_unit':'KiB', 'swap_hard_limit':${init_swap_hard_limit}, 'swap_limit_unit':'KiB'}" + target_limit_dict = {'soft_limit':-1, 'swap_hard_limit':-1, 'hard_limit':-1} + vm_attrs = {'memory_unit':"KiB", 'memory':2097152, 'current_mem':2097152, 'current_mem_unit':'KiB', ${init_memory_tuning_dict}} + diff --git a/libvirt/tests/cfg/memory/memory_update_device.cfg b/libvirt/tests/cfg/memory/memory_update_device.cfg index 6ff1f277aa0..1f93a0644e9 100644 --- a/libvirt/tests/cfg/memory/memory_update_device.cfg +++ b/libvirt/tests/cfg/memory/memory_update_device.cfg @@ -10,9 +10,11 @@ func_supported_since_libvirt_ver = (8, 0, 0) func_supported_since_qemu_kvm_ver = (6, 2, 0) vm_attrs = {'max_mem_rt': 10485760, 'max_mem_rt_slots': 16, 'max_mem_rt_unit': 'KiB', 'vcpu': 4, 'cpu': {'numa_cell': [{'id': '0', 'cpus': '0-1', 'memory': '1048576', 'unit': 'KiB'}]}} + mem_device_attrs = {'mem_model': 'virtio-mem', 'target': {'requested_unit': 'KiB', 'size': 262144, 'node': 0, 'size_unit': 'KiB', 'requested_size': 131072, 'block_unit': 'KiB', 'block_size': 2048}} + requested_size = 160MiB aarch64: - vm_attrs = {'max_mem_rt': 10485760, 'max_mem_rt_slots': 16, 'max_mem_rt_unit': 'KiB', 'vcpu': 4, 'cpu': {'mode': 'host-passthrough', 'numa_cell': [{'id': '0', 'cpus': '0-3', 'memory': '524288', 'unit': 'KiB'}]}} + vm_attrs = {'max_mem_rt': 20971520, 'max_mem_rt_slots': 16, 'max_mem_rt_unit': 'KiB', 'vcpu': 4, 'cpu': {'mode': 'host-passthrough', 'numa_cell': [{'id': '0', 'cpus': '0-3', 'memory': '8388608', 'unit': 'KiB'}]}} mem_device_attrs = {'mem_model': 'virtio-mem', 'target': {'requested_unit': 'KiB', 'size': 1048576, 'node': 0, 'size_unit': 'KiB', 'requested_size': 524288, 'block_unit': 'KiB', 'block_size': 524288}} - requested_size = 1048576KiB + requested_size = 1048576KiB check_log_str = "MEMORY_DEVICE_SIZE_CHANGE.*virtiomem" virsh_opts = "--alias %s --requested-size ${requested_size}" diff --git a/libvirt/tests/cfg/memory/nvdimm.cfg b/libvirt/tests/cfg/memory/nvdimm.cfg index d7c0d003f15..3e636a835a3 100644 --- a/libvirt/tests/cfg/memory/nvdimm.cfg +++ b/libvirt/tests/cfg/memory/nvdimm.cfg @@ -2,10 +2,12 @@ type = nvdimm start_vm = no nvdimm_file_size = '512M' + cpuxml_mode = host-model + aarch64: + cpuxml_mode = host-passthrough variants: - back_file: nvdimm_file = /tmp/nvdimm - cpuxml_mode = host-model cpuxml_check = partial cpuxml_fallback = allow nvdimmxml_mem_model = nvdimm @@ -37,6 +39,8 @@ - default: - check_life_cycle: check_life_cycle = "yes" + error_msg_1 = "unsupported configuration: revert to external snapshot not supported yet" + error_msg_2 = "internal error: Invalid target domain state 'disk-snapshot'. Refusing snapshot reversion" - discard: check = discard nvdimmxml_discard = yes @@ -44,9 +48,10 @@ error_msg = 'discard is not supported for nvdimms' - pmem_alignsize: check = pmem_alignsize + pmem_support_check_cmd = "yum deplist qemu-kvm-core | grep libpmem" nvdimm_file_path = '/tmp/nvdimm' alignsize = 2048 - vm_attrs = {'max_mem_rt': 8192, 'max_mem_rt_slots': 8, 'max_mem_rt_unit': 'M', 'vcpu': 4, 'cpu': {'mode': 'host-model', 'numa_cell': [{'id': '0', 'cpus': '0-1', 'memory': '2097152', 'unit': 'K'}, {'id': '1', 'cpus': '2-3', 'memory': '2097152', 'unit': 'K'}]}} + vm_attrs = {'max_mem_rt': 8192, 'max_mem_rt_slots': 8, 'max_mem_rt_unit': 'M', 'vcpu': 4, 'cpu': {'mode': '${cpuxml_mode}', 'numa_cell': [{'id': '0', 'cpus': '0-1', 'memory': '2097152', 'unit': 'K'}, {'id': '1', 'cpus': '2-3', 'memory': '2097152', 'unit': 'K'}]}} mem_device_attrs = {'mem_model': 'nvdimm', 'source': {'path': '${nvdimm_file_path}', 'alignsize': ${alignsize}, 'alignsize_unit': 'K', 'pmem': True}, 'target': {'size': 512, 'size_unit': 'M', 'node': 1, 'readonly': True, 'label': {'size': 128, 'size_unit': 'KiB'}}} qemu_checks = "align.*pmem" error_msg = "['pwrite.* failed: Operation not permitted', 'wrong fs type, bad option, bad superblock on /dev/pmem0']" @@ -113,7 +118,6 @@ nvdimmxml2_label_size = 128 nvdimmxml2_label_size_unit = KiB nvdimmxml2_address_slot = 1 - cpuxml_mode = host-model cpuxml_check = partial cpuxml_fallback = allow cpuxml_topology = {'sockets': '2', 'cores': '2', 'threads': '1'} diff --git a/libvirt/tests/cfg/memory/secure_dump.cfg b/libvirt/tests/cfg/memory/secure_dump.cfg new file mode 100644 index 00000000000..46fbe9e88fb --- /dev/null +++ b/libvirt/tests/cfg/memory/secure_dump.cfg @@ -0,0 +1,7 @@ +- secure_dump: + type = secure_dump + start_vm = yes + only s390-virtio + variants: + - decrypt: + comm_key = 0123456789012345678901234567890 diff --git a/libvirt/tests/cfg/virsh_cmd/domain/virsh_setmem.cfg b/libvirt/tests/cfg/memory/virsh_setmem.cfg similarity index 97% rename from libvirt/tests/cfg/virsh_cmd/domain/virsh_setmem.cfg rename to libvirt/tests/cfg/memory/virsh_setmem.cfg index 244957e7283..cb589bd33bb 100644 --- a/libvirt/tests/cfg/virsh_cmd/domain/virsh_setmem.cfg +++ b/libvirt/tests/cfg/memory/virsh_setmem.cfg @@ -17,6 +17,11 @@ # expected to fail on older libvirt. setmem_old_libvirt_fail = "no" take_regular_screendumps = no + reset_vm_memory = "yes" + s390-virtio: + reset_vm_memory = "no" + use_dmidecode = "no" + vm_attrs = {'memory': 4, 'memory_unit': 'GiB', 'current_mem': 4, 'current_mem_unit': 'GiB'} variants: - valid_options: # These should not fail diff --git a/libvirt/tests/cfg/migration/abort_precopy_migration/abort_by_domjobabort_on_target.cfg b/libvirt/tests/cfg/migration/abort_precopy_migration/abort_by_domjobabort_on_target.cfg index 81072bab160..fb3b4f5660d 100644 --- a/libvirt/tests/cfg/migration/abort_precopy_migration/abort_by_domjobabort_on_target.cfg +++ b/libvirt/tests/cfg/migration/abort_precopy_migration/abort_by_domjobabort_on_target.cfg @@ -27,6 +27,8 @@ virsh_migrate_dest_state = "running" virsh_migrate_src_state = "shut off" migrate_speed = "10" + aarch64: + migrate_speed = "15" stress_package = "stress" stress_args = "--cpu 8 --io 4 --vm 2 --vm-bytes 128M --timeout 20s" variants: @@ -36,9 +38,11 @@ virsh_migrate_options = '--live --verbose' variants: - with_precopy: - action_during_mig = '[{"func": "libvirt_network.check_established", "after_event": "iteration: '1'", "func_param": "params"}, {"func": "do_domjobabort", "func_param": "params", "need_sleep_time": "5"}]' + action_during_mig = '[{"func": "do_domjobabort", "after_event": "iteration: '1'", "func_param": "params", "need_sleep_time": "5"}]' domjobabort_err_msg = "cannot acquire state change lock .*held by monitor=remoteDispatchDomainMigratePrepare3Params" - with_postcopy: + func_supported_since_libvirt_ver = (8, 5, 0) postcopy_options = '--postcopy --timeout 10 --timeout-postcopy' - action_during_mig = '[{"func": "libvirt_network.check_established", "after_event": "iteration: '1'", "func_param": "params"}, {"func": "do_domjobabort", "func_param": "params", "need_sleep_time": "10"}]' + domjobabort_options = '--postcopy' + action_during_mig = '[{"func": "do_domjobabort", "after_event": "iteration: '1'", "func_param": "params", "need_sleep_time": "10"}]' domjobabort_err_msg = "cannot acquire state change lock .*held by monitor=remoteDispatchDomainMigrateFinish3Params" diff --git a/libvirt/tests/cfg/migration/async_job/abort_migration_with_wrong_api_flag.cfg b/libvirt/tests/cfg/migration/async_job/abort_migration_with_wrong_api_flag.cfg new file mode 100644 index 00000000000..6c0dd1972ba --- /dev/null +++ b/libvirt/tests/cfg/migration/async_job/abort_migration_with_wrong_api_flag.cfg @@ -0,0 +1,39 @@ +- migration.async_job.abort_migration_with_wrong_api_flag: + type = async_job + 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' + image_convert = 'no' + server_ip = "${migrate_dest_host}" + server_user = "root" + server_pwd = "${migrate_dest_pwd}" + check_network_accessibility_after_mig = "yes" + migrate_desturi_port = "16509" + migrate_desturi_type = "tcp" + virsh_migrate_desturi = "qemu+tcp://${migrate_dest_host}/system" + status_error = "no" + virsh_migrate_dest_state = "running" + virsh_migrate_src_state = "shut off" + domjobabort_on_src = "yes" + variants: + - abort_postcopy_migration_by_domjobabort_without_postcopy: + virsh_migrate_options = '--live --p2p --verbose --postcopy --timeout 3 --timeout-postcopy --postcopy-bandwidth 10 --bandwidth 10' + domjobabort_err_msg = "cannot abort migration in post-copy mode" + action_during_mig = '[{"func": "do_domjobabort", "after_event": "iteration: '1'", "func_param": "params", "need_sleep_time": "5"}, {"func": "set_migrate_speed_to_high", "func_param": "params"}]' + - abort_precopy_migration_by_domjobabort_with_postcopy: + domjobabort_err_msg = "current job is not outgoing migration in post-copy mode" + virsh_migrate_options = '--live --p2p --verbose --bandwidth 3' + domjobabort_options = "--postcopy" + action_during_mig = '[{"func": "do_domjobabort", "func_param": "params"}, {"func": "set_migrate_speed_to_high", "func_param": "params"}]' diff --git a/libvirt/tests/cfg/migration/async_job/migration_domjobinfo.cfg b/libvirt/tests/cfg/migration/async_job/migration_domjobinfo.cfg index eed5f6ccb47..1ffb3bb651a 100644 --- a/libvirt/tests/cfg/migration/async_job/migration_domjobinfo.cfg +++ b/libvirt/tests/cfg/migration/async_job/migration_domjobinfo.cfg @@ -36,11 +36,11 @@ virsh_migrate_options = '--live --verbose' variants: - with_precopy: - action_during_mig = '[{"func": "libvirt_monitor.check_domjobinfo_output", "after_event": "iteration: '1'", "func_param": "params", "need_sleep_time": "5"}, {"func": "set_migrate_speed_to_high", "func_param": "params"}]' expected_domjobinfo = {"src_items": {"str_items": {"Job type": "Unbounded", "Operation": "Outgoing migration"}, "int_items": {"Postcopy requests": "0"}, "all_items": ["Time elapsed", "Data processed", "Data remaining", "Data total", "Memory processed", "Memory remaining", "Memory total", "Memory bandwidth", "Dirty rate", "Page size", "Iteration", "Constant pages", "Normal pages", "Normal data", "Expected downtime", "Setup time"]}, "dest_items": {"error_msg": "migration statistics are available only on the source host"}} + action_during_mig = [{"func": "libvirt_monitor.check_domjobinfo_output", "after_event": "iteration: '1'", "func_param": {"vm_name": "${main_vm}", "expected_domjobinfo": ${expected_domjobinfo}, "remote_ip": "${server_ip}"}, "need_sleep_time": "5"}, {"func": "set_migrate_speed_to_high", "func_param": "params"}] expected_domjobinfo_complete = {"src_items": {"str_items": {"Job type": "Completed", "Operation": "Outgoing migration"}, "int_items": {"Postcopy requests": "0", "Memory remaining": "0", "Data remaining": "0", "Dirty rate": "0"}, "all_items": ["Time elapsed", "Data processed", "Data total", "Memory processed", "Memory total", "Memory bandwidth", "Page size", "Iteration", "Constant pages", "Normal pages", "Normal data", "Total downtime", "Setup time"]}, "dest_items": {"str_items": {"Job type": "Completed", "Operation": "Incoming migration"}, "int_items": {"Postcopy requests": "0", "Memory remaining": "0", "Data remaining": "0", "Dirty rate": "0"}, "all_items": ["Time elapsed", "Data processed", "Data total", "Memory processed", "Memory total", "Memory bandwidth", "Page size", "Iteration", "Constant pages", "Normal pages", "Normal data", "Total downtime", "Setup time"]}} - with_postcopy: postcopy_options = '--postcopy --timeout 10 --timeout-postcopy' - action_during_mig = '[{"func": "libvirt_monitor.check_domjobinfo_output", "after_event": "iteration: '1'", "func_param": "params", "need_sleep_time": "15"}, {"func": "set_migrate_speed_to_high", "func_param": "params"}]' expected_domjobinfo = {"src_items": {"str_items": {"Job type": "Unbounded", "Operation": "Outgoing migration"}, "all_items": ["Time elapsed", "Data processed", "Data remaining", "Data total", "Memory processed", "Memory remaining", "Memory total", "Memory bandwidth", "Dirty rate", "Page size", "Iteration", "Postcopy requests", "Constant pages", "Normal pages", "Normal data", "Expected downtime", "Setup time"]}, "dest_items": {"error_msg": "migration statistics are available only on the source host"}} + action_during_mig = [{"func": "libvirt_monitor.check_domjobinfo_output", "after_event": "iteration: '1'", "func_param": {"vm_name": "${main_vm}", "expected_domjobinfo": ${expected_domjobinfo}, "postcopy_options": "${postcopy_options}", "remote_ip": "${server_ip}"}, "need_sleep_time": "15"}, {"func": "set_migrate_speed_to_high", "func_param": "params"}] expected_domjobinfo_complete = {"src_items": {"str_items": {"Job type": "Completed", "Operation": "Outgoing migration"}, "int_items": {"Memory remaining": "0", "Data remaining": "0", "Dirty rate": "0"}, "all_items": ["Time elapsed", "Data processed", "Data total", "Memory processed", "Memory total", "Memory bandwidth", "Page size", "Iteration", "Postcopy requests", "Constant pages", "Normal pages", "Normal data", "Total downtime", "Setup time"]}, "dest_items": {"str_items": {"Job type": "None"}}} diff --git a/libvirt/tests/cfg/migration/async_ops/destroy_vm_during_finishphase.cfg b/libvirt/tests/cfg/migration/async_ops/destroy_vm_during_finishphase.cfg new file mode 100644 index 00000000000..08c0d9474ff --- /dev/null +++ b/libvirt/tests/cfg/migration/async_ops/destroy_vm_during_finishphase.cfg @@ -0,0 +1,55 @@ +- migration.async_ops.destroy_vm_during_finishphase: + type = destroy_vm_during_finishphase + 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 + start_vm = "yes" + 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}" + check_network_accessibility_after_mig = "yes" + migrate_desturi_port = "16509" + migrate_desturi_type = "tcp" + virsh_migrate_desturi = "qemu+tcp://${migrate_dest_host}/system" + status_error = "yes" + migrate_again_status_error = "no" + virsh_migrate_extra = "--bandwidth 10 --postcopy-bandwidth 10" + virsh_migrate_extra_mig_again = " " + variants: + - p2p: + virsh_migrate_options = '--live --p2p --verbose' + - non_p2p: + virsh_migrate_options = '--live --verbose' + variants: + - with_postcopy: + postcopy_options = '--postcopy' + variants: + - destroy_dst_vm: + expected_event_src = ["Suspended Post-copy", "Suspended Post-copy Error"] + expected_event_target = ["lifecycle.*Stopped Destroyed"] + expected_dest_state = "nonexist" + expected_src_state = "paused" + err_msg = "domain is not running" + action_during_mig = '[{"func": "virsh.migrate_postcopy", "func_param": "'%s' % params.get('migrate_main_vm')", "need_sleep_time": "10"}, {"func": "check_vm_status_during_mig", "func_param": {"vm_name": "${main_vm}", "src_state":"paused", "src_reason": "post-copy"}, "need_sleep_time": "5"}, {"func": "virsh.destroy", "func_param": {"name": "${main_vm}", "uri": "${virsh_migrate_desturi}"}}]' + - destroy_src_vm: + expected_event_src = ["Suspended Post-copy Error", "Stopped Destroyed"] + expected_event_target = ["Resumed Post-copy Error"] + expected_dest_state = "running" + expected_src_state = "shut off" + err_msg = "job 'migration in' failed in post-copy phase" + action_during_mig = '[{"func": "virsh.migrate_postcopy", "func_param": "'%s' % params.get('migrate_main_vm')", "need_sleep_time": "10"}, {"func": "check_vm_status_during_mig", "func_param": {"vm_name": "${main_vm}", "src_state":"paused", "src_reason": "post-copy"}, "need_sleep_time": "5"}, {"func": "virsh.destroy", "func_param": {"name": "${main_vm}"}}]' diff --git a/libvirt/tests/cfg/migration/async_ops/destroy_vm_during_performphase.cfg b/libvirt/tests/cfg/migration/async_ops/destroy_vm_during_performphase.cfg new file mode 100644 index 00000000000..08c1d9eb303 --- /dev/null +++ b/libvirt/tests/cfg/migration/async_ops/destroy_vm_during_performphase.cfg @@ -0,0 +1,65 @@ +- migration.async_ops.destroy_vm_during_performphase: + type = destroy_vm_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}" + check_network_accessibility_after_mig = "yes" + migrate_desturi_port = "16509" + migrate_desturi_type = "tcp" + virsh_migrate_desturi = "qemu+tcp://${migrate_dest_host}/system" + status_error = "yes" + migrate_again = "yes" + migrate_again_status_error = "no" + variants: + - p2p: + virsh_migrate_options = '--live --p2p --verbose' + - non_p2p: + virsh_migrate_options = '--live --verbose' + variants: + - with_precopy: + variants: + - destroy_dst_vm_before_vm_paused: + virsh_migrate_extra = "--bandwidth 1" + expected_event_src = ["migration-iteration"] + expected_event_target = ["lifecycle.*Stopped Destroyed"] + expected_dest_state = "nonexist" + expected_src_state = "running" + action_during_mig = [{"func": "virsh.destroy", "after_event": "iteration: '1'", "func_param": {"name": "${main_vm}", "uri": "${virsh_migrate_desturi}"}, "need_sleep_time": "1"}] + err_msg = "domain is not running|Unable to read from socket: Connection reset by peer|domain.* is not processing incoming migration" + virsh_migrate_extra_mig_again = " " + - destroy_dst_vm_after_vm_paused: + migrate_speed = "10" + action_during_mig = [{"func": "virsh.destroy", "after_event": "Suspended Migrated", "func_param": {"name": "${main_vm}", "uri": "${virsh_migrate_desturi}"}}] + virsh_migrate_extra = "--timeout 2 --timeout-suspend" + expected_event_src = ["lifecycle.*Suspended Migrated", "lifecycle.*Resumed Migrated"] + expected_event_target = ["lifecycle.*Stopped Destroyed"] + expected_dest_state = "nonexist" + expected_src_state = "running" + err_msg = "domain is no longer running|Unable to read from socket: Connection reset by peer|domain.* is not processing incoming migration" + - destroy_src_vm: + migrate_speed = "10" + virsh_migrate_extra = "--timeout 2 --timeout-suspend" + expected_event_src = ["lifecycle.*Stopped Destroyed"] + expected_event_target = ["lifecycle.*Started Migrated", "lifecycle.*Stopped Failed"] + expected_dest_state = "nonexist" + expected_src_state = "shut off" + action_during_mig = [{"func": "virsh.destroy", "after_event": "iteration: '1'", "func_param": {"name": "${main_vm}"}}] + err_msg = "domain is not running|internal error: QEMU unexpectedly closed the monitor" diff --git a/libvirt/tests/cfg/migration/async_ops/migrate_vm_again_during_migration.cfg b/libvirt/tests/cfg/migration/async_ops/migrate_vm_again_during_migration.cfg new file mode 100644 index 00000000000..886f17248d0 --- /dev/null +++ b/libvirt/tests/cfg/migration/async_ops/migrate_vm_again_during_migration.cfg @@ -0,0 +1,37 @@ +- migration.async_ops.migrate_vm_again_during_migration: + type = migrate_vm_again_during_migration + 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 = "16509" + migrate_desturi_type = "tcp" + virsh_migrate_desturi = "qemu+tcp://${migrate_dest_host}/system" + migrate_speed = "20" + do_migration_during_mig = "yes" + action_during_mig = [{"func": "do_migration", "after_event": "iteration: '1'", "func_param": "params"}] + status_error_during_mig = "yes" + err_msg_during_mig = "another migration job is already running for domain" + variants: + - p2p: + virsh_migrate_options = '--live --p2p --verbose' + - non_p2p: + virsh_migrate_options = '--live --verbose' diff --git a/libvirt/tests/cfg/migration/async_ops/pause_resume_vm_during_migration.cfg b/libvirt/tests/cfg/migration/async_ops/pause_resume_vm_during_migration.cfg new file mode 100644 index 00000000000..50ea21413cc --- /dev/null +++ b/libvirt/tests/cfg/migration/async_ops/pause_resume_vm_during_migration.cfg @@ -0,0 +1,45 @@ +- migration.async_ops.pause_resume_vm_during_migration: + type = pause_resume_vm_during_migration + 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" + check_network_accessibility_after_mig = "yes" + migrate_desturi_port = "16509" + migrate_desturi_type = "tcp" + virsh_migrate_desturi = "qemu+tcp://${migrate_dest_host}/system" + migrate_speed = "5" + action_during_mig = [{"func": "virsh.suspend", "after_event": "iteration: '1'", "func_param": {"name": "${main_vm}"}}, {"func": "check_resume", "func_param": "params"}] + variants: + - p2p: + virsh_migrate_options = '--live --p2p --verbose' + - non_p2p: + virsh_migrate_options = '--live --verbose' + variants: + - with_precopy: + expected_event_src = ["lifecycle.*: Suspended Migrated"] + resume_err_msg_src = "cannot acquire state change lock .*held by monitor=remoteDispatchDomainMigratePerform3Params" + resume_err_msg_target = "cannot acquire state change lock .*held by monitor=remoteDispatchDomainMigratePrepare3Params" + - with_postcopy: + postcopy_options = '--postcopy --timeout 5 --timeout-postcopy' + expected_event_src = ["lifecycle.*: Suspended Post-copy"] + resume_err_msg_src = "cannot acquire state change lock .*held by monitor=remoteDispatchDomainMigratePerform3Params" + resume_err_msg_target = "cannot acquire state change lock .*held by monitor=remoteDispatchDomainMigrateFinish3Params" diff --git a/libvirt/tests/cfg/migration/async_ops/query_info_during_migration.cfg b/libvirt/tests/cfg/migration/async_ops/query_info_during_migration.cfg new file mode 100644 index 00000000000..bc8d99f0eb1 --- /dev/null +++ b/libvirt/tests/cfg/migration/async_ops/query_info_during_migration.cfg @@ -0,0 +1,43 @@ +- migration.async_ops.query_info_during_migration: + type = query_info_during_migration + 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}" + check_network_accessibility_after_mig = "yes" + migrate_desturi_port = "16509" + migrate_desturi_type = "tcp" + virsh_migrate_desturi = "qemu+tcp://${migrate_dest_host}/system" + status_error = "no" + action_during_mig = '[{"func": "execute_statistics_command", "after_event": "iteration: '1'", "func_param": "params"}]' + target_dev = "vdb" + loop_disk_type = "block" + block_device = "${nfs_mount_dir}/query_info_test.img" + migrate_speed = "15" + loop_time = "10" + variants: + - p2p: + virsh_migrate_options = '--live --p2p --verbose' + - non_p2p: + virsh_migrate_options = '--live --verbose' + variants: + - with_precopy: + - with_postcopy: + postcopy_options = '--postcopy --timeout 10 --timeout-postcopy' diff --git a/libvirt/tests/cfg/migration/destructive_operations_around_live_migration/kill_qemu_during_finishphase.cfg b/libvirt/tests/cfg/migration/destructive_operations_around_live_migration/kill_qemu_during_finishphase.cfg new file mode 100644 index 00000000000..b55789a6f36 --- /dev/null +++ b/libvirt/tests/cfg/migration/destructive_operations_around_live_migration/kill_qemu_during_finishphase.cfg @@ -0,0 +1,54 @@ +- migration.destructive_operations_around_live_migration.kill_qemu_during_finishphase: + type = kill_qemu_during_finishphase + 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}" + check_network_accessibility_after_mig = "yes" + migrate_desturi_port = "16509" + migrate_desturi_type = "tcp" + virsh_migrate_desturi = "qemu+tcp://${migrate_dest_host}/system" + status_error = "yes" + migrate_again = "yes" + service_name = "qemu-kvm" + migrate_again_status_error = "no" + virsh_migrate_extra = "--postcopy-bandwidth 10 --bandwidth 10" + virsh_migrate_extra_mig_again = " " + action_during_mig = '[{"func": "virsh.migrate_postcopy", "func_param": "'%s' % params.get('migrate_main_vm')", "need_sleep_time": "10"}, {"func": "check_vm_status_during_mig", "func_param": {"vm_name": "${main_vm}", "src_state":"paused", "src_reason": "post-copy"}, "need_sleep_time": "5"}, {"func": "libvirt_service.kill_service", "func_param": "params"}]' + variants: + - p2p: + virsh_migrate_options = '--live --p2p --verbose' + - non_p2p: + virsh_migrate_options = '--live --verbose' + variants: + - with_postcopy: + postcopy_options = "--postcopy" + variants test_case: + - kill_dest_qemu: + service_on_dst = "yes" + expected_event_src = ["Suspended Post-copy", "Suspended Post-copy Error"] + expected_event_target = ["Stopped Failed"] + expected_dest_state = "nonexist" + expected_src_state = "paused" + - kill_src_qemu: + expected_dest_state = "running" + expected_src_state = "shut off" + expected_event_src = ["Suspended Post-copy", "Stopped Failed"] + expected_event_target = ["Resumed Post-copy Error"] diff --git a/libvirt/tests/cfg/migration/destructive_operations_around_live_migration/kill_qemu_during_performphase.cfg b/libvirt/tests/cfg/migration/destructive_operations_around_live_migration/kill_qemu_during_performphase.cfg new file mode 100644 index 00000000000..cdcbc4a2b73 --- /dev/null +++ b/libvirt/tests/cfg/migration/destructive_operations_around_live_migration/kill_qemu_during_performphase.cfg @@ -0,0 +1,69 @@ +- migration.destructive_operations_around_live_migration.kill_qemu_during_performphase: + type = kill_qemu_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}" + check_network_accessibility_after_mig = "yes" + migrate_desturi_port = "16509" + migrate_desturi_type = "tcp" + virsh_migrate_desturi = "qemu+tcp://${migrate_dest_host}/system" + status_error = "yes" + migrate_again = "yes" + service_name = "qemu-kvm" + migrate_again_status_error = "no" + migrate_speed = "10" + simple_disk_check_after_mig = "yes" + variants: + - p2p: + virsh_migrate_options = '--live --p2p --verbose' + - non_p2p: + virsh_migrate_options = '--live --verbose' + variants: + - with_precopy: + variants test_case: + - kill_dest_qemu_before_vm_paused: + service_on_dst = "yes" + expected_event_src = ["migration-iteration"] + expected_event_target = ["lifecycle", "lifecycle.*: Stopped Failed"] + action_during_mig = '[{"func": "libvirt_service.kill_service", "func_param": "params", "need_sleep_time": "1"}]' + expected_dest_state = "nonexist" + expected_src_state = "running" + migrate_speed = "1" + err_msg = "QEMU unexpectedly closed the monitor|Unable to read from socket: Connection reset by peer|Channel error: Input/output error" + check_disk_on_dest = "no" + virsh_migrate_extra = "--bandwidth 1000" + - kill_dest_qemu_after_vm_paused: + service_on_dst = "yes" + expected_event_src = ["migration-iteration", "lifecycle.*: Suspended Migrated", "lifecycle.*: Resumed Migrated"] + expected_event_target = ["lifecycle", "lifecycle.*: Stopped Failed"] + action_during_mig = '[{"func": "libvirt_service.kill_service", "after_event": "migration-iteration", "func_param": "params"}]' + expected_dest_state = "nonexist" + expected_src_state = "running" + virsh_migrate_extra = "--timeout 2 --timeout-suspend --bandwidth 1000" + err_msg = "QEMU unexpectedly closed the monitor|Unable to read from socket: Connection reset by peer|Channel error: Input/output error" + - kill_src_qemu: + expected_dest_state = "nonexist" + expected_src_state = "shut off" + expected_event_src = ["migration-iteration", "lifecycle.*: Stopped Failed"] + expected_event_target = ["lifecycle", "lifecycle.*: Stopped Failed"] + action_during_mig = '[{"func": "libvirt_service.kill_service", "after_event": "migration-iteration", "func_param": "params"}]' + virsh_migrate_extra = "--bandwidth 1000" + err_msg = "operation failed: domain is not running" 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/cfg/migration/guest_lifecycle_operations_during_migration/migration_poweroff_vm.cfg b/libvirt/tests/cfg/migration/guest_lifecycle_operations_during_migration/migration_poweroff_vm.cfg index fa12a1e9d16..074a4e460ac 100644 --- a/libvirt/tests/cfg/migration/guest_lifecycle_operations_during_migration/migration_poweroff_vm.cfg +++ b/libvirt/tests/cfg/migration/guest_lifecycle_operations_during_migration/migration_poweroff_vm.cfg @@ -1,11 +1,6 @@ - migration.guest_lifecycle_operations_during_migration.migration_poweroff_vm: type = migration_poweroff_vm 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 @@ -20,6 +15,9 @@ server_ip = "${migrate_dest_host}" server_user = "root" server_pwd = "${migrate_dest_pwd}" + client_ip = "${migrate_source_host}" + client_user = "root" + client_pwd = "${migrate_source_pwd}" status_error = "yes" check_network_accessibility_after_mig = "yes" migrate_desturi_port = "16509" @@ -27,11 +25,10 @@ stress_package = "stress" stress_args = "--cpu 8 --io 4 --vm 2 --vm-bytes 128M --timeout 20s" virsh_migrate_desturi = "qemu+tcp://${migrate_dest_host}/system" - action_during_mig = '[{"func": "libvirt_network.check_established", "after_event": "iteration: '1'", "func_param": 'params'}, {"func": "poweroff_vm", "func_param": "params", "need_sleep_time": "70"}]' err_msg = "error: operation failed: domain is not running" - virsh_migrate_extra = "--bandwidth 5" test_case = "poweroff_vm" - + action_during_mig = '[{"func": "poweroff_vm", "func_param": "params", "need_sleep_time": "70"}]' + virsh_migrate_src_state = "shut off" variants: - p2p: virsh_migrate_options = '--live --p2p --verbose' @@ -39,8 +36,24 @@ virsh_migrate_options = '--live --verbose' variants: - with_precopy: - virsh_migrate_src_state = "shut off" - with_postcopy: - postcopy_options = '--postcopy --timeout 10 --timeout-postcopy --postcopy-bandwidth 5' - virsh_migrate_src_state = "paused" - poweroff_vm_dest = "yes" + postcopy_options = '--postcopy --timeout 5 --timeout-postcopy --postcopy-bandwidth 5' + variants: + - nbd: + virsh_migrate_extra = "--bandwidth 5 --copy-storage-all --migrate-disks vda" + setup_nfs = "no" + nfs_mount_dir = + setup_local_nfs = "no" + storage_type = "" + - non_nbd: + virsh_migrate_extra = "--bandwidth 5" + storage_type = 'nfs' + setup_local_nfs = 'yes' + disk_type = "file" + disk_source_protocol = "netfs" + mnt_path_name = ${nfs_mount_dir} + with_postcopy: + poweroff_vm_dest = "yes" + virsh_migrate_src_state = "paused" + with_precopy: + err_msg = "domain is not running|internal error: QEMU unexpectedly closed the monitor" diff --git a/libvirt/tests/cfg/migration/memory_copy_mode/migration_memory_copy_mode_precopy.cfg b/libvirt/tests/cfg/migration/memory_copy_mode/migration_memory_copy_mode_precopy.cfg deleted file mode 100644 index f23c2e293a9..00000000000 --- a/libvirt/tests/cfg/migration/memory_copy_mode/migration_memory_copy_mode_precopy.cfg +++ /dev/null @@ -1,45 +0,0 @@ -- migration.migration_memory_copy_mode.precopy: - type = migration_memory_copy_mode - 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" - check_network_accessibility_after_mig = "yes" - migrate_desturi_port = "16509" - migrate_desturi_type = "tcp" - virsh_migrate_desturi = "qemu+tcp://${migrate_dest_host}/system" - - variants test_case: - - default: - migrate_speed = "10" - stress_package = "stress" - stress_args = "--cpu 8 --io 4 --vm 2 --vm-bytes 128M --timeout 20s" - port_to_check = "16509" - check_local_port = "yes" - migrate_speed_high = '8796093022207' - action_during_mig = '[{"func": "libvirt_network.check_established", "after_event": "iteration: \'1\'", "func_param": "params"}, {"func": "set_migrate_speed_to_high", "func_param": "params"}]' - variants: - - p2p: - service_to_check = "virtqemud|libvirtd" - virsh_migrate_options = '--live --p2p --verbose' - - non_p2p: - service_to_check = "virsh" - virsh_migrate_options = '--live --verbose' diff --git a/libvirt/tests/cfg/migration/memory_copy_mode/postcopy.cfg b/libvirt/tests/cfg/migration/memory_copy_mode/postcopy.cfg new file mode 100644 index 00000000000..54229467656 --- /dev/null +++ b/libvirt/tests/cfg/migration/memory_copy_mode/postcopy.cfg @@ -0,0 +1,55 @@ +- migration.memory_copy_mode.postcopy: + type = memory_copy_mode + 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" + check_network_accessibility_after_mig = "yes" + migrate_desturi_port = "16509" + migrate_desturi_type = "tcp" + virsh_migrate_desturi = "qemu+tcp://${migrate_dest_host}/system" + stress_package = "stress" + stress_args = "--cpu 8 --io 4 --vm 2 --vm-bytes 128M --timeout 20s" + test_case = "postcopy" + libvirtd_file_type = "virtqemud" + libvirtd_debug_level = "1" + libvirtd_debug_filters = "1:*" + libvirtd_debug_file = '/var/log/libvirt/virtqemud.log' + check_str_local_log = '['{"capability":"postcopy-preempt","state":true}']' + expected_event_src = ["lifecycle.*Suspended Migrated", "lifecycle.*Suspended Post-copy", "lifecycle.*Stopped Migrated", "job-completed"] + expected_event_target = ["event 'lifecycle'.*: Started Migrated", "event 'lifecycle'.*: Resumed Post-copy", "event 'lifecycle'.*: Resumed Migrated"] + variants: + - p2p: + virsh_migrate_options = '--live --p2p --verbose' + - non_p2p: + virsh_migrate_options = '--live --verbose' + variants: + - default_postcopy: + postcopy_options = '--postcopy' + expected_event_src = ["lifecycle.*Suspended Migrated", "lifecycle.*Stopped Migrated", "job-completed"] + expected_event_target = ["event 'lifecycle'.*: Started Migrated", "event 'lifecycle'.*: Resumed Migrated"] + - migrate_postcopy: + postcopy_options = '--postcopy' + action_during_mig = '[{"func": "virsh.migrate_postcopy", "after_event": "iteration: '1'", "func_param": "'%s' % params.get('migrate_main_vm')"}]' + - postcopy_after_precopy: + postcopy_options = '--postcopy --postcopy-after-precopy' + - timeout_postcopy: + postcopy_options = '--postcopy --timeout 10 --timeout-postcopy' diff --git a/libvirt/tests/cfg/migration/memory_copy_mode/migration_memory_copy_mode_postcopy.cfg b/libvirt/tests/cfg/migration/memory_copy_mode/precopy.cfg similarity index 56% rename from libvirt/tests/cfg/migration/memory_copy_mode/migration_memory_copy_mode_postcopy.cfg rename to libvirt/tests/cfg/migration/memory_copy_mode/precopy.cfg index d79a1e7517b..aa2318a5582 100644 --- a/libvirt/tests/cfg/migration/memory_copy_mode/migration_memory_copy_mode_postcopy.cfg +++ b/libvirt/tests/cfg/migration/memory_copy_mode/precopy.cfg @@ -1,5 +1,5 @@ -- migration.migration_memory_copy_mode: - type = migration_memory_copy_mode +- migration.memory_copy_mode.precopy: + type = memory_copy_mode migration_setup = 'yes' storage_type = 'nfs' setup_local_nfs = 'yes' @@ -26,25 +26,19 @@ migrate_desturi_port = "16509" migrate_desturi_type = "tcp" virsh_migrate_desturi = "qemu+tcp://${migrate_dest_host}/system" + migrate_speed = "10" stress_package = "stress" stress_args = "--cpu 8 --io 4 --vm 2 --vm-bytes 128M --timeout 20s" + port_to_check = "16509" + check_local_port = "yes" + migrate_speed_high = '8796093022207' + action_during_mig = '[{"func": "libvirt_network.check_established", "after_event": "iteration: \'1\'", "func_param": "params"}, {"func": "set_migrate_speed_to_high", "func_param": "params"}]' + expected_event_src = ["migration-iteration.*iteration: '1'", "lifecycle.*Suspended Migrated", "lifecycle.*Stopped Migrated", "job-completed"] + expected_event_target = ["event 'lifecycle'.*: Started Migrated", "event 'lifecycle'.*: Resumed Migrated"] variants: - p2p: + service_to_check = "virtqemud|libvirtd" virsh_migrate_options = '--live --p2p --verbose' - non_p2p: + service_to_check = "virsh" virsh_migrate_options = '--live --verbose' - variants test_case: - - postcopy_migration: - variants: - - default_postcopy: - postcopy_options = '--postcopy' - - migrate_postcopy: - expected_event_src = 'Suspended Post-copy' - postcopy_options = '--postcopy' - action_during_mig = '[{"func": "virsh.migrate_postcopy", "after_event": "iteration: '1'", "func_param": "'%s' % params.get('migrate_main_vm')"}]' - - postcopy_after_precopy: - expected_event_src = 'Suspended Post-copy' - postcopy_options = '--postcopy --postcopy-after-precopy' - - timeout_postcopy: - expected_event_src = 'Suspended Post-copy' - postcopy_options = '--postcopy --timeout 10 --timeout-postcopy' diff --git a/libvirt/tests/cfg/migration/migrate_graphics.cfg b/libvirt/tests/cfg/migration/migrate_graphics.cfg index 422f3e846d8..63c18164dd6 100644 --- a/libvirt/tests/cfg/migration/migrate_graphics.cfg +++ b/libvirt/tests/cfg/migration/migrate_graphics.cfg @@ -1,5 +1,6 @@ - migration.migrate_graphics: type = migrate_graphics + start_vm = "yes" migration_setup = 'yes' storage_type = 'nfs' setup_local_nfs = 'yes' diff --git a/libvirt/tests/cfg/migration/migrate_mem.cfg b/libvirt/tests/cfg/migration/migrate_mem.cfg index 5f35452bc72..754aaf1b423 100644 --- a/libvirt/tests/cfg/migration/migrate_mem.cfg +++ b/libvirt/tests/cfg/migration/migrate_mem.cfg @@ -28,11 +28,12 @@ start_vm = "no" variants case: - mem_device: + no s390-virtio cpuxml_cpu_mode = "host-model" + aarch64: + cpuxml_cpu_mode = "host-passthrough" cpuxml_fallback = "allow" cpuxml_model = "qemu64" - cpu_feature = "svm" - cpu_feature_policy = "disable" cpuxml_numa_cell = [{'id': '0', 'cpus': '0-1', 'memory': '1024', 'unit': 'MiB', 'discard': 'yes'}, {'id': '1', 'cpus': '2-3', 'memory': '1024', 'unit': 'MiB'}] setvm_max_mem_rt_slots = "16" setvm_max_mem_rt = 8192 @@ -52,11 +53,14 @@ check_str_local_log = 'Unsupported migration cookie feature memory-hotplug' str_in_log = False - mem_balloon: - ballooned_mem = "716800" + ballooned_mem = "1572864" + s390-virtio: + ballooned_mem = "716800" - mem_nvdimm: + no s390-virtio nvdimm_file_path = '${nfs_mount_dir}/nvdimm' nvdimm_file_size = '512M' - vm_attrs = {'max_mem_rt': 4096, 'max_mem_rt_slots': 16, 'max_mem_rt_unit': 'M', 'vcpu': 4, 'cpu': {'mode': 'host-model', 'numa_cell': [{'id': '0', 'cpus': '0-1', 'memory': '1024', 'unit': 'M'}, {'id': '1', 'cpus': '2-3', 'memory': '1024', 'unit': 'M'}]}} + vm_attrs = {'max_mem_rt': 4096, 'max_mem_rt_slots': 16, 'max_mem_rt_unit': 'M', 'vcpu': 4, 'cpu': {'mode': 'host-passthrough', 'numa_cell': [{'id': '0', 'cpus': '0-1', 'memory': '1024', 'unit': 'M'}, {'id': '1', 'cpus': '2-3', 'memory': '1024', 'unit': 'M'}]}} mem_device_attrs = {'mem_model': 'nvdimm', 'mem_access': 'shared', 'source': {'path': '${nvdimm_file_path}'}, 'target': {'size': 512, 'size_unit': 'M', 'node': 1, 'label': {'size': 256, 'size_unit': 'KiB'}}} qemu_checks = "nvdimm=on.*mem-path=${nvdimm_file_path.*share=yes.*size=536870912.*device.*nvdimm,node=1,label-size=262144}" migrate_vm_back = "yes" diff --git a/libvirt/tests/cfg/migration/migrate_network.cfg b/libvirt/tests/cfg/migration/migrate_network.cfg index 94ae10bf57f..1e9216bfdd9 100644 --- a/libvirt/tests/cfg/migration/migrate_network.cfg +++ b/libvirt/tests/cfg/migration/migrate_network.cfg @@ -1,5 +1,6 @@ - virsh.migrate_network: type = migrate_network + start_vm = "yes" # Console output can only be monitored via virsh console output only_pty = True take_regular_screendumps = no @@ -15,6 +16,8 @@ virsh_migrate_dest_state = running virsh_migrate_src_state = running virsh_migrate_options = "--live --p2p --verbose" + host_iface_src = + host_iface_dst = # Local URI virsh_migrate_connect_uri = "qemu:///system" migrate_vm_back = "yes" diff --git a/libvirt/tests/cfg/migration/migrate_options_shared.cfg b/libvirt/tests/cfg/migration/migrate_options_shared.cfg index c5e9714ed8e..44ce5234de8 100644 --- a/libvirt/tests/cfg/migration/migrate_options_shared.cfg +++ b/libvirt/tests/cfg/migration/migrate_options_shared.cfg @@ -23,12 +23,9 @@ virsh_migrate_dest_state = running virsh_migrate_src_state = running virsh_migrate_libvirtd_state = 'on' - # Local URI virsh_migrate_connect_uri = "qemu:///system" - log_outputs = "/var/log/libvirt/libvirtd.log" - variants: - with_postcopy: postcopy_options = "--postcopy" @@ -319,6 +316,7 @@ actions_after_migration = "save_restore" actions_during_migration = "setmaxdowntime,setmigratepostcopy" - vtpm_emulator: + no s390-virtio tpm_args = "{"tpm_model": "tpm-crb", "backend_type": "emulator", "backend_version": "2.0"}" pseries: tpm_args = "{"tpm_model": "tpm-spapr", "backend_type": "emulator", "backend_version": "2.0"}" @@ -453,6 +451,7 @@ server_cn = "test.com.cn" virsh_migrate_extra = "--tls --tls-destination ${server_cn}" - vtpm_emulator: + no s390-virtio only without_postcopy tpm_args = "{"tpm_model": "tpm-crb", "backend_type": "emulator", "backend_version": "2.0"}" update_tpm_secret = yes @@ -487,12 +486,16 @@ virsh_migrate_options = "--live --p2p --tunnelled --verbose" variants: - vtpm_emulator: + no s390-virtio tpm_args = "{"tpm_model": "tpm-crb", "backend_type": "emulator", "backend_version": "2.0"}" update_tpm_secret = yes src_secret_value = "sec value test" dst_secret_value = ${src_secret_value} cmd_in_vm_after_migration = "tpm2_getrandom 10" - timer: + no s390-virtio + aarch64: + armvtimer = {"clock": {"offset": "utc", "timers": [{"name": "armvtimer", "tickpolicy": "discard"}]}} timer_migration = "yes" asynch_migrate = "yes" actions_during_migration = "setmaxdowntime" @@ -544,6 +547,7 @@ client_cn = "ENTER.YOUR.CLIENT_CN" disable_verify_peer = "yes" - vtpm_emulator: + no s390-virtio only without_postcopy tpm_args = "{"tpm_model": "tpm-crb", "backend_type": "emulator", "backend_version": "2.0"}" update_tpm_secret = yes @@ -610,7 +614,7 @@ variants: - without_option: virsh_migrate_extra = "--tls" - err_msg = "error: internal error: qemu unexpectedly closed the monitor|Domain not found|QEMU unexpectedly closed the monitor" + err_msg = "error: internal error: qemu unexpectedly closed the monitor|Domain not found|QEMU unexpectedly closed the monitor|Certificate does not match the hostname" - empty_str: virsh_migrate_extra = "--tls --tls-destination ''" err_msg = "error: Failed to get option 'tls-destination': Option argument is empty" @@ -619,7 +623,7 @@ err_msg = "error: Option --tls is required by option --tls-destination" - incorrect_hostname: virsh_migrate_extra = "--tls --tls-destination fake${server_cn}" - err_msg = "error: internal error: qemu unexpectedly closed the monitor|Domain not found|QEMU unexpectedly closed the monitor" + err_msg = "error: internal error: qemu unexpectedly closed the monitor|Domain not found|QEMU unexpectedly closed the monitor|Certificate does not match the hostname" - tunnelled_migration: only without_postcopy virsh_migrate_options = "--live --p2p --tunnelled --verbose" diff --git a/libvirt/tests/cfg/migration/migrate_service_control.cfg b/libvirt/tests/cfg/migration/migrate_service_control.cfg index 556b7c9f0e9..85fccaecc76 100644 --- a/libvirt/tests/cfg/migration/migrate_service_control.cfg +++ b/libvirt/tests/cfg/migration/migrate_service_control.cfg @@ -40,7 +40,7 @@ - kill_qemu_on_dst: service_name = "qemu-kvm" service_on_dst = "yes" - err_msg = 'qemu unexpectedly closed the monitor|domain is no longer running|Domain not found|Unable to write to socket: Bad file descriptor' + err_msg = 'qemu unexpectedly closed the monitor|domain is no longer running|Domain not found|Unable to write to socket: Bad file descriptor|Channel error: Input/output error|QEMU unexpectedly closed the monitor' - kill_libvirtd_on_src: service_name = "libvirtd" err_msg = 'End of file while reading data: Input/output error' diff --git a/libvirt/tests/cfg/migration/migrate_vm.cfg b/libvirt/tests/cfg/migration/migrate_vm.cfg index d4f713ff4ee..4f6acd163bc 100644 --- a/libvirt/tests/cfg/migration/migrate_vm.cfg +++ b/libvirt/tests/cfg/migration/migrate_vm.cfg @@ -11,10 +11,10 @@ client_user = "root" client_pwd = "${migrate_source_pwd}" start_vm = "no" + storage_type = transport = "ssh" port = "22" client = "ssh" - start_vm = "no" ssh_port = "${port}" # setup NFS test environment nfs_client_ip = "${server_ip}" @@ -174,12 +174,9 @@ migration_timeout = 600 virsh_options = "--live --verbose" - netperf_network: - netperf_version = "netperf-2.6.0-1" - netperf_source = "shared/deps/netperf/${netperf_version}.tar.bz2" - client_path = "/var/tmp/" - server_path = "/var/tmp/" - netperf_test_duration = 300 - netperf_para_sessions = 1 + netperf_network = "yes" + netperf_cmd_dst = "netperf -H ${client_ip} -l 600 > /dev/null 2>&1 &" + netperf_cmd_src = "netperf -H ${server_ip} -l 600 &" migration_timeout = 600 virsh_options = "--live --verbose" - iothread: @@ -716,7 +713,7 @@ config_libvirtd = "yes" variants: - no_migrate_disks: - err_msg = "error: internal error: unable to execute QEMU command '(nbd-server-add|block-export-add)': Block node is read-only" + err_msg = "error: internal error: unable to execute QEMU command '(nbd-server-add|block-export-add)'" virsh_options = "--live --verbose --copy-storage-all" - create_neither_target_pool_nor_image: create_target_image = "no" @@ -749,8 +746,9 @@ variants: - copy_storage_inc: virsh_options = "--live --verbose --copy-storage-inc" - err_msg = "error: Operation not supported: pre-creation of storage targets for incremental storage migration is not supported" + err_msg = "error: Operation not supported: pre-creation of storage targets for incremental storage migration is not supported|error: Operation not supported: pre-creation of storage target.*for incremental storage migration of .* is not supported" - backing_file_with_copy_storage_inc: + no s390-virtio create_target_image = "no" setup_nfs = "yes" enable_virt_use_nfs = "yes" @@ -770,7 +768,7 @@ check_disk_size_cmd = "qemu-img info ${new_disk_source}" local_image_source = "${new_disk_source}" virsh_options = "--live --verbose --copy-storage-inc" - err_msg = "error: Operation not supported: pre-creation of storage targets for incremental storage migration is not supported" + err_msg = "error: Operation not supported: pre-creation of storage targets for incremental storage migration is not supported|error: Operation not supported: pre-creation of storage target.*for incremental storage migration of .* is not supported" - mutually_exclusive_options: create_target_image = "yes" virsh_options = "--live --persistent --verbose --copy-storage-all --copy-storage-inc" @@ -790,7 +788,7 @@ virsh_options = "--live --verbose --persistent --copy-storage-all" - copy_storage_inc: virsh_options = "--live --verbose --persistent --copy-storage-inc" - err_msg = "error: Operation not supported: pre-creation of storage targets for incremental storage migration is not supported" + err_msg = "error: Operation not supported: pre-creation of storage targets for incremental storage migration is not supported|error: Operation not supported: pre-creation of storage target.*for incremental storage migration of .* is not supported" - cache_mode: only without_postcopy nfs_mount_dir = @@ -831,19 +829,19 @@ hard_limit_value = "1048576" swap_hard_limit_value = "2097152" memtune_options = "--hard-limit ${hard_limit_value} --swap-hard-limit ${swap_hard_limit_value} --config" - err_msg = "unable to execute QEMU command 'migrate-incoming': RDMA ERROR: could not create rdma event channel" + err_msg = "unable to execute QEMU command 'migrate-incoming': RDMA ERROR: could not create rdma event channel|unable to execute QEMU command 'migrate-incoming': Migration requires multi-channel URIs|unable to execute QEMU command 'migrate-incoming': unknown migration protocol: rdma" - no_rdma_env_rdma_pin_all: hard_limit_value = "2097152" swap_hard_limit_value = "2097152" memtune_options = "--hard-limit ${hard_limit_value} --swap-hard-limit ${swap_hard_limit_value} --config" virsh_options = "--live --verbose --rdma-pin-all --migrateuri rdma://${server_ip} --listen-address 0.0.0.0" - err_msg = "unable to execute QEMU command 'migrate-incoming': RDMA ERROR: could not create rdma event channel" + err_msg = "unable to execute QEMU command 'migrate-incoming': RDMA ERROR: could not create rdma event channel|unable to execute QEMU command 'migrate-incoming': Migration requires multi-channel URIs|unable to execute QEMU command 'migrate-incoming': unknown migration protocol: rdma" - no_rdma_env_turn_off_rdma_pin_all: hard_limit_value = "1048576" swap_hard_limit_value = "1048576" memtune_options = "--hard-limit ${hard_limit_value} --swap-hard-limit ${swap_hard_limit_value} --config" virsh_options = "--live --verbose --rdma-pin-all --migrateuri rdma://${server_ip}" - err_msg = "unable to execute QEMU command 'migrate-incoming': RDMA ERROR: could not create rdma event channel" + err_msg = "unable to execute QEMU command 'migrate-incoming': RDMA ERROR: could not create rdma event channel|unable to execute QEMU command 'migrate-incoming': Migration requires multi-channel URIs|unable to execute QEMU command 'migrate-incoming': unknown migration protocol: rdma" - cross_rhel_platform_migration: # only work well on RHEL platform migration_timeout = 600 diff --git a/libvirt/tests/cfg/migration/migrate_vm_in_various_status/migrate_paused_vm.cfg b/libvirt/tests/cfg/migration/migrate_vm_in_various_status/migrate_paused_vm.cfg index db8ebf03406..6d607cc2f0d 100644 --- a/libvirt/tests/cfg/migration/migrate_vm_in_various_status/migrate_paused_vm.cfg +++ b/libvirt/tests/cfg/migration/migrate_vm_in_various_status/migrate_paused_vm.cfg @@ -33,6 +33,8 @@ - migration_succeeds: status_error = "no" virsh_migrate_dest_state = "paused" + migrate_vm_back = "yes" + src_state = "paused" - cancel_migration: status_error = "yes" migrate_speed = "5" diff --git a/libvirt/tests/cfg/migration/migrate_with_panic_device.cfg b/libvirt/tests/cfg/migration/migrate_with_panic_device.cfg new file mode 100644 index 00000000000..0dd426652f9 --- /dev/null +++ b/libvirt/tests/cfg/migration/migrate_with_panic_device.cfg @@ -0,0 +1,33 @@ +- migrate.panic_device: + type = migrate_with_panic_device + 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" + migrate_desturi_port = "22" + migrate_desturi_type = "ssh" + virsh_migrate_desturi = "qemu+ssh://${migrate_dest_host}/system" + image_convert = 'no' + server_ip = "${migrate_dest_host}" + server_user = "${remote_user}" + server_pwd = "${migrate_dest_pwd}" + start_vm = 'no' + crash_action = "coredump-restart" + expected_match = "crashed.*(panicked).*" + dump_file_path = "/var/lib/libvirt/qemu/dump" + panic_dev = {"model": "isa", "addr_type": "isa", "addr_iobase": "0x505"} + aarch64: + panic_dev = {"model": "pvpanic", "addr_type": "pci"} diff --git a/libvirt/tests/cfg/migration/migration_misc/canonical_paths_in_shared_filesystems.cfg b/libvirt/tests/cfg/migration/migration_misc/canonical_paths_in_shared_filesystems.cfg new file mode 100644 index 00000000000..e5a7458e34a --- /dev/null +++ b/libvirt/tests/cfg/migration/migration_misc/canonical_paths_in_shared_filesystems.cfg @@ -0,0 +1,67 @@ +- migration.migration_misc.canonical_paths_in_shared_filesystems: + type = canonical_paths_in_shared_filesystems + migration_setup = 'yes' + storage_type = '' + setup_nfs = 'no' + setup_local_nfs = 'no' + disk_type = "file" + disk_source_protocol = "netfs" + # 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' + vms = avocado-vt-vm1 vm2 + server_ip = "${migrate_dest_host}" + server_user = "root" + server_pwd = "${migrate_dest_pwd}" + client_ip = "${migrate_source_host}" + client_user = "root" + client_pwd = "${migrate_source_pwd}" + status_error = "no" + migrate_desturi_port = "22" + migrate_desturi_type = "ssh" + virsh_migrate_desturi = "qemu+ssh://${migrate_dest_host}/system" + start_vm = "no" + nfs_mount_options = "bind" + export_dir = "/nfs" + nfs_server_ip = "${migrate_source_host}" + images_path = "/var/lib/libvirt/images" + nvram_path = "/var/lib/libvirt/qemu/nvram" + swtpm_path = "/var/lib/libvirt/swtpm" + nfs_mount_dir = "${images_path}" + mnt_path_name = "${images_path}" + nfs_images_path = "${export_dir}/libvirt/images" + nfs_nvram_path = "${export_dir}/libvirt/nvram" + nfs_swtpm_path = "${export_dir}/libvirt/swtpm" + mount_images_path = "${nfs_server_ip}:${export_dir}/libvirt/images" + mount_nvram_path = "${nfs_server_ip}:${export_dir}/libvirt/nvram" + mount_swtpm_path = "${nfs_server_ip}:${export_dir}/libvirt/swtpm" + qemu_conf_dest = '{r".*shared_filesystems\s*=.*": "shared_filesystems = [\"${images_path}\", \"${nvram_path}\", \"${swtpm_path}\"]"}' + qemu_conf_src = '{"shared_filesystems": "[\"${images_path}\", \"${nvram_path}\", \"${swtpm_path}\"]"}' + migrate_vm_back = "yes" + variants: + - with_tpm: + tpm_args = "{"tpm_model": "tpm-crb", "backend_type": "emulator", "backend_version": "2.0"}" + - without_tpm: + variants boot_type: + - bios: + firmware_type = "seabios" + os_dict = {'type': 'hvm', 'boots': ['hd'], 'machine': 'q35'} + - statless_uefi: + firmware_type = "ovmf" + loader_path = "/usr/share/edk2/ovmf/OVMF.amdsev.fd" + loader_dict = {'os_firmware': 'efi', 'loader_stateless': 'yes', 'loader': '${loader_path}', 'loader_type': 'rom'} + - uefi_with_nvram: + firmware_type = "ovmf" + loader_path = "/usr/share/edk2/ovmf/OVMF_CODE.secboot.fd" + nvram_fd_path = "/var/lib/libvirt/qemu/nvram/avocado-vt-vm1_VARS.fd" + nvram_template = "/usr/share/edk2/ovmf/OVMF_VARS.secboot.fd" + loader_dict = {'loader': '${loader_path}', 'nvram': '${nvram_fd_path}', 'nvram_attrs': {'template': '${nvram_template}'}, 'secure': 'yes', 'loader_readonly': 'yes', 'loader_type': 'pflash'} diff --git a/libvirt/tests/cfg/migration/migration_misc/migration_with_cpu_mode.cfg b/libvirt/tests/cfg/migration/migration_misc/migration_with_cpu_mode.cfg new file mode 100644 index 00000000000..74c902aa709 --- /dev/null +++ b/libvirt/tests/cfg/migration/migration_misc/migration_with_cpu_mode.cfg @@ -0,0 +1,42 @@ +- migration.migration_misc.migration_with_cpu_mode: + type = migration_with_cpu_mode + 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' + image_convert = 'no' + server_ip = "${migrate_dest_host}" + server_user = "root" + server_pwd = "${migrate_dest_pwd}" + status_error = "no" + migrate_desturi_port = "16509" + migrate_desturi_type = "tcp" + virsh_migrate_desturi = "qemu+tcp://${migrate_dest_host}/system" + start_vm = "no" + variants: + - p2p: + virsh_migrate_options = '--live --p2p --verbose' + - non_p2p: + virsh_migrate_options = '--live --verbose' + variants migration_option: + - with_xml: + - without_xml: + variants cpu_mode: + - host_model: + no s390x + numa_cell = "'numa_cell': [{'cpus': '0-1', 'memory': '2097152', 'unit': 'KiB'}]" + vm_attrs = {'cpu': {'mode': 'host-model', 'check': 'partial', ${numa_cell}}} + - custom: + no aarch64 + cpu_mode = "custom" diff --git a/libvirt/tests/cfg/migration/migration_misc/migration_with_host_uuid.cfg b/libvirt/tests/cfg/migration/migration_misc/migration_with_host_uuid.cfg new file mode 100644 index 00000000000..3425e38c185 --- /dev/null +++ b/libvirt/tests/cfg/migration/migration_misc/migration_with_host_uuid.cfg @@ -0,0 +1,32 @@ +- migration.migration_misc.migration_with_host_uuid: + type = migration_with_host_uuid + 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' + image_convert = 'no' + server_ip = "${migrate_dest_host}" + server_user = "root" + server_pwd = "${migrate_dest_pwd}" + status_error = "yes" + migrate_desturi_port = "16509" + migrate_desturi_type = "tcp" + virsh_migrate_desturi = "qemu+tcp://${migrate_dest_host}/system" + err_msg = "Attempt to migrate guest to the same host" + libvirtd_conf = {"host_uuid": '"00000000-0000-0000-0000-000000000001"'} + variants: + - p2p: + virsh_migrate_options = '--live --p2p --verbose' + - non_p2p: + virsh_migrate_options = '--live --verbose' diff --git a/libvirt/tests/cfg/migration/migration_misc/migration_with_special_cpu.cfg b/libvirt/tests/cfg/migration/migration_misc/migration_with_special_cpu.cfg new file mode 100644 index 00000000000..09c0f1f4cea --- /dev/null +++ b/libvirt/tests/cfg/migration/migration_misc/migration_with_special_cpu.cfg @@ -0,0 +1,46 @@ +- migration.migration_misc.migration_with_special_cpu: + type = migration_with_special_cpu + migration_setup = 'yes' + vms = avocado-vt-vm1 vm2 + start_vm = no + # 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}" + client_ip = "${migrate_source_host}" + client_user = "root" + client_pwd = "${migrate_source_pwd}" + status_error = "no" + migrate_desturi_port = "16509" + migrate_desturi_type = "tcp" + virsh_migrate_desturi = "qemu+tcp://${migrate_dest_host}/system" + cpu_mode = "host-model" + vm1_hostname = "test-mig-1" + vm2_hostname = "test-mig-2" + l2vm_name = "l2vm" + only x86_64 + variants: + - cpu_disable_vmx_apicv_register: + l1vm_feature_list = {"vmx": "require", "vmx-apicv-register": "disable"} + - cpu: + l1vm_feature_list = {"vmx": "require"} + variants: + - p2p: + virsh_migrate_options = '--live --p2p --verbose' + - non_p2p: + virsh_migrate_options = '--live --verbose' + variants: + - with_precopy: + - with_postcopy: + postcopy_options = '--postcopy --timeout 10 --timeout-postcopy' diff --git a/libvirt/tests/cfg/migration/migration_misc/non_canonical_paths_in_shared_filesystems.cfg b/libvirt/tests/cfg/migration/migration_misc/non_canonical_paths_in_shared_filesystems.cfg new file mode 100644 index 00000000000..8f11f00428a --- /dev/null +++ b/libvirt/tests/cfg/migration/migration_misc/non_canonical_paths_in_shared_filesystems.cfg @@ -0,0 +1,49 @@ +- migration.migration_misc.non_canonical_paths_in_shared_filesystems: + type = non_canonical_paths_in_shared_filesystems + migration_setup = 'yes' + storage_type = '' + setup_nfs = 'no' + setup_local_nfs = 'no' + disk_type = "file" + disk_source_protocol = "netfs" + # 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}" + client_ip = "${migrate_source_host}" + client_user = "root" + client_pwd = "${migrate_source_pwd}" + status_error = "no" + migrate_desturi_port = "22" + migrate_desturi_type = "ssh" + virsh_migrate_desturi = "qemu+ssh://${migrate_dest_host}/system" + start_vm = "yes" + nfs_mount_options = "bind" + export_dir = "/nfs" + nfs_server_ip = "${migrate_source_host}" + images_path = "/var/lib/libvirt/images" + nvram_path = "/var/lib/libvirt/qemu/nvram" + swtpm_path = "/var/lib/libvirt/swtpm" + soft_link = "/var/lib/libvirt/images/nfs-link" + nfs_mount_dir = "${soft_link}" + mnt_path_name = "${soft_link}" + nfs_images_path = "${export_dir}/libvirt/images" + nfs_nvram_path = "${export_dir}/libvirt/nvram" + nfs_swtpm_path = "${export_dir}/libvirt/swtpm" + mount_images_path = "${nfs_server_ip}:${export_dir}/libvirt/images" + mount_nvram_path = "${nfs_server_ip}:${export_dir}/libvirt/nvram" + mount_swtpm_path = "${nfs_server_ip}:${export_dir}/libvirt/swtpm" + qemu_conf_dest = '{r".*shared_filesystems\s*=.*": "shared_filesystems = [\"${soft_link}\", \"${nvram_path}\", \"${swtpm_path}\"]"}' + qemu_conf_src = '{"shared_filesystems": "[\"${soft_link}/\", \"${nvram_path}\", \"${swtpm_path}\"]"}' + migrate_vm_back = "yes" diff --git a/libvirt/tests/cfg/migration/migration_misc/qemu_err_incoming_migration.cfg b/libvirt/tests/cfg/migration/migration_misc/qemu_err_incoming_migration.cfg new file mode 100644 index 00000000000..fb3b2fb9b67 --- /dev/null +++ b/libvirt/tests/cfg/migration/migration_misc/qemu_err_incoming_migration.cfg @@ -0,0 +1,36 @@ +- migration.migration_misc.qemu_err_incoming_migration: + type = qemu_err_incoming_migration + 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' + image_convert = 'no' + server_ip = "${migrate_dest_host}" + server_user = "root" + server_pwd = "${migrate_dest_pwd}" + status_error = "yes" + migrate_desturi_port = "16509" + migrate_desturi_type = "tcp" + virsh_migrate_desturi = "qemu+tcp://${migrate_dest_host}/system" + err_msg = "unable to map backing store for guest RAM: Cannot allocate memory" + setup_hugepages = "yes" + start_vm = "no" + nr_hugepages_src = "2500" + nr_hugepages_dest = "0" + memory_backing = {'hugepages': {'pages': [{'size': '2048', 'unit': 'KiB'}]}} + variants: + - p2p: + virsh_migrate_options = '--live --p2p --verbose' + - non_p2p: + virsh_migrate_options = '--live --verbose' diff --git a/libvirt/tests/cfg/migration/migration_numa/migration_numatune.cfg b/libvirt/tests/cfg/migration/migration_numa/migration_numatune.cfg new file mode 100644 index 00000000000..2b7854aa897 --- /dev/null +++ b/libvirt/tests/cfg/migration/migration_numa/migration_numatune.cfg @@ -0,0 +1,62 @@ +- migration.numa.numatune: + type = migration_numatune + take_regular_screendumps = 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 + # 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" + migration_connections = 3 + virsh_migrate_options = "--p2p --live --persistent --parallel --parallel-connections ${migration_connections} --migrateuri tcp://${migrate_dest_host}" + single_host_node = "no" + mem_value = "'memory': 4194304, 'memory_unit': 'KiB'" + vm_node_mem = 1048576 + hugepage_mem = 4194304 + numa_node0 = {'id': '0', 'cpus': '0', 'memory': '${vm_node_mem}', 'unit': 'KiB'} + numa_node1 = {'id': '1', 'cpus': '1', 'memory': '${vm_node_mem}', 'unit': 'KiB'} + numa_node2 = {'id': '2', 'cpus': '2', 'memory': '${vm_node_mem}', 'unit': 'KiB'} + numa_node3 = {'id': '3', 'cpus': '3', 'memory': '${vm_node_mem}', 'unit': 'KiB'} + numa_cell = "'numa_cell': [${numa_node0}, ${numa_node1}, ${numa_node2}, ${numa_node3}]" + cpu_mode = 'host-model' + no s390-virtio + aarch64: + cpu_mode = 'host-passthrough' + variants mem_pagesize: + - default: + - hugepage: + memory_backing = {'hugepages': {}} + variants memory_mode: + - mem_mode_strict: + mem_mode = 'strict' + numa_memnode = [{'cellid': '0', 'mode': 'preferred', 'nodeset': '%s'}, {'cellid': '1', 'mode': 'interleave', 'nodeset': '%s'}] + - mem_mode_interleave: + mem_mode = 'interleave' + numa_memnode = [{'cellid': '0', 'mode': 'preferred', 'nodeset': '%s'}, {'cellid': '1', 'mode': 'strict', 'nodeset': '%s'}] + - mem_mode_preferred: + mem_mode = 'preferred' + numa_memnode = [{'cellid': '0', 'mode': 'strict', 'nodeset': '%s'}, {'cellid': '1', 'mode': 'interleave', 'nodeset': '%s'}] + - mem_mode_restrictive: + func_supported_since_libvirt_ver = (9, 4, 0) + mem_mode = 'restrictive' + numa_memnode = [{'cellid': '0', 'mode': 'restrictive', 'nodeset': '%s'}, {'cellid': '1', 'mode': 'restrictive', 'nodeset': '%s'}] + numa_memory = {'mode': '${mem_mode}', 'nodeset': '%s'} + vm_attrs = {${mem_value}, 'vcpu': 4, 'cpu': {'mode': '${cpu_mode}', ${numa_cell}}} diff --git a/libvirt/tests/cfg/migration/migration_performance_tuning/migration_timeout_action.cfg b/libvirt/tests/cfg/migration/migration_performance_tuning/migration_timeout_action.cfg index e3d0baa0fc4..7da49fd69a8 100644 --- a/libvirt/tests/cfg/migration/migration_performance_tuning/migration_timeout_action.cfg +++ b/libvirt/tests/cfg/migration/migration_performance_tuning/migration_timeout_action.cfg @@ -29,8 +29,7 @@ test_case = "timeout_action" migrate_speed = "5" timeout_value = "8" - action_during_mig = '[{"func": "check_vm_status_during_mig", "after_event": "iteration: '1'", "func_param": 'params'}, {"func": "set_migrate_speed_to_high", "func_param": "params"}]' - vm_status_during_mig = "paused" + action_during_mig = '[{"func": "check_vm_status_during_mig", "after_event": "iteration: '1'", "func_param": {"vm_name": "${main_vm}", "dest_state": "paused", "src_state":"paused", "dest_uri": "${virsh_migrate_desturi}"}, "need_sleep_time": "${timeout_value}"}, {"func": "set_migrate_speed_to_high", "func_param": "params"}]' stress_package = "stress" stress_args = "--cpu 8 --io 4 --vm 2 --vm-bytes 128M --timeout 20s" variants: diff --git a/libvirt/tests/cfg/migration/migration_uri/migration_desturi.cfg b/libvirt/tests/cfg/migration/migration_uri/migration_desturi.cfg index bf10c658750..ec3c5afd8cb 100644 --- a/libvirt/tests/cfg/migration/migration_uri/migration_desturi.cfg +++ b/libvirt/tests/cfg/migration/migration_uri/migration_desturi.cfg @@ -24,6 +24,8 @@ status_error = "no" check_network_accessibility_after_mig = "yes" migrate_speed = "5" + aarch64: + migrate_speed = "15" action_during_mig = '[{"func": "libvirt_network.check_established", "after_event": "iteration: \'1\'", "func_param": "params"}]' check_local_port = "yes" test_case = "desturi" @@ -62,6 +64,7 @@ ipv6_config = "yes" ipv6_addr_des = "ENTER.YOUR.IPv6.DESTINATION" dest_host = "[${ipv6_addr_des}]" + server_info_ip = "${ipv6_addr_des}" - hostname: dest_host = "ENTER.YOUR.EXAMPLE.SERVER_CN" - wrong_hostname: diff --git a/libvirt/tests/cfg/migration/migration_uri/migration_network_data_transport_tls.cfg b/libvirt/tests/cfg/migration/migration_uri/migration_network_data_transport_tls.cfg index 16d6ec87753..a4b4cb46286 100644 --- a/libvirt/tests/cfg/migration/migration_uri/migration_network_data_transport_tls.cfg +++ b/libvirt/tests/cfg/migration/migration_uri/migration_network_data_transport_tls.cfg @@ -48,10 +48,11 @@ client_cn = "ENTER.YOUR.EXAMPLE.CLIENT_CN" set_remote_libvirtd_log = "yes" libvirtd_file_type = "virtqemud" + remote_file_type = "virtqemud" libvirtd_debug_level = "1" libvirtd_debug_filters = "1:*" check_str_local_log = '['"dir":"/etc/pki/qemu","endpoint":"client","verify-peer":true']' - check_str_remote_log = '"dir":"/etc/pki/qemu","endpoint":"server","verify-peer":true' + check_str_remote_log = '['"dir":"/etc/pki/qemu","endpoint":"server","verify-peer":true']' action_during_mig = '[{"func": "libvirt_network.check_established", "after_event": "iteration: \'1\'", "func_param": "params"}, {"func": "set_migrate_speed_to_high", "func_param": "params"}]' - tls_destination: no with_postcopy diff --git a/libvirt/tests/cfg/migration/migration_uri/migration_network_data_transport_tls_wrong_cert_configuration.cfg b/libvirt/tests/cfg/migration/migration_uri/migration_network_data_transport_tls_wrong_cert_configuration.cfg index 1d191e04923..9972a4b71a0 100644 --- a/libvirt/tests/cfg/migration/migration_uri/migration_network_data_transport_tls_wrong_cert_configuration.cfg +++ b/libvirt/tests/cfg/migration/migration_uri/migration_network_data_transport_tls_wrong_cert_configuration.cfg @@ -42,13 +42,13 @@ variants cert_configuration: - no_client_cert_on_src: cert_path = "${custom_pki_path}/client-cert.pem" - err_msg = "Cannot write to TLS channel: Input/output error|unable to execute QEMU command 'object-add': Unable to access credentials ${cert_path}" + err_msg = "Cannot write to TLS channel: Input/output error|unable to execute QEMU command 'object-add': Unable to access credentials ${cert_path}|Cannot read from TLS channel" - no_server_cert_on_target: cert_path = "${custom_pki_path}/server-cert.pem" err_msg = "unable to execute QEMU command 'object-add': Unable to access credentials ${cert_path}" - wrong_hostname_in_cert: server_cn = "test.com.cn" - err_msg = "qemu-kvm: Cannot read from TLS channel: Input/output error|Certificate does not match the hostname|Domain not found: no domain with matching uuid" + err_msg = "qemu-kvm: Cannot read from TLS channel: Input/output error|Certificate does not match the hostname|Domain not found: no domain with matching uuid|qemu-kvm: load of migration failed: Invalid argument" - signed_by_diff_cert: new_ca_cn = "NEWCERT.VIRT" err_msg = "The certificate hasn't got a known issuer" diff --git a/libvirt/tests/cfg/migration/migration_uri/tls_migrate_tls_x509_verify_on_src.cfg b/libvirt/tests/cfg/migration/migration_uri/tls_migrate_tls_x509_verify_on_src.cfg new file mode 100644 index 00000000000..03ff374a0b3 --- /dev/null +++ b/libvirt/tests/cfg/migration/migration_uri/tls_migrate_tls_x509_verify_on_src.cfg @@ -0,0 +1,44 @@ +- migration.migration_uri.network_data_transport.tls.migrate_tls_x509_verify_on_src: + type = tls_migrate_tls_x509_verify + 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" + check_network_accessibility_after_mig = "yes" + migrate_desturi_port = "16509" + migrate_desturi_type = "tcp" + virsh_migrate_desturi = "qemu+tcp://${migrate_dest_host}/system" + custom_pki_path = "/etc/pki/qemu" + qemu_tls = "yes" + server_cn = "wrong-hostname" + client_cn = "ENTER.YOUR.EXAMPLE.CLIENT_CN" + qemu_conf_path = '/etc/libvirt/qemu.conf' + transport_type = "tls" + test_case = "migrate_tls_x509_verify_on_src" + err_msg = "Certificate does not match the hostname|internal error: QEMU unexpectedly closed the monitor" + status_error = "yes" + qemu_conf_src = '{"default_tls_x509_verify": "0", "migrate_tls_x509_verify": "0"}' + virsh_migrate_extra = "--tls" + variants: + - p2p: + virsh_migrate_options = '--live --p2p --verbose' + - non_p2p: + virsh_migrate_options = '--live --verbose' diff --git a/libvirt/tests/cfg/migration/migration_uri/tls_migrate_tls_x509_verify_on_target.cfg b/libvirt/tests/cfg/migration/migration_uri/tls_migrate_tls_x509_verify_on_target.cfg new file mode 100644 index 00000000000..79c1a502e39 --- /dev/null +++ b/libvirt/tests/cfg/migration/migration_uri/tls_migrate_tls_x509_verify_on_target.cfg @@ -0,0 +1,75 @@ +- migration.migration_uri.network_data_transport.tls.migrate_tls_x509_verify_on_target: + type = tls_migrate_tls_x509_verify + 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" + check_network_accessibility_after_mig = "yes" + migrate_desturi_port = "16509" + migrate_desturi_type = "tcp" + virsh_migrate_desturi = "qemu+tcp://${migrate_dest_host}/system" + custom_pki_path = "/etc/pki/qemu" + qemu_tls = "yes" + server_cn = "ENTER.YOUR.EXAMPLE.SERVER_CN" + client_cn = "ENTER.YOUR.EXAMPLE.CLIENT_CN" + qemu_conf_path = '/etc/libvirt/qemu.conf' + cert_path = "${custom_pki_path}/client-cert.pem" + tmp_cert_path = "/tmp/client-cert.pem" + transport_type = "tls" + test_case = "migrate_tls_x509_verify_on_target" + virsh_migrate_extra = "--tls" + variants: + - p2p: + virsh_migrate_options = '--live --p2p --verbose' + - non_p2p: + virsh_migrate_options = '--live --verbose' + variants: + - both_to_default: + # Use default value for default_tls_x509_verify and migrate_tls_x509_verify + default_qemu_conf = ["default_tls_x509_verify", "migrate_tls_x509_verify"] + err_msg = "Cannot read from TLS channel" + migrate_again = "yes" + status_error = "yes" + migrate_again_status_error = "no" + - set_migrate_to_0: + default_qemu_conf = ["default_tls_x509_verify"] + qemu_conf_dest = '{r".*migrate_tls_x509_verify\s*=.*": "migrate_tls_x509_verify=0"}' + status_error = "no" + - set_default_to_0: + default_qemu_conf = ["migrate_tls_x509_verify"] + qemu_conf_dest = '{r".*default_tls_x509_verify\s*=.*": "default_tls_x509_verify=0"}' + status_error = "no" + - set_default_to_0_and_migrate_to_1: + qemu_conf_dest = '{r".*default_tls_x509_verify\s*=.*": "default_tls_x509_verify=0", r".*migrate_tls_x509_verify\s*=.*": "migrate_tls_x509_verify=1"}' + err_msg = "Cannot read from TLS channel" + migrate_again = "yes" + status_error = "yes" + migrate_again_status_error = "no" + - set_default_to_1_and_migrate_to_0: + qemu_conf_dest = '{r".*default_tls_x509_verify\s*=.*": "default_tls_x509_verify=1", r".*migrate_tls_x509_verify\s*=.*": "migrate_tls_x509_verify=0"}' + status_error = "no" + - set_default_to_1: + default_qemu_conf = ["migrate_tls_x509_verify"] + qemu_conf_dest = '{r".*default_tls_x509_verify\s*=.*": "default_tls_x509_verify=1"}' + err_msg = "Cannot read from TLS channel" + migrate_again = "yes" + status_error = "yes" + migrate_again_status_error = "no" diff --git a/libvirt/tests/cfg/migration/migration_with_numa_topology.cfg b/libvirt/tests/cfg/migration/migration_with_numa_topology.cfg new file mode 100644 index 00000000000..49133da53e7 --- /dev/null +++ b/libvirt/tests/cfg/migration/migration_with_numa_topology.cfg @@ -0,0 +1,48 @@ +- migrate.migration_with_numa_topology: + type = migration_with_numa_topology + only aarch64 + migration_setup = "yes" + storage_type = "nfs" + setup_local_nfs = "yes" + take_regular_screendumps = no + start_vm = 'no' + dest_persist_xml = "yes" + dest_xml = "yes" + migration_bandwidth = "1000" + base_migration_options = "--live --p2p --persistent --undefinesource --bandwidth ${migration_bandwidth}" + node_0_cpu = 0-1 + node_1_cpu = 2-3 + node_num = 4 + vcpu_memory_dict = "'vcpu': 8, 'memory_unit':'KiB','memory':8388608,'current_mem':8388608,'current_mem_unit':'KiB'" + variants: + - one_cluster_on_numa: + topology_dict = {'sockets': '2', 'clusters':'2', 'cores': '2', 'threads': '1'} + node_2_cpu = 4-5 + node_3_cpu = 6-7 + numa_list = "[{'id': '0', 'cpus': '${node_0_cpu}', 'memory': '2097152', 'unit': 'KiB'}, {'id': '1', 'cpus': '${node_1_cpu}', 'memory': '2097152', 'unit': 'KiB'}, {'id': '2', 'cpus': '${node_2_cpu}', 'memory': '2097152', 'unit': 'KiB'}, {'id': '3', 'cpus': '${node_3_cpu}', 'memory': '2097152', 'unit': 'KiB'}]" + - multi_cluster_on_numa: + topology_dict = {'sockets': '1', 'clusters':'4', 'cores': '2', 'threads': '1'} + node_2_cpu = 4-7 + numa_list = "[{'id': '0', 'cpus': '${node_0_cpu}', 'memory': '2097152', 'unit': 'KiB'}, {'id': '1', 'cpus': '${node_1_cpu}', 'memory': '2097152', 'unit': 'KiB'}, {'id': '2', 'cpus': '${node_2_cpu}', 'memory': '2097152', 'unit': 'KiB'}, {'id': '3', 'memory': '2097152', 'unit': 'KiB'}]" + variants: + - base_options: + add_options = "" + - addtional_options: + migration_connections = 3 + add_options = "--auto-converge --parallel --parallel-connections ${migration_connections} --tls" + migrate_dest_host_cn = "ENTER.YOUR.EXAMPLE.SERVER_CN" + migrate_source_host_cn = "ENTER.YOUR.EXAMPLE.CLIENT_CN" + variants: + - without_postcopy: + copy_type = "" + - postcopy: + only base_options + copy_type = "--postcopy" + variants: + - with_back_migration: + migrate_vm_back = "yes" + - no_back_migration: + migrate_vm_back = "no" + vm_attrs = {${vcpu_memory_dict}, 'cpu': {'numa_cell': ${numa_list}}} + virsh_migrate_options = "${base_migration_options} ${add_options} ${copy_type}" + diff --git a/libvirt/tests/cfg/migration/migration_with_virtiofs/migration_with_externally_launched_virtiofs_dev.cfg b/libvirt/tests/cfg/migration/migration_with_virtiofs/migration_with_externally_launched_virtiofs_dev.cfg new file mode 100644 index 00000000000..c26d050c665 --- /dev/null +++ b/libvirt/tests/cfg/migration/migration_with_virtiofs/migration_with_externally_launched_virtiofs_dev.cfg @@ -0,0 +1,37 @@ +- migration.migration_with_virtiofs.migration_with_externally_launched_virtiofs_dev: + type = migration_with_externally_launched_virtiofs_dev + 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 = "/var/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: diff --git a/libvirt/tests/cfg/migration/migration_with_virtiofs/migration_with_internally_launched_virtiofs_dev.cfg b/libvirt/tests/cfg/migration/migration_with_virtiofs/migration_with_internally_launched_virtiofs_dev.cfg new file mode 100644 index 00000000000..c08a6b10927 --- /dev/null +++ b/libvirt/tests/cfg/migration/migration_with_virtiofs/migration_with_internally_launched_virtiofs_dev.cfg @@ -0,0 +1,37 @@ +- migration.migration_with_virtiofs.migration_with_internally_launched_virtiofs_dev: + type = migration_with_internally_launched_virtiofs_dev + 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'}} + dev_type = "filesystem" + mount_tag = "mount_tag1" + mount_dir = "/mnt/${mount_tag}" + test_file = "${mount_dir}/test_file" + fs_dict = {'accessmode':'passthrough', 'type_name': 'mount', 'driver': {'type': 'virtiofs', 'queue':'1024'}, 'source':{'dir': '${mnt_path_name}'}, "target": {'dir': '${mount_tag}'}, 'binary': {'path': '/usr/libexec/virtiofsd', 'xattr': 'on','cache_mode':'none'}} + expect_str = "${mount_tag}.*${mount_dir}" + variants: + - with_precopy: diff --git a/libvirt/tests/cfg/migration/migration_with_vtpm/migration_with_external_tpm.cfg b/libvirt/tests/cfg/migration/migration_with_vtpm/migration_with_external_tpm.cfg index 7807974850a..aa8771b8380 100644 --- a/libvirt/tests/cfg/migration/migration_with_vtpm/migration_with_external_tpm.cfg +++ b/libvirt/tests/cfg/migration/migration_with_vtpm/migration_with_external_tpm.cfg @@ -4,7 +4,6 @@ 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 @@ -26,6 +25,7 @@ client_pwd = "${migrate_source_pwd}" status_error = "no" transport_type = "ssh" + migrate_desturi_type = "ssh" virsh_migrate_desturi = "qemu+ssh://${migrate_dest_host}/system" # vtpm setting func_supported_since_libvirt_ver = (9, 0, 0) @@ -35,11 +35,8 @@ aarch64: tpm_dict = {'tpm_model': 'tpm-tis', 'backend': {'backend_type': 'external', 'source': {'type': 'unix', 'mode': 'connect', 'path': '/var/tmp/guest-swtpm.sock'}}} statedir = "/var/tmp/mytpm" - swtpm_setup_path = '/usr/bin/swtpm_setup' - swtpm_path = '/usr/bin/swtpm' tpm_cmd = "tpm2_getrandom --hex 16" tpm_security_contexts= "user_tmp_t" - variants: - persistent_and_p2p: virsh_migrate_options = "--live --p2p --verbose --undefinesource --persistent" diff --git a/libvirt/tests/cfg/migration/migration_with_vtpm/migration_with_shared_tpm.cfg b/libvirt/tests/cfg/migration/migration_with_vtpm/migration_with_shared_tpm.cfg index 330781b12de..6a160e17ec3 100644 --- a/libvirt/tests/cfg/migration/migration_with_vtpm/migration_with_shared_tpm.cfg +++ b/libvirt/tests/cfg/migration/migration_with_vtpm/migration_with_shared_tpm.cfg @@ -19,56 +19,49 @@ client_pwd = "${migrate_source_pwd}" status_error = "no" transport_type = "ssh" + migrate_desturi_type = "ssh" virsh_migrate_desturi = "qemu+ssh://${migrate_dest_host}/system" tpm_cmd = "tpm2_getrandom --hex 16" auth_sec_dict = {"sec_ephemeral": "no", "sec_private": "yes", "sec_desc": "sample vTPM secret", "sec_usage": "vtpm", "sec_name": "VTPM_example"} secret_value = "sec value test" - check_str_remote_log = "migration release-lock-outgoing,incoming" + check_str_remote_log = '["migration release-lock-outgoing,incoming"]' set_remote_libvirtd_log = "yes" libvirtd_file_type = "virtqemud" + remote_file_type = "virtqemud" libvirtd_debug_level = "1" libvirtd_debug_filters = "1:*" libvirtd_debug_file = '/var/log/libvirt/virtqemud.log' func_supported_since_libvirt_ver = (9, 0, 0) - + tpm_model = "tpm-crb" + aarch64: + tpm_model = "tpm-tis" + swtpm_path = "/var/lib/libvirt/swtpm" + storage_type = 'nfs' + setup_local_nfs = 'yes' + disk_type = "file" + mnt_path_name = ${nfs_mount_dir} variants: - persistent_and_p2p: virsh_migrate_options = "--live --p2p --verbose --undefinesource --persistent" - tpm_dict = {'tpm_model': 'tpm-crb', 'backend': {'backend_type': 'emulator', 'backend_version': '2.0', 'encryption_secret': '0051c505-1ad0-4d77-9b3e-360c8f5e3b86', 'active_pcr_banks': {'sha256': 'True'}}} + tpm_dict = {'tpm_model': '${tpm_model}', 'backend': {'backend_type': 'emulator', 'backend_version': '2.0', 'encryption_secret': '0051c505-1ad0-4d77-9b3e-360c8f5e3b86', 'active_pcr_banks': {'sha256': 'True'}}} - persistent_and_non_p2p: virsh_migrate_options = "--live --verbose" - tpm_dict = {'tpm_model': 'tpm-crb', 'backend': {'backend_type': 'emulator', 'backend_version': '2.0', 'encryption_secret': '0051c505-1ad0-4d77-9b3e-360c8f5e3b86', 'active_pcr_banks': {'sha256': 'True'}}} + tpm_dict = {'tpm_model': '${tpm_model}', 'backend': {'backend_type': 'emulator', 'backend_version': '2.0', 'encryption_secret': '0051c505-1ad0-4d77-9b3e-360c8f5e3b86', 'active_pcr_banks': {'sha256': 'True'}}} - transient_and_non_p2p: virsh_migrate_options = "--live --verbose" - tpm_dict = {'tpm_model': 'tpm-crb', 'backend': {'backend_type': 'emulator', 'backend_version': '2.0', 'persistent_state': 'yes', 'encryption_secret': '0051c505-1ad0-4d77-9b3e-360c8f5e3b86', 'active_pcr_banks': {'sha256': 'True'}}} + tpm_dict = {'tpm_model': '${tpm_model}', 'backend': {'backend_type': 'emulator', 'backend_version': '2.0', 'persistent_state': 'yes', 'encryption_secret': '0051c505-1ad0-4d77-9b3e-360c8f5e3b86', 'active_pcr_banks': {'sha256': 'True'}}} transient_vm = "yes" variants shared_storage_type: - nfs: - image_convert = "no" - storage_type = 'nfs' - setup_local_nfs = 'yes' - disk_type = "file" - disk_source_protocol = "netfs" - nfs_mount_dir = "/var/lib/libvirt/swtpm" - mnt_path_name = ${nfs_mount_dir} + nfs_export_dir = "${export_dir}/swtpm" + src_mount_path = "${client_ip}:${nfs_export_dir}" tpm_security_contexts = "nfs_t" tpm_security_contexts_restore = "${tpm_security_contexts}" - ceph: - disk_type = "network" - nfs_mount_dir = - mnt_path_name = - setup_local_nfs = 'no' - disk_source_protocol = "rbd" - disk_source_port = "6789" - disk_source_name = "migration-with-vtpm-pool" tpm_security_contexts = "svirt_image_t" tpm_security_contexts_restore = "virt_var_lib_t" disk_dict = {"device": "disk", "type_name": "network", "driver": {"name": "qemu", "type": "raw", "cache": "none"}, "target": {"dev": "vda", "bus": "virtio"}} seclabel_dict = {"type": "static", "model": "selinux", "relabel": "yes", "label": "system_u:system_r:svirt_t:s0:c392,c662"} - cleanup_disks = "yes" - image_convert = "yes" - variants: - - non_auth: - mon_host = "EXAMPLE_MON_HOST" - disk_source_host = "EXAMPLE_HOSTS" - host_dict = {"name": "${disk_source_host}", "port": "${disk_source_port}"} + mon_host = "EXAMPLE_MON_HOST" + ceph_key = "EXAMPLE_CEPH_KEY" + src_mount_path = "${mon_host}:6789:/" diff --git a/libvirt/tests/cfg/migration/migration_with_vtpm/migration_with_vtpm_dev.cfg b/libvirt/tests/cfg/migration/migration_with_vtpm/migration_with_vtpm_dev.cfg new file mode 100644 index 00000000000..2c1722b020e --- /dev/null +++ b/libvirt/tests/cfg/migration/migration_with_vtpm/migration_with_vtpm_dev.cfg @@ -0,0 +1,66 @@ +- migration_with_vtpm.migration_with_vtpm_dev: + type = migration_with_vtpm_dev + 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 + start_vm = "no" + # Local URI + virsh_migrate_connect_uri = "qemu:///system" + server_ip = "${migrate_dest_host}" + server_user = "root" + server_pwd = "${migrate_dest_pwd}" + client_ip = "${migrate_source_host}" + client_user = "root" + client_pwd = "${migrate_source_pwd}" + transport_type = "ssh" + migrate_desturi_type = "ssh" + virsh_migrate_desturi = "qemu+ssh://${migrate_dest_host}/system" + tpm_cmd = "tpm2_getrandom --hex 16" + auth_sec_dict = {"sec_ephemeral": "no", "sec_private": "yes", "sec_desc": "sample vTPM secret", "sec_usage": "vtpm", "sec_name": "VTPM_example"} + src_secret_value = "sec value test" + src_secret_value_path = "/var/tmp/src_secretinfile" + dst_secret_value = ${src_secret_value} + dst_secret_value_path = "/var/tmp/dst_secretinfile" + swtpm_path = "/var/lib/libvirt/swtpm/" + swtpm_log = "/var/log/swtpm/libvirt/qemu/${migrate_main_vm}-swtpm.log" + status_error = "yes" + err_msg = "guest CPU doesn't match specification: missing features" + status_error_again = "no" + migrate_again = "yes" + tpm_model = "tpm-crb" + aarch64: + tpm_model = "tpm-tis" + tpm_dict = {'tpm_model': '${tpm_model}', 'backend': {'backend_type': 'emulator', 'backend_version': '2.0', 'encryption_secret': '0051c505-1ad0-4d77-9b3e-360c8f5e3b86'}} + variants: + - p2p: + virsh_migrate_options = '--live --p2p --verbose' + - non_p2p: + virsh_migrate_options = '--live --verbose' + variants: + - with_precopy: + - with_postcopy: + postcopy_options = '--postcopy --postcopy-bandwidth 10 --bandwidth 10' + action_during_mig_again = '[{"func": "virsh.migrate_postcopy", "func_param": "'%s' % params.get('migrate_main_vm')", "need_sleep_time": "5"}]' + variants test_case: + - default: + - tunnelled: + only with_precopy + only p2p + virsh_migrate_extra = "--tunnelled" + - diff_secret_on_src_and_dst: + only with_precopy + status_error = "yes" + migrate_again = "no" + src_secret_value = "sec value test" + dst_secret_value = "sec value diff" + err_msg = "qemu-kvm: tpm-emulator: Setting the stateblob \(type 1\) failed with a TPM error 0x21 decryption error" diff --git a/libvirt/tests/cfg/migration/migration_with_vtpm/migration_with_vtpm_state_on_block_dev.cfg b/libvirt/tests/cfg/migration/migration_with_vtpm/migration_with_vtpm_state_on_block_dev.cfg new file mode 100644 index 00000000000..652e3b8a2bb --- /dev/null +++ b/libvirt/tests/cfg/migration/migration_with_vtpm/migration_with_vtpm_state_on_block_dev.cfg @@ -0,0 +1,69 @@ +- migration_with_vtpm.migration_with_vtpm_state_on_block_dev: + type = migration_with_vtpm_state_on_block_dev + 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 + start_vm = "no" + # Local URI + virsh_migrate_connect_uri = "qemu:///system" + server_ip = "${migrate_dest_host}" + server_user = "root" + server_pwd = "${migrate_dest_pwd}" + client_ip = "${migrate_source_host}" + client_user = "root" + client_pwd = "${migrate_source_pwd}" + transport_type = "ssh" + migrate_desturi_type = "ssh" + virsh_migrate_desturi = "qemu+ssh://${migrate_dest_host}/system" + tpm_cmd = "tpm2_getrandom --hex 16" + auth_sec_dict = {"sec_ephemeral": "no", "sec_private": "yes", "sec_desc": "sample vTPM secret", "sec_usage": "vtpm", "sec_name": "VTPM_example"} + src_secret_value = "sec value test" + src_secret_value_path = "/var/tmp/src_secretinfile" + dst_secret_value = ${src_secret_value} + dst_secret_value_path = "/var/tmp/dst_secretinfile" + status_error = "no" + func_supported_since_libvirt_ver = (10, 10, 0) + block_path = "/var/iscsiswtpm" + libvirtd_debug_file = '/var/log/libvirt/virtqemud.log' + libvirtd_debug_filters = "1:*" + libvirtd_debug_level = "1" + libvirtd_file_type = "virtqemud" + unexpected_in_list_1 = "['support explicit locking']" + expected_in_list_1 = "['swtpm socket.*--tpmstate.*,lock']" + expected_in_list_2 = "['qemuTPMVirCommandSwtpmAddTPMState.*This swtpm version doesn\'t support explicit locking', '--tpmstate dir=/test/myDir,mode=0600']" + unexpected_in_list_3 = "['swtpm socket.*--tpmstate.*,lock']" + expected_in_list_3 = "['qemuTPMGetSwtpmSetupStateArg.*This swtpm version doesn\'t support explicit locking', '--tpmstate dir=/test/myDir,mode=0600']" + tpm_model = "tpm-crb" + aarch64: + tpm_model = "tpm-tis" + variants test_case: + - auto_create_dir: + block_dir = "${block_path}/mig_vtpm_auto_dir_test" + tpm_dict = {'tpm_model': '${tpm_model}', 'backend': {'backend_type': 'emulator', 'backend_version': '2.0', 'encryption_secret': '0051c505-1ad0-4d77-9b3e-360c8f5e3b86', 'source': {'type': 'dir', 'path': '${block_dir}'}}} + check_lables_1 = '[r"tss tss system_u:object_r:virt_var_lib_t:s0.*.lock", r"tss tss system_u:object_r:virt_var_lib_t:s0.*tpm2-00.permall"]' + check_lables_2 = '[r"tss tss system_u:object_r:svirt_image_t:s0:c.*.lock", r"tss tss system_u:object_r:svirt_image_t:s0:c.*tpm2-00.permall"]' + check_lables_3 = '[r"tss tss system_u:object_r:virt_var_lib_t:s0.*.lock", r"tss tss system_u:object_r:virt_var_lib_t:s0.*tpm2-00.permall"]' + - manual_create_dir: + block_dir = "${block_path}/mig_vtpm_manual_dir_test" + tpm_dict = {'tpm_model': '${tpm_model}', 'backend': {'backend_type': 'emulator', 'backend_version': '2.0', 'encryption_secret': '0051c505-1ad0-4d77-9b3e-360c8f5e3b86', 'source': {'type': 'dir', 'path': '${block_dir}'}}} + check_lables_1 = '[r"root root system_u:object_r:virt_var_lib_t:s0.*.", r"root root unconfined_u:object_r:virt_var_lib_t:s0.*.."]' + check_lables_2 = '[r"tss tss system_u:object_r:svirt_image_t:s0:c.*.lock", r"tss tss system_u:object_r:svirt_image_t:s0:c.*tpm2-00.permall"]' + check_lables_3 = '[r"tss tss system_u:object_r:virt_var_lib_t:s0.*.lock", r"tss tss system_u:object_r:virt_var_lib_t:s0.*tpm2-00.permall"]' + - auto_create_file: + dir_name = "mig_vtpm_auto_file_test" + file_name = "${dir_name}2-00.permall" + block_dir = "${block_path}/${dir_name}" + tpm_dict = {'tpm_model': '${tpm_model}', 'backend': {'backend_type': 'emulator', 'backend_version': '2.0', 'encryption_secret': '0051c505-1ad0-4d77-9b3e-360c8f5e3b86', 'source': {'type': 'file', 'path': '${block_dir}/${file_name}'}}} + check_lables_1 = '[r"tss tss system_u:object_r:virt_var_lib_t:s0.*.", r"root root unconfined_u:object_r:virt_var_lib_t:s0.*.."]' + check_lables_2 = '[r"tss tss system_u:object_r:svirt_image_t:s0:c.*${file_name}"]' + check_lables_3 = '[r"tss tss system_u:object_r:virt_var_lib_t:s0.*${file_name}"]' diff --git a/libvirt/tests/cfg/migration/migration_xml_update.cfg b/libvirt/tests/cfg/migration/migration_xml_update.cfg new file mode 100644 index 00000000000..5a227d9227f --- /dev/null +++ b/libvirt/tests/cfg/migration/migration_xml_update.cfg @@ -0,0 +1,48 @@ +- migration.xml_update: + type = migration_xml_update + migration_setup = 'yes' + storage_type = 'nfs' + setup_local_nfs = 'yes' + disk_type = "file" + 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 + start_vm = "yes" + virsh_migrate_dest_state = running + virsh_migrate_src_state = running + # Local URI + virsh_migrate_connect_uri = "qemu:///system" + server_ip = "${migrate_dest_host}" + server_user = "root" + server_pwd = "${migrate_dest_pwd}" + client_ip = "${migrate_source_host}" + client_user = "root" + client_pwd = "${migrate_source_pwd}" + status_error = "no" + transport_type = "ssh" + virsh_migrate_desturi = "qemu+ssh://${migrate_dest_host}/system" + variants: + - positive: + variants: + - update_rng_alias: + remove_all = rng + add_device = {"rng_model": "virtio", "backend": {"backend_model": "builtin"}} + status_error = no + modify = alias + - negative: + variants: + - update_rng_address: + remove_all = rng + add_device = {"rng_model": "virtio", "backend": {"backend_model": "builtin"}} + status_error = yes + err_msg = "unsupported configuration" + modify = address + new_address =
+ s390-virtio: + new_address =
+ diff --git a/libvirt/tests/cfg/migration/non_live_migration/non_live_migration.cfg b/libvirt/tests/cfg/migration/non_live_migration/non_live_migration.cfg new file mode 100644 index 00000000000..f4324c651f0 --- /dev/null +++ b/libvirt/tests/cfg/migration/non_live_migration/non_live_migration.cfg @@ -0,0 +1,40 @@ +- migration.non_live_migration: + type = non_live_migration + 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" + image_convert = 'no' + server_ip = "${migrate_dest_host}" + server_user = "root" + server_pwd = "${migrate_dest_pwd}" + status_error = "no" + start_vm = "yes" + migrate_desturi_port = "16509" + migrate_desturi_type = "tcp" + virsh_migrate_desturi = "qemu+tcp://${migrate_dest_host}/system" + check_network_accessibility_after_mig = "yes" + variants: + - p2p: + virsh_migrate_options = "--p2p --verbose" + - non_p2p: + virsh_migrate_options = "--verbose" + variants: + - with_precopy: + expected_event_src = ["lifecycle.*Suspended Migrated", "migration-iteration.*iteration"] + - with_postcopy: + postcopy_options = "--postcopy" + status_error = "yes" + err_msg = "post-copy migration is not supported with non-live or paused migration" diff --git a/libvirt/tests/cfg/migration/p2p_keepalive/customized_keepalive.cfg b/libvirt/tests/cfg/migration/p2p_keepalive/customized_keepalive.cfg new file mode 100644 index 00000000000..3bc9bff1697 --- /dev/null +++ b/libvirt/tests/cfg/migration/p2p_keepalive/customized_keepalive.cfg @@ -0,0 +1,76 @@ +- migration.p2p_keepalive.customized_keepalive: + type = p2p_keepalive + 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' + image_convert = 'no' + server_ip = "${migrate_dest_host}" + server_user = "root" + server_pwd = "${migrate_dest_pwd}" + client_ip = "${migrate_source_host}" + client_user = "root" + client_pwd = "${migrate_source_pwd}" + libvirtd_file_type = "virtqemud" + libvirtd_debug_level = "1" + libvirtd_debug_filters = "1:*" + set_remote_libvirtd_log = "yes" + virsh_migrate_options = "--live --p2p --timeout 2 --timeout-suspend --verbose" + virsh_migrate_extra = "--bandwidth 10" + virsh_migrate_dest_state = "running" + virsh_migrate_src_state = "shut off" + variants: + - with_precopy: + variants: + - desturi_ssh: + migrate_desturi_type = "ssh" + new_ssh_port = "6666" + migrate_desturi_port = "${new_ssh_port}" + conf_on_src = '{"keepalive_interval": "3", "keepalive_count": "3"}' + src_conf_type = "qemu" + conf_on_target = '{r".*keepalive_interval\s*=.*": "keepalive_interval = 2", r".*keepalive_count\s*=.*": "keepalive_count = 4"}' + target_conf_type = "virtqemud" + remote_file_type = "virtqemud" + firewall_rule_on_dest = "ipv4 filter INPUT 0 -p tcp -j DROP --dport ${migrate_desturi_port} -s ${migrate_source_host}" + firewall_rule_on_src = "ipv4 filter INPUT 0 -p tcp -j DROP --sport ${migrate_desturi_port} -s ${migrate_dest_host}" + virsh_migrate_desturi = "qemu+${migrate_desturi_type}://${migrate_dest_host}:${new_ssh_port}/system" + - desturi_tcp: + migrate_desturi_port = "16509" + migrate_desturi_type = "tcp" + conf_on_src = '{"keepalive_interval": "3", "keepalive_count": "3"}' + src_conf_type = "qemu" + conf_on_target = '{r".*keepalive_interval\s*=.*": "keepalive_interval = 2", r".*keepalive_count\s*=.*": "keepalive_count = 4"}' + target_conf_type = "virtproxyd" + remote_file_type = "virtproxyd" + firewall_rule_on_dest = "ipv4 filter INPUT 0 -p tcp -j DROP --dport ${migrate_desturi_port} -s ${migrate_source_host}" + firewall_rule_on_src = "ipv4 filter INPUT 0 -p tcp -j DROP --sport ${migrate_desturi_port} -s ${migrate_dest_host}" + virsh_migrate_desturi = "qemu+${migrate_desturi_type}://${migrate_dest_host}/system" + variants test_case: + - after_keepalive_timeout: + status_error = "yes" + migrate_again = "yes" + migrate_again_status_error = "no" + expected_event_src = ["lifecycle.*Suspended Migrated", "lifecycle.*Resumed Migrated"] + expected_event_target = ["lifecycle.*: Stopped Destroyed|lifecycle.*: Stopped Failed"] + check_str_local_log = '["countToDeath=3 idle=3", "countToDeath=2 idle=6", "countToDeath=1 idle=9", "countToDeath=0 idle=12", "No response from client.*after 4 keepalive messages in 12 seconds", "internal error: connection closed due to keepalive timeout"]' + check_str_remote_log = '["countToDeath=4 idle=2", "countToDeath=3 idle=4", "countToDeath=2 idle=6", "countToDeath=1 idle=8", "countToDeath=0 idle=10", "No response from client.*after 5 keepalive messages in 10 seconds", "internal error: connection closed due to keepalive timeout"]' + migrate_src_state = "running" + migrate_dest_state = "nonexist" + virsh_migrate_extra_mig_again = " " + action_during_mig = '[{"func": "libvirt_network.setup_firewall_rule", "after_event": "iteration: '1'", "func_param": "params", "need_sleep_time": "4"}]' + - before_keepalive_timeout: + status_error = "no" + check_str_local_log = '["client=.* countToDeath=3 idle=3", "client=.* countToDeath=2 idle=6", "client=.* countToDeath=3 idle=3", "client=.* countToDeath=3 idle=3"]' + check_str_remote_log = '["client=.* countToDeath=4 idle=2", "client=.* countToDeath=3 idle=4", "client=.* countToDeath=4 idle=2", "client=.* countToDeath=4 idle=2"]' + action_during_mig = [{"func": "libvirt_network.setup_firewall_rule", "after_event": "iteration: '1'", "func_param": "params"}, {"func": "libvirt_network.cleanup_firewall_rule", "func_param": "params", "need_sleep_time": "3"}] diff --git a/libvirt/tests/cfg/migration/p2p_keepalive/default_keepalive.cfg b/libvirt/tests/cfg/migration/p2p_keepalive/default_keepalive.cfg new file mode 100644 index 00000000000..11cbc763962 --- /dev/null +++ b/libvirt/tests/cfg/migration/p2p_keepalive/default_keepalive.cfg @@ -0,0 +1,76 @@ +- migration.p2p_keepalive.default_keepalive: + type = p2p_keepalive + 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' + image_convert = 'no' + server_ip = "${migrate_dest_host}" + server_user = "root" + server_pwd = "${migrate_dest_pwd}" + client_ip = "${migrate_source_host}" + client_user = "root" + client_pwd = "${migrate_source_pwd}" + libvirtd_file_type = "virtqemud" + libvirtd_debug_level = "1" + libvirtd_debug_filters = "1:*" + set_remote_libvirtd_log = "yes" + virsh_migrate_options = "--live --p2p --timeout 2 --timeout-suspend --verbose" + virsh_migrate_extra = "--bandwidth 10" + virsh_migrate_dest_state = "running" + virsh_migrate_src_state = "shut off" + variants: + - with_precopy: + variants: + - desturi_ssh: + migrate_desturi_type = "ssh" + new_ssh_port = "6666" + migrate_desturi_port = ${new_ssh_port} + default_conf_on_src = ["keepalive_interval", "keepalive_count"] + src_conf_type = "qemu" + default_conf_on_target = ["keepalive_interval", "keepalive_count"] + target_conf_type = "virtqemud" + remote_file_type = "virtqemud" + firewall_rule_on_dest = "ipv4 filter INPUT 0 -p tcp -j DROP --dport ${migrate_desturi_port} -s ${migrate_source_host}" + firewall_rule_on_src = "ipv4 filter INPUT 0 -p tcp -j DROP --sport ${migrate_desturi_port} -s ${migrate_dest_host}" + virsh_migrate_desturi = "qemu+${migrate_desturi_type}://${migrate_dest_host}:${migrate_desturi_port}/system" + - desturi_tcp: + migrate_desturi_port = "16509" + migrate_desturi_type = "tcp" + default_conf_on_src = ["keepalive_interval", "keepalive_count"] + src_conf_type = "qemu" + default_conf_on_target = ["keepalive_interval", "keepalive_count"] + target_conf_type = "virtproxyd" + remote_file_type = "virtproxyd" + firewall_rule_on_dest = "ipv4 filter INPUT 0 -p tcp -j DROP --dport ${migrate_desturi_port} -s ${migrate_source_host}" + firewall_rule_on_src = "ipv4 filter INPUT 0 -p tcp -j DROP --sport ${migrate_desturi_port} -s ${migrate_dest_host}" + virsh_migrate_desturi = "qemu+${migrate_desturi_type}://${migrate_dest_host}/system" + variants keepalive_timeout: + - after_keepalive_timeout: + status_error = "yes" + migrate_again = "yes" + migrate_again_status_error = "no" + expected_event_src = ["lifecycle.*Suspended Migrated", "lifecycle.*Resumed Migrated"] + expected_event_target = ["lifecycle.*: Stopped Failed|lifecycle.*: Stopped Destroyed"] + check_str_local_log = '["countToDeath=5 idle=5", "countToDeath=4 idle=10", "countToDeath=3 idle=15", "countToDeath=2 idle=20", "countToDeath=1 idle=25", "countToDeath=0 idle=30", "No response from client.*after 5 keepalive messages in 30 seconds", "internal error: connection closed due to keepalive timeout"]' + check_str_remote_log = '["countToDeath=5 idle=5", "countToDeath=4 idle=10", "countToDeath=3 idle=15", "countToDeath=2 idle=20", "countToDeath=1 idle=25", "countToDeath=0 idle=30", "No response from client.*after 5 keepalive messages in 30 seconds", "internal error: connection closed due to keepalive timeout"]' + migrate_src_state = "running" + migrate_dest_state = "nonexist" + virsh_migrate_extra_mig_again = " " + action_during_mig = '[{"func": "libvirt_network.setup_firewall_rule", "after_event": "iteration: '1'", "func_param": "params", "need_sleep_time": "5"}]' + - before_keepalive_timeout: + status_error = "no" + check_str_local_log = '["client=.* countToDeath=5 idle=5", "client=.* countToDeath=4 idle=10", "client=.* countToDeath=5 idle=5", "client=.* countToDeath=5 idle=5"]' + check_str_remote_log = '["client=.* countToDeath=5 idle=5", "client=.* countToDeath=4 idle=10", "client=.* countToDeath=5 idle=5", "client=.* countToDeath=5 idle=5"]' + action_during_mig = [{"func": "libvirt_network.setup_firewall_rule", "after_event": "iteration: '1'", "func_param": "params"}, {"func": "libvirt_network.cleanup_firewall_rule", "func_param": "params", "need_sleep_time": "10"}] diff --git a/libvirt/tests/cfg/migration/p2p_keepalive/src_and_dest_keepalive_disabled.cfg b/libvirt/tests/cfg/migration/p2p_keepalive/src_and_dest_keepalive_disabled.cfg new file mode 100644 index 00000000000..3bbc34e1802 --- /dev/null +++ b/libvirt/tests/cfg/migration/p2p_keepalive/src_and_dest_keepalive_disabled.cfg @@ -0,0 +1,57 @@ +- migration.p2p_keepalive.src_and_dest_keepalive_disabled: + type = p2p_keepalive + 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' + image_convert = 'no' + server_ip = "${migrate_dest_host}" + server_user = "root" + server_pwd = "${migrate_dest_pwd}" + client_ip = "${migrate_source_host}" + client_user = "root" + client_pwd = "${migrate_source_pwd}" + virsh_migrate_options = "--live --p2p --timeout 2 --timeout-suspend --verbose" + virsh_migrate_extra = "--bandwidth 10" + virsh_migrate_dest_state = "running" + virsh_migrate_src_state = "shut off" + status_error = "no" + action_during_mig = '[{"func": "libvirt_network.setup_firewall_rule", "after_event": "iteration: '1'", "func_param": "params", "need_sleep_time": "5"}, {"func": "libvirt_network.cleanup_firewall_rule", "func_param": "params", "need_sleep_time": "30"}]' + test_case = "src_and_dest_keepalive_disabled" + variants: + - with_precopy: + variants: + - desturi_ssh: + migrate_desturi_type = "ssh" + new_ssh_port = "6666" + migrate_desturi_port = "${new_ssh_port}" + conf_on_src = '{"keepalive_interval": "-1"}' + src_conf_type = "qemu" + conf_on_target = '{r".*keepalive_interval\s*=.*": "keepalive_interval = -1"}' + target_conf_type = "virtqemud" + remote_file_type = "virtqemud" + firewall_rule_on_dest = "ipv4 filter INPUT 0 -p tcp -j DROP --dport ${migrate_desturi_port} -s ${migrate_source_host}" + firewall_rule_on_src = "ipv4 filter INPUT 0 -p tcp -j DROP --sport ${migrate_desturi_port} -s ${migrate_dest_host}" + virsh_migrate_desturi = "qemu+${migrate_desturi_type}://${migrate_dest_host}:${new_ssh_port}/system" + - desturi_tcp: + migrate_desturi_port = "16509" + migrate_desturi_type = "tcp" + conf_on_src = '{"keepalive_interval": "-1"}' + src_conf_type = "qemu" + conf_on_target = '{r".*keepalive_interval\s*=.*": "keepalive_interval = -1"}' + target_conf_type = "virtproxyd" + remote_file_type = "virtproxyd" + firewall_rule_on_dest = "ipv4 filter INPUT 0 -p tcp -j DROP --dport ${migrate_desturi_port} -s ${migrate_source_host}" + firewall_rule_on_src = "ipv4 filter INPUT 0 -p tcp -j DROP --sport ${migrate_desturi_port} -s ${migrate_dest_host}" + virsh_migrate_desturi = "qemu+${migrate_desturi_type}://${migrate_dest_host}/system" diff --git a/libvirt/tests/cfg/migration/p2p_keepalive/src_keepalive_disabled.cfg b/libvirt/tests/cfg/migration/p2p_keepalive/src_keepalive_disabled.cfg new file mode 100644 index 00000000000..61052432426 --- /dev/null +++ b/libvirt/tests/cfg/migration/p2p_keepalive/src_keepalive_disabled.cfg @@ -0,0 +1,71 @@ +- migration.p2p_keepalive.src_keepalive_disabled: + type = p2p_keepalive + 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' + image_convert = 'no' + server_ip = "${migrate_dest_host}" + server_user = "root" + server_pwd = "${migrate_dest_pwd}" + client_ip = "${migrate_source_host}" + client_user = "root" + client_pwd = "${migrate_source_pwd}" + libvirtd_file_type = "virtqemud" + libvirtd_debug_level = "1" + libvirtd_debug_filters = "1:*" + set_remote_libvirtd_log = "yes" + virsh_migrate_options = "--live --p2p --timeout 2 --timeout-suspend --verbose" + virsh_migrate_extra = "--bandwidth 10" + virsh_migrate_dest_state = "running" + virsh_migrate_src_state = "shut off" + variants: + - with_precopy: + variants: + - desturi_ssh: + migrate_desturi_type = "ssh" + new_ssh_port = "6666" + migrate_desturi_port = "${new_ssh_port}" + conf_on_src = '{"keepalive_interval": "-1"}' + src_conf_type = "qemu" + remote_file_type = "virtqemud" + firewall_rule_on_dest = "ipv4 filter INPUT 0 -p tcp -j DROP --dport ${migrate_desturi_port} -s ${migrate_source_host}" + firewall_rule_on_src = "ipv4 filter INPUT 0 -p tcp -j DROP --sport ${migrate_desturi_port} -s ${migrate_dest_host}" + virsh_migrate_desturi = "qemu+${migrate_desturi_type}://${migrate_dest_host}:${new_ssh_port}/system" + - desturi_tcp: + migrate_desturi_port = "16509" + migrate_desturi_type = "tcp" + conf_on_src = '{"keepalive_interval": "-1"}' + src_conf_type = "qemu" + remote_file_type = "virtproxyd" + firewall_rule_on_dest = "ipv4 filter INPUT 0 -p tcp -j DROP --dport ${migrate_desturi_port} -s ${migrate_source_host}" + firewall_rule_on_src = "ipv4 filter INPUT 0 -p tcp -j DROP --sport ${migrate_desturi_port} -s ${migrate_dest_host}" + virsh_migrate_desturi = "qemu+${migrate_desturi_type}://${migrate_dest_host}/system" + variants keepalive_timeout: + - after_keepalive_timeout: + status_error = "yes" + migrate_again = "yes" + migrate_again_status_error = "no" + expected_event_src = ["lifecycle.*Suspended Migrated", "lifecycle.*Resumed Migrated"] + expected_event_target = ["lifecycle.*: Stopped Destroyed|lifecycle.*: Stopped Failed"] + check_no_str_local_log = '["No response.*after 5 keepalive messages in 30 seconds"]' + check_str_remote_log = '["countToDeath=5 idle=5", "countToDeath=4 idle=10", "countToDeath=3 idle=15", "countToDeath=2 idle=20", "countToDeath=1 idle=25", "countToDeath=0 idle=30", "No response from client.*after 5 keepalive messages in 30 seconds", "internal error: connection closed due to keepalive timeout"]' + migrate_src_state = "running" + migrate_dest_state = "nonexist" + virsh_migrate_extra_mig_again = " " + action_during_mig = '[{"func": "libvirt_network.setup_firewall_rule", "after_event": "iteration: '1'", "func_param": "params", "need_sleep_time": "5"}]' + - before_keepalive_timeout: + status_error = "no" + check_str_remote_log = '["client=.* countToDeath=5 idle=5", "client=.* countToDeath=4 idle=10", "client=.* countToDeath=5 idle=5", "client=.* countToDeath=5 idle=5"]' + action_during_mig = [{"func": "libvirt_network.setup_firewall_rule", "after_event": "iteration: '1'", "func_param": "params"}, {"func": "libvirt_network.cleanup_firewall_rule", "func_param": "params", "need_sleep_time": "10"}] diff --git a/libvirt/tests/cfg/migration/pause_postcopy_migration_and_recover/pause_and_io_error_and_recover.cfg b/libvirt/tests/cfg/migration/pause_postcopy_migration_and_recover/pause_and_io_error_and_recover.cfg index 723f0859c55..c8bd02afcfe 100644 --- a/libvirt/tests/cfg/migration/pause_postcopy_migration_and_recover/pause_and_io_error_and_recover.cfg +++ b/libvirt/tests/cfg/migration/pause_postcopy_migration_and_recover/pause_and_io_error_and_recover.cfg @@ -21,7 +21,7 @@ server_ip = "${migrate_dest_host}" server_user = "root" server_pwd = "${migrate_dest_pwd}" - check_network_accessibility_after_mig = "yes" + check_network_accessibility_after_mig = "no" migrate_desturi_port = "16509" migrate_desturi_type = "tcp" virsh_migrate_desturi = "qemu+tcp://${migrate_dest_host}/system" @@ -31,7 +31,7 @@ stress_package = "stress" stress_args = "--cpu 8 --io 4 --vm 2 --vm-bytes 128M --timeout 20s" postcopy_options = "--timeout 4 --timeout-postcopy --postcopy" - action_during_mig = '[{"func": "libvirt_network.check_established", "after_event": "iteration: '1'", "func_param": 'params'}, {"func": "get_vm_serial_session_on_dest", "func_param": "params", "need_sleep_time": "10"}, {"func": "virsh.domjobabort", "func_param": "'%s --postcopy' % params.get('migrate_main_vm')"}]' + action_during_mig = '[{"func": "libvirt_network.check_established", "after_event": "iteration: '1'", "func_param": 'params'}, {"func": "write_vm_disk_on_dest", "func_param": "params", "need_sleep_time": "60"}, {"func": "virsh.domjobabort", "func_param": "'%s --postcopy' % params.get('migrate_main_vm')", "need_sleep_time": "5"}]' migrate_again = 'yes' migrate_again_status_error = 'no' action_during_mig_again = '[{"func": "set_migrate_speed_to_high", "before_pause": "yes", "func_param": "params"}]' diff --git a/libvirt/tests/cfg/migration/pause_postcopy_migration_and_recover/pause_and_recover_and_disruptive.cfg b/libvirt/tests/cfg/migration/pause_postcopy_migration_and_recover/pause_and_recover_and_disruptive.cfg index 369cdd13b42..98900a1086d 100644 --- a/libvirt/tests/cfg/migration/pause_postcopy_migration_and_recover/pause_and_recover_and_disruptive.cfg +++ b/libvirt/tests/cfg/migration/pause_postcopy_migration_and_recover/pause_and_recover_and_disruptive.cfg @@ -77,9 +77,9 @@ virsh_migrate_extra = "--migrateuri tcp://${migrate_dest_host}:${port_to_check} --listen-address ${migrate_dest_host}" firewall_rule_on_dest = "ipv4 filter INPUT 0 -p tcp --dport ${port_to_check} -j DROP" firewall_rule_on_src = "ipv4 filter INPUT 0 -p tcp --sport ${port_to_check} -j DROP" - action_during_do_mig = '[{"func": "libvirt_network.setup_firewall_rule", "func_param": "params", "need_sleep_time": "10"}, {"func": "libvirt_network.cleanup_firewall_rule", "func_param": "params", "need_sleep_time": "90"}]' + action_during_do_mig = '[{"func": "libvirt_network.setup_firewall_rule", "func_param": "params", "need_sleep_time": "10"}, {"func": "libvirt_network.cleanup_firewall_rule", "func_param": "params", "need_sleep_time": "10"}]' status_error_during_mig = "no" - tcp_config_list = '{"tcp_keepalive_probes": "9", "tcp_keepalive_intvl": "60", "tcp_retries1": "4", "tcp_retries2": "8", "tcp_fin_timeout": "2"}' + tcp_config_list = '{"tcp_keepalive_probes": "3", "tcp_keepalive_intvl": "3", "tcp_retries1": "1", "tcp_retries2": "1", "tcp_fin_timeout": "2"}' recover_tcp_config_list = '{"tcp_keepalive_probes": "9", "tcp_keepalive_intvl": "75", "tcp_retries1": "3", "tcp_retries2": "15", "tcp_fin_timeout": "60"}' - pause_by_proxy_issue: action_during_do_mig = '[{"func": "clear_pmsocat", "func_param": "params", "need_sleep_time": "5"}, {"func": "base_steps.recreate_conn_objs", "func_param": "params", "need_sleep_time": "10"}]' diff --git a/libvirt/tests/cfg/migration/pause_postcopy_migration_and_recover/pause_and_recover_twice.cfg b/libvirt/tests/cfg/migration/pause_postcopy_migration_and_recover/pause_and_recover_twice.cfg index c7ece41cce3..8c78bdd7dc0 100644 --- a/libvirt/tests/cfg/migration/pause_postcopy_migration_and_recover/pause_and_recover_twice.cfg +++ b/libvirt/tests/cfg/migration/pause_postcopy_migration_and_recover/pause_and_recover_twice.cfg @@ -46,12 +46,12 @@ virsh_migrate_extra = "--migrateuri tcp://${migrate_dest_host}:${port_to_check} --listen-address ${migrate_dest_host}" firewall_rule_on_dest = "ipv4 filter INPUT 0 -p tcp --dport ${port_to_check} -j DROP" firewall_rule_on_src = "ipv4 filter INPUT 0 -p tcp --sport ${port_to_check} -j DROP" - action_during_mig = '[{"func": "libvirt_network.check_established", "after_event": "iteration: '1'", "func_param": 'params'}, {"func": "virsh.domjobabort", "func_param": "'%s --postcopy' % params.get('migrate_main_vm')", "need_sleep_time": "5"}, {"func": "libvirt_network.setup_firewall_rule", "func_param": "params"}, {"func": "do_migration", "func_param": "params", "need_sleep_time": "90"}, {"func": "libvirt_network.cleanup_firewall_rule", "func_param": "params", "need_sleep_time": "5"}, {"func": "resume_migration_again", "func_param": "params", "need_sleep_time": "5"}]' + action_during_mig = '[{"func": "libvirt_network.check_established", "after_event": "iteration: '1'", "func_param": 'params'}, {"func": "virsh.domjobabort", "func_param": "'%s --postcopy' % params.get('migrate_main_vm')", "need_sleep_time": "5"}, {"func": "libvirt_network.setup_firewall_rule", "func_param": "params"}, {"func": "do_migration", "func_param": "params", "need_sleep_time": "15"}, {"func": "libvirt_network.cleanup_firewall_rule", "func_param": "params", "need_sleep_time": "5"}, {"func": "resume_migration_again", "func_param": "params", "need_sleep_time": "5"}]' migrate_desturi_port = "16509" migrate_desturi_type = "tcp" virsh_migrate_desturi = "qemu+tcp://${migrate_dest_host}/system" err_msg_during_mig = "unable to connect to server at.*: Connection timed out" - tcp_config_list = '{"tcp_keepalive_probes": "9", "tcp_keepalive_intvl": "60", "tcp_retries1": "4", "tcp_retries2": "8", "tcp_fin_timeout": "2"}' + tcp_config_list = '{"tcp_keepalive_probes": "3", "tcp_keepalive_intvl": "3", "tcp_retries1": "1", "tcp_retries2": "1", "tcp_fin_timeout": "2"}' recover_tcp_config_list = '{"tcp_keepalive_probes": "9", "tcp_keepalive_intvl": "75", "tcp_retries1": "3", "tcp_retries2": "15", "tcp_fin_timeout": "60"}' - proxy_issue: transport_type = "unix_proxy" diff --git a/libvirt/tests/cfg/migration/pause_postcopy_migration_and_recover/pause_by_domjobabort_and_recover.cfg b/libvirt/tests/cfg/migration/pause_postcopy_migration_and_recover/pause_by_domjobabort_and_recover.cfg index 83bed87b680..649a8e62d96 100644 --- a/libvirt/tests/cfg/migration/pause_postcopy_migration_and_recover/pause_by_domjobabort_and_recover.cfg +++ b/libvirt/tests/cfg/migration/pause_postcopy_migration_and_recover/pause_by_domjobabort_and_recover.cfg @@ -26,7 +26,7 @@ migrate_desturi_type = "tcp" virsh_migrate_desturi = "qemu+tcp://${migrate_dest_host}/system" status_error = "yes" - migrate_speed = "5" + migrate_speed = "15" stress_package = "stress" stress_args = "--cpu 8 --io 4 --vm 2 --vm-bytes 128M --timeout 20s" postcopy_options = "--timeout 4 --timeout-postcopy --postcopy" diff --git a/libvirt/tests/cfg/migration/pause_postcopy_migration_and_recover/pause_by_network_and_recover.cfg b/libvirt/tests/cfg/migration/pause_postcopy_migration_and_recover/pause_by_network_and_recover.cfg index 2839312e20a..b3dc700e847 100644 --- a/libvirt/tests/cfg/migration/pause_postcopy_migration_and_recover/pause_by_network_and_recover.cfg +++ b/libvirt/tests/cfg/migration/pause_postcopy_migration_and_recover/pause_by_network_and_recover.cfg @@ -27,10 +27,8 @@ stress_package = "stress" stress_args = "--cpu 8 --io 4 --vm 2 --vm-bytes 128M --timeout 20s" postcopy_options = "--timeout 4 --timeout-postcopy --postcopy --postcopy-bandwidth 5" - action_during_mig = '[{"func": "libvirt_network.check_established", "after_event": "iteration: '1'", "func_param": 'params'}, {"func": "libvirt_network.setup_firewall_rule", "func_param": "params", "need_sleep_time": "5"}, {"func": "do_common_check", "func_param": "params", "need_sleep_time": "90"}, {"func": "libvirt_network.cleanup_firewall_rule", "func_param": "params"}]' + action_during_mig = '[{"func": "libvirt_network.check_established", "after_event": "iteration: '1'", "func_param": 'params'}, {"func": "libvirt_network.setup_firewall_rule", "func_param": "params", "need_sleep_time": "5"}]' migrate_again = 'yes' - migrate_again_status_error = 'no' - action_during_mig_again = '[{"func": "do_common_check", "before_pause": "yes", "func_param": "params"}, {"func": "set_migrate_speed_to_high", "before_pause": "yes", "func_param": "params"}]' virsh_migrate_extra_mig_again = "--timeout 4 --timeout-postcopy --postcopy --postcopy-resume" postcopy_resume_migration = "yes" migrate_speed_high = "1048576" @@ -38,12 +36,10 @@ expected_dest_state = "running" expected_src_state = "paused" dominfo_check = "Persistent: no" - expected_event_src = ["event 'lifecycle' for domain.*: Suspended Post-copy Error", "event 'lifecycle' for domain .*: Suspended Post-copy", "event 'lifecycle' for domain .*: Stopped Migrated", "event 'job-completed' for domain"] - expected_event_target = ["event 'lifecycle' for domain.*: Resumed Post-copy Error", "event 'lifecycle' for domain.*: Resumed Post-copy", "event 'lifecycle' for domain.*: Resumed Migrated"] migrate_desturi_port = "16509" migrate_desturi_type = "tcp" virsh_migrate_desturi = "qemu+tcp://${migrate_dest_host}/system" - tcp_config_list = '{"tcp_keepalive_probes": "9", "tcp_keepalive_intvl": "60", "tcp_retries1": "4", "tcp_retries2": "8", "tcp_fin_timeout": "2"}' + tcp_config_list = '{"tcp_keepalive_probes": "3", "tcp_keepalive_intvl": "3", "tcp_retries1": "1", "tcp_retries2": "1", "tcp_fin_timeout": "2"}' recover_tcp_config_list = '{"tcp_keepalive_probes": "9", "tcp_keepalive_intvl": "75", "tcp_retries1": "3", "tcp_retries2": "15", "tcp_fin_timeout": "60"}' func_supported_since_libvirt_ver = (8, 5, 0) @@ -68,7 +64,15 @@ firewall_rule_on_dest = "ipv4 filter INPUT 0 -p tcp --dport ${port_to_check} -j DROP" firewall_rule_on_src = "ipv4 filter INPUT 0 -p tcp --sport ${port_to_check} -j DROP" err_msg = "job 'migration in' failed in post-copy phase" + migrate_again_status_error = 'no' + action_during_mig_again = '[{"func": "do_common_check", "before_pause": "yes", "func_param": "params"}, {"func": "set_migrate_speed_to_high", "before_pause": "yes", "func_param": "params"}]' + expected_event_src = ["event 'lifecycle' for domain.*: Suspended Post-copy Error", "event 'lifecycle' for domain .*: Suspended Post-copy", "event 'lifecycle' for domain .*: Stopped Migrated", "event 'job-completed' for domain"] + expected_event_target = ["event 'lifecycle' for domain.*: Resumed Post-copy Error", "event 'lifecycle' for domain.*: Resumed Post-copy", "event 'lifecycle' for domain.*: Resumed Migrated"] - libvirt_layer: firewall_rule_on_dest = "ipv4 filter INPUT 0 -p tcp --dport ${migrate_desturi_port} -j DROP" firewall_rule_on_src = "ipv4 filter INPUT 0 -p tcp --sport ${migrate_desturi_port} -j DROP" - err_msg = "internal error: client socket is closed|connection closed due to keepalive timeout" + err_msg = "internal error: client socket is closed|connection closed due to keepalive timeout|Cannot recv data: Connection timed out" + migrate_again_status_error = 'yes' + err_msg_again = "QEMU reports migration is still running" + expected_event_src = ["event 'lifecycle' for domain.*: Suspended Post-copy Error", "event 'lifecycle' for domain .*: Suspended Post-copy"] + expected_event_target = ["event 'lifecycle' for domain.*: Resumed Post-copy"] diff --git a/libvirt/tests/cfg/migration/pause_postcopy_migration_and_recover/unattended_migration.cfg b/libvirt/tests/cfg/migration/pause_postcopy_migration_and_recover/unattended_migration.cfg index 924b88f0fba..6e2c46501a0 100644 --- a/libvirt/tests/cfg/migration/pause_postcopy_migration_and_recover/unattended_migration.cfg +++ b/libvirt/tests/cfg/migration/pause_postcopy_migration_and_recover/unattended_migration.cfg @@ -67,9 +67,10 @@ expected_event_src = ["event 'lifecycle' for domain .*: Suspended Post-copy"] expected_event_src_2 = ["event 'lifecycle' for domain .*: Stopped Migrated", "event 'job-completed' for domain"] expected_event_target = ["event 'lifecycle' for domain.*: Resumed Post-copy", "event 'lifecycle' for domain.*: Resumed Migrated"] - tcp_config_list = '{"tcp_keepalive_probes": "9", "tcp_keepalive_intvl": "60", "tcp_retries1": "4", "tcp_retries2": "8", "tcp_fin_timeout": "2"}' + tcp_config_list = '{"tcp_keepalive_probes": "3", "tcp_keepalive_intvl": "3", "tcp_retries1": "1", "tcp_retries2": "1", "tcp_fin_timeout": "2"}' recover_tcp_config_list = '{"tcp_keepalive_probes": "9", "tcp_keepalive_intvl": "75", "tcp_retries1": "3", "tcp_retries2": "15", "tcp_fin_timeout": "60"}' action_during_mig = '[{"func": "libvirt_network.check_established", "after_event": "iteration: '1'", "func_param": 'params'}, {"func": "check_event_before_unattended", "func_param": "params"}, {"func": "libvirt_network.setup_firewall_rule", "func_param": "params"}, {"func": "do_common_check", "func_param": "params", "need_sleep_time": "90"}, {"func": "wait_for_unattended_mig", "func_param": "params"}, {"func": "libvirt_network.cleanup_firewall_rule", "func_param": "params"}]' + action_during_mig = '[{"func": "libvirt_network.check_established", "after_event": "iteration: '1'", "func_param": 'params'}, {"func": "check_event_before_unattended", "func_param": "params"}, {"func": "libvirt_network.setup_firewall_rule", "func_param": "params"}, {"func": "do_common_check", "func_param": "params", "need_sleep_time": "15"}, {"func": "wait_for_unattended_mig", "func_param": "params"}]' variants migration_options: - with_undefinesource_persistent: virsh_migrate_extra = "--undefinesource --persistent" diff --git a/libvirt/tests/cfg/migration/pause_postcopy_migration_and_recover/unattended_migration_and_disruptive.cfg b/libvirt/tests/cfg/migration/pause_postcopy_migration_and_recover/unattended_migration_and_disruptive.cfg index 09ee9aa2914..0518e945144 100644 --- a/libvirt/tests/cfg/migration/pause_postcopy_migration_and_recover/unattended_migration_and_disruptive.cfg +++ b/libvirt/tests/cfg/migration/pause_postcopy_migration_and_recover/unattended_migration_and_disruptive.cfg @@ -64,10 +64,10 @@ virsh_migrate_extra = "--migrateuri tcp://${migrate_dest_host}:${port_to_check} --listen-address ${migrate_dest_host}" firewall_rule_on_dest = "ipv4 filter INPUT 0 -p tcp --dport ${port_to_check} -j DROP" firewall_rule_on_src = "ipv4 filter INPUT 0 -p tcp --sport ${port_to_check} -j DROP" - action_during_mig = '[{"func": "libvirt_network.check_established", "after_event": "iteration: '1'", "func_param": 'params'}, {"func": "libvirt_service.kill_service", "func_param": "params"}, {"func": "libvirt_network.setup_firewall_rule", "func_param": "params", "need_sleep_time": "5"}, {"func": "libvirt_network.cleanup_firewall_rule", "func_param": "params", "need_sleep_time": "90"}, {"func": "do_migration", "func_param": "params", "need_sleep_time": "10"}]' + action_during_mig = '[{"func": "libvirt_network.check_established", "after_event": "iteration: '1'", "func_param": 'params'}, {"func": "libvirt_service.kill_service", "func_param": "params"}, {"func": "libvirt_network.setup_firewall_rule", "func_param": "params", "need_sleep_time": "5"}, {"func": "libvirt_network.cleanup_firewall_rule", "func_param": "params", "need_sleep_time": "10"}, {"func": "do_migration", "func_param": "params", "need_sleep_time": "10"}]' status_error = "no" status_error_during_mig = "no" - tcp_config_list = '{"tcp_keepalive_probes": "9", "tcp_keepalive_intvl": "60", "tcp_retries1": "4", "tcp_retries2": "8", "tcp_fin_timeout": "2"}' + tcp_config_list = '{"tcp_keepalive_probes": "3", "tcp_keepalive_intvl": "3", "tcp_retries1": "1", "tcp_retries2": "1", "tcp_fin_timeout": "2"}' recover_tcp_config_list = '{"tcp_keepalive_probes": "9", "tcp_keepalive_intvl": "75", "tcp_retries1": "3", "tcp_retries2": "15", "tcp_fin_timeout": "60"}' action_during_do_mig = '[{"func": "set_migrate_speed_to_high", "before_pause": "yes", "func_param": "params"}]' - pause_by_proxy: diff --git a/libvirt/tests/cfg/migration_with_copy_storage/async_job/abort_job.cfg b/libvirt/tests/cfg/migration_with_copy_storage/async_job/abort_job.cfg new file mode 100644 index 00000000000..7452e865e02 --- /dev/null +++ b/libvirt/tests/cfg/migration_with_copy_storage/async_job/abort_job.cfg @@ -0,0 +1,77 @@ +- migration_with_copy_storage.async_job.abort_job: + type = abort_job + migration_setup = 'yes' + # 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 + start_vm = "yes" + # 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}" + client_ip = "${migrate_source_host}" + client_user = "root" + client_pwd = "${migrate_source_pwd}" + simple_disk_check_after_mig = "yes" + status_error = "yes" + setup_nfs = "no" + nfs_mount_dir = + setup_local_nfs = "no" + storage_type = "" + port_to_check = "49153" + migrate_again = "yes" + migrate_again_status_error = 'no' + stress_package = "stress" + stress_args = "--cpu 8 --io 4 --vm 4 --vm-bytes 128M --timeout 50s" + action_during_mig_again = '[{"func": "libvirt_network.check_established", "func_param": "params", "need_sleep_time": "1"}]' + domjobabort_on_src = "yes" + variants: + - p2p: + virsh_migrate_options = "--live --p2p --verbose" + - non_p2p: + virsh_migrate_options = "--live --verbose" + variants: + - with_precopy: + variants: + - tcp: + migrate_desturi_port = "16509" + migrate_desturi_type = "tcp" + virsh_migrate_desturi = "qemu+tcp://${migrate_dest_host}/system" + - unix_proxy: + desturi_socket_path = "/tmp/desturi-socket" + migrateuri_socket_path = "/var/lib/libvirt/qemu/migrateuri-socket" + disks_uri_socket_path = "/var/lib/libvirt/qemu/disks-uri-socket" + migrate_desturi_type = "unix_proxy" + virsh_migrate_desturi = "qemu+unix:///system?socket=${desturi_socket_path}" + variants: + - copy_storage_all: + virsh_migrate_extra = "--copy-storage-all" + - copy_storage_inc: + virsh_migrate_extra = "--copy-storage-inc" + variants: + - with_tls: + virsh_migrate_extra = "${virsh_migrate_extra} --tls" + transport_type = "tls" + custom_pki_path = "/etc/pki/qemu" + qemu_tls = "yes" + server_cn = "ENTER.YOUR.EXAMPLE.SERVER_CN" + client_cn = "ENTER.YOUR.EXAMPLE.CLIENT_CN" + - without_tls: + variants: + - abort_in_storage_copy_phase: + action_during_mig = '[{"func": "libvirt_network.check_established", "func_param": "params", "need_sleep_time": "3"}, {"func": "do_domjobabort", "func_param": "params"}]' + expected_event_src = ["block-job.*Block Copy for.* failed", "block-job-2.*Block Copy for vda failed"] + expected_event_target = ["lifecycle.*Stopped Failed"] + err_msg = "operation aborted: migration out: canceled by client" + - abort_in_memory_copy_phase: + action_during_mig = '[{"func": "libvirt_network.check_established", "after_event": "migration-iteration", "func_param": "params", "wait_for_after_event_timeout": "600"}, {"func": "do_domjobabort", "func_param": "params"}]' + expected_event_target = ["lifecycle.*Stopped Failed"] + err_msg = "operation aborted: job 'migration out' canceled by client" diff --git a/libvirt/tests/cfg/migration_with_copy_storage/async_job/query_domain_job_info.cfg b/libvirt/tests/cfg/migration_with_copy_storage/async_job/query_domain_job_info.cfg new file mode 100644 index 00000000000..3304ded2545 --- /dev/null +++ b/libvirt/tests/cfg/migration_with_copy_storage/async_job/query_domain_job_info.cfg @@ -0,0 +1,57 @@ +- migration_with_copy_storage.async_job.query_domain_job_info: + type = query_domain_job_info + migration_setup = 'yes' + # 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}" + client_ip = "${migrate_source_host}" + client_user = "root" + client_pwd = "${migrate_source_pwd}" + check_network_accessibility_after_mig = "yes" + storage_type = 'file' + start_vm = "yes" + setup_ssh = "yes" + migrate_desturi_port = "16509" + migrate_desturi_type = "tcp" + virsh_migrate_desturi = "qemu+tcp://${migrate_dest_host}/system" + setup_nfs = "no" + nfs_mount_dir = + status_error = "no" + str_items = {"Job type": "Unbounded", "Operation": "Outgoing migration"} + s_all_items = ["Time elapsed", "Data processed", "Data remaining", "Data total", "File processed", "File remaining", "File total"] + m_all_items = ["Time elapsed", "Data remaining", "Memory processed", "Memory remaining", "Memory total", "Memory bandwidth", "Page size", "Iteration", "File processed", "File total", "Constant pages", "Normal pages", "Normal data", "Expected downtime", "Setup time"] + m_int_items = {"Dirty rate": "0", "Postcopy requests": "0", "File remaining": "0"} + m_sum_items = {"Data processed": "Memory processed+File processed", "Data total": "Memory total+File total"} + dest_items = {"error_msg": "migration statistics are available only on the source host"} + s_domjobinfo = {"src_items": {"str_items": ${str_items}, "all_items": ${s_all_items}}, "dest_items": ${dest_items}} + m_domjobinfo = {"src_items": {"str_items": ${str_items}, "all_items": ${m_all_items}, "int_items": ${m_int_items}, "sum_items": ${m_sum_items}}, "dest_items": ${dest_items}} + action_during_mig = [{"func": "libvirt_monitor.check_domjobinfo_output", "func_param": {"vm_name": "${main_vm}", "expected_domjobinfo": ${s_domjobinfo}, "remote_ip": "${server_ip}"}, "need_sleep_time": "5"}, {"func": "libvirt_monitor.check_domjobinfo_output", "after_event": "migration-iteration", "func_param": {"vm_name": "${main_vm}", "expected_domjobinfo": ${m_domjobinfo}, "remote_ip": "${server_ip}"}, "wait_for_after_event_timeout": 120}] + src_str_items_complete = {"Job type": "Completed", "Operation": "Outgoing migration"} + src_all_items_complete = ["Time elapsed", "Time elapsed w/o network", "Data processed", "Data total", "Memory processed", "Memory total", "Memory bandwidth", "Page size", "Iteration", "File processed", "File total", "Constant pages", "Normal pages", "Normal data", "Total downtime", "Downtime w/o network", "Setup time"] + src_int_items_complete = {"Data remaining": "0", "Memory remaining": "0", "Dirty rate": "0", "Postcopy requests": "0", "File remaining": "0"} + dest_str_items_complete = {"Job type": "Completed", "Operation": "Incoming migration"} + dest_all_items_complete = ["Time elapsed", "Time elapsed w/o network", "Data processed", "Data total", "Memory processed", "Memory total", "Memory bandwidth", "Page size", "Iteration", "Constant pages", "Normal pages", "Normal data", "Total downtime", "Downtime w/o network", "Setup time"] + dest_int_items_complete = {"Data remaining": "0", "Memory remaining": "0", "Dirty rate": "0", "Postcopy requests": "0"} + expected_domjobinfo_complete = {"src_items": {"str_items": ${src_str_items_complete}, "all_items": ${src_all_items_complete}, "int_items": ${src_int_items_complete}}, "dest_items": {"str_items": ${dest_str_items_complete}, "all_items": ${dest_all_items_complete}, "int_items": ${dest_int_items_complete}}} + variants: + - p2p: + virsh_migrate_options = '--live --p2p --verbose' + - non_p2p: + virsh_migrate_options = '--live --verbose' + variants: + - copy_storage_all: + copy_storage_option = "--copy-storage-all" + - copy_storage_inc: + copy_storage_option = "--copy-storage-inc" diff --git a/libvirt/tests/cfg/migration_with_copy_storage/autoskipped_disks.cfg b/libvirt/tests/cfg/migration_with_copy_storage/autoskipped_disks.cfg new file mode 100644 index 00000000000..234d7f691f1 --- /dev/null +++ b/libvirt/tests/cfg/migration_with_copy_storage/autoskipped_disks.cfg @@ -0,0 +1,77 @@ +- migration_with_copy_storage.autoskipped_disks: + type = autoskipped_disks + migration_setup = 'yes' + # 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 + start_vm = "no" + # 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}" + client_ip = "${migrate_source_host}" + client_user = "root" + client_pwd = "${migrate_source_pwd}" + simple_disk_check_after_mig = "yes" + migrate_desturi_port = "16509" + migrate_desturi_type = "tcp" + virsh_migrate_desturi = "qemu+tcp://${migrate_dest_host}/system" + status_error = "no" + variants: + - p2p: + virsh_migrate_options = "--live --p2p --verbose" + - non_p2p: + virsh_migrate_options = "--live --verbose" + variants: + - local_storage: + setup_nfs = "no" + nfs_mount_dir = + setup_local_nfs = "no" + storage_type = "" + - shared_storage: + storage_type = 'nfs' + setup_local_nfs = 'yes' + disk_type = "file" + disk_source_protocol = "netfs" + mnt_path_name = ${nfs_mount_dir} + variants: + - copy_storage_all: + virsh_migrate_extra = "--copy-storage-all" + - copy_storage_inc: + virsh_migrate_extra = "--copy-storage-inc" + variants test_case: + - disk_with_shareable: + second_disk_dict = {"device": "disk", "type_name": "file", "driver": {"name": "qemu", "type": "raw", "cache": "none"}, "target": {"dev": "vdb", "bus": "virtio"}, "share": True} + second_disk_name = "shareable.raw" + local_storage: + status_error = "yes" + err_msg = "Unsafe migration: Migration without shared storage is unsafe" + - disk_with_readonly: + second_disk_dict = {"device": "disk", "type_name": "file", "driver": {"name": "qemu", "type": "raw"}, "target": {"dev": "vdb", "bus": "virtio"}, "readonly": True} + second_disk_name = "readonly.raw" + local_storage: + status_error = "yes" + err_msg = "No such file or directory" + - cdrom_with_empty_source: + second_disk_dict = {"device": "cdrom", "type_name": "file", "driver": {"name": "qemu"}, "target": {"dev": "sda", "bus": "sata"}, "readonly": True} + - cdrom_with_startuppolicy: + second_disk_name = "cdrom.iso" + variants: + - optional: + startup_policy = {"startupPolicy": "optional"} + - requisite: + startup_policy = {"startupPolicy": "requisite"} + - mandatory: + startup_policy = {"startupPolicy": "mandatory"} + local_storage: + status_error = "yes" + err_msg = "Cannot access storage file.*: No such file or directory" + second_disk_dict = {"device": "cdrom", "type_name": "file", "driver": {"name": "qemu", "type": "raw"}, "target": {"dev": "sda", "bus": "sata"}, "source": {"attrs": ${startup_policy}}, "readonly": True} diff --git a/libvirt/tests/cfg/migration_with_copy_storage/disk_io_load_in_vm.cfg b/libvirt/tests/cfg/migration_with_copy_storage/disk_io_load_in_vm.cfg new file mode 100644 index 00000000000..73203b1a903 --- /dev/null +++ b/libvirt/tests/cfg/migration_with_copy_storage/disk_io_load_in_vm.cfg @@ -0,0 +1,40 @@ +- migration_with_copy_storage.disk_io_load_in_vm: + type = disk_io_load_in_vm + migration_setup = 'yes' + # 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" + image_convert = "no" + migrate_desturi_port = "16509" + migrate_desturi_type = "tcp" + virsh_migrate_desturi = "qemu+tcp://${migrate_dest_host}/system" + start_vm = "yes" + setup_nfs = "no" + nfs_mount_dir = + server_ip = "${migrate_dest_host}" + server_user = "root" + server_pwd = "${migrate_dest_pwd}" + client_ip = "${migrate_source_host}" + client_user = "root" + client_pwd = "${migrate_source_pwd}" + status_error = "no" + variants: + - p2p: + virsh_migrate_options = "--live --p2p --verbose" + - non_p2p: + virsh_migrate_options = "--live --verbose" + variants: + - with_sync_writes: + virsh_migrate_extra = "--copy-storage-synchronous-writes" + - without_sync_writes: + variants: + - copy_storage_all: + copy_storage_option = "--copy-storage-all" + - copy_storage_inc: + copy_storage_option = "--copy-storage-inc" diff --git a/libvirt/tests/cfg/migration_with_copy_storage/disk_type_coverage/block_disk.cfg b/libvirt/tests/cfg/migration_with_copy_storage/disk_type_coverage/block_disk.cfg new file mode 100644 index 00000000000..1891f05b5dd --- /dev/null +++ b/libvirt/tests/cfg/migration_with_copy_storage/disk_type_coverage/block_disk.cfg @@ -0,0 +1,40 @@ +- migration_with_copy_storage.disk_type_coverage.block_disk: + type = block_disk + migration_setup = 'yes' + # 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" + image_convert = "no" + status_error = "no" + migrate_desturi_port = "16509" + migrate_desturi_type = "tcp" + virsh_migrate_desturi = "qemu+tcp://${migrate_dest_host}/system" + start_vm = "no" + setup_nfs = "no" + nfs_mount_dir = + server_ip = "${migrate_dest_host}" + server_user = "root" + server_pwd = "${migrate_dest_pwd}" + client_ip = "${migrate_source_host}" + client_user = "root" + client_pwd = "${migrate_source_pwd}" + target_type = "vdb" + attach_disk_args = "--config --driver qemu --subdriver raw" + scsi_disk_option = "lbpu=1 lbpws=1" + check_disk_after_mig = "yes" + variants: + - p2p: + virsh_migrate_options = "--live --p2p --verbose" + - non_p2p: + virsh_migrate_options = "--live --verbose" + variants: + - copy_storage_all: + copy_storage_option = "--copy-storage-all" + - copy_storage_inc: + copy_storage_option = "--copy-storage-inc" diff --git a/libvirt/tests/cfg/migration_with_copy_storage/migrate_disks.cfg b/libvirt/tests/cfg/migration_with_copy_storage/migrate_disks.cfg new file mode 100644 index 00000000000..d4ba15bd32a --- /dev/null +++ b/libvirt/tests/cfg/migration_with_copy_storage/migrate_disks.cfg @@ -0,0 +1,76 @@ +- migration_with_copy_storage.migrate_disks: + type = migrate_disks + migration_setup = 'yes' + # 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" + image_convert = "no" + migrate_desturi_port = "16509" + migrate_desturi_type = "tcp" + virsh_migrate_desturi = "qemu+tcp://${migrate_dest_host}/system" + server_ip = "${migrate_dest_host}" + server_user = "root" + server_pwd = "${migrate_dest_pwd}" + client_ip = "${migrate_source_host}" + client_user = "root" + client_pwd = "${migrate_source_pwd}" + start_vm = "no" + disk2_name = "mig_disk2.qcow2" + disk2_dict = {"device": "disk", "type_name":"file", "driver": {"name": "qemu", "type":"qcow2"}, "target":{"dev": "vdb", "bus": "virtio"}} + variants: + - copy_storage_all: + copy_storage_option = "--copy-storage-all" + - copy_storage_inc: + copy_storage_option = "--copy-storage-inc" + variants: + - p2p: + virsh_migrate_options = "--live --p2p --verbose" + - non_p2p: + virsh_migrate_options = "--live --verbose" + variants disks: + - disk1: + setup_nfs = "no" + nfs_mount_dir = + virsh_migrate_extra = "--migrate-disks vda" + status_error = "yes" + err_msg = "Unsafe migration: Migration without shared storage is unsafe" + - disk1_disk2: + setup_nfs = "no" + nfs_mount_dir = + virsh_migrate_extra = "--migrate-disks vda,vdb" + status_error = "no" + - disk1_disk2_disk3: + virsh_migrate_extra = "--migrate-disks vda,vdb,vdc" + storage_type = 'nfs' + setup_local_nfs = 'yes' + status_error = "no" + disk3_name = "mig_disk3.raw" + disk3_dict = {"device": "disk", "type_name":"file", "driver": {"name": "qemu", "type":"raw"}, "target":{"dev": "vdc", "bus": "virtio"}, "share": True} + - disk1_disk2_disk4: + virsh_migrate_extra = "--migrate-disks vda,vdb,vdd" + storage_type = 'nfs' + setup_local_nfs = 'yes' + status_error = "yes" + err_msg = "Operation not supported: Cannot migrate empty or read-only disk vdd" + disk4_name = "mig_disk4.raw" + disk4_dict = {"device": "disk", "type_name":"file", "driver": {"name": "qemu", "type":"raw"}, "target":{"dev": "vdd", "bus": "virtio"}, "readonly": True} + - disk1_disk2_disk_nonexist: + setup_nfs = "no" + nfs_mount_dir = + virsh_migrate_extra = "--migrate-disks vda,vdb,aaa" + status_error = "yes" + err_msg = "invalid argument: disk target aaa not found" + - disk1_disk2_disk5: + no aarch64 + setup_nfs = "no" + nfs_mount_dir = + virsh_migrate_extra = "--migrate-disks vda,vdb,sda" + status_error = "yes" + err_msg = "Operation not supported: Cannot migrate empty or read-only disk sda" + disk5_dict = {"device": "cdrom", "type_name":"file", "driver": {"name": "qemu", "type":"raw"}, "target":{"dev": "sda", "bus": "sata"}, "readonly": True} diff --git a/libvirt/tests/cfg/migration_with_copy_storage/migrate_vm_disk_on_shared_storage.cfg b/libvirt/tests/cfg/migration_with_copy_storage/migrate_vm_disk_on_shared_storage.cfg index e65fc375da4..8487816a142 100644 --- a/libvirt/tests/cfg/migration_with_copy_storage/migrate_vm_disk_on_shared_storage.cfg +++ b/libvirt/tests/cfg/migration_with_copy_storage/migrate_vm_disk_on_shared_storage.cfg @@ -30,7 +30,7 @@ virsh_migrate_options = "--live --verbose" variants: - shared_storage: - err_msg = "unable to execute QEMU command 'block-export-add': Block node is read-only" + err_msg = "unable to execute QEMU command 'block-export-add'" variants: - copy_storage_all: copy_storage_option = "--copy-storage-all" diff --git a/libvirt/tests/cfg/migration_with_copy_storage/migration_bandwidth_limit.cfg b/libvirt/tests/cfg/migration_with_copy_storage/migration_bandwidth_limit.cfg new file mode 100644 index 00000000000..a27bd06cd2e --- /dev/null +++ b/libvirt/tests/cfg/migration_with_copy_storage/migration_bandwidth_limit.cfg @@ -0,0 +1,55 @@ +- migration_with_copy_storage.migration_bandwidth_limit: + type = migration_bandwidth_limit + migration_setup = 'yes' + # 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 + start_vm = "yes" + # 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}" + client_ip = "${migrate_source_host}" + client_user = "root" + client_pwd = "${migrate_source_pwd}" + status_error = "no" + simple_disk_check_after_mig = "no" + migrate_desturi_port = "16509" + migrate_desturi_type = "tcp" + virsh_migrate_desturi = "qemu+tcp://${migrate_dest_host}/system" + setup_nfs = "no" + nfs_mount_dir = + storage_type = "file" + bandwidth = "20" + jobinfo_item = "Memory bandwidth:" + precopy_bandwidth = "${bandwidth}" + compare_to_value = "${bandwidth}" + check_item = "bandwidth" + check_item_value = "20971520" + action_during_mig = '[{"func": "libvirt_disk.check_item_by_blockjob", "after_event": "block-job", "func_param": "params", "wait_for_after_event_timeout": "600"}, {"func": "check_domjobinfo_during_mig", "after_event": "migration-iteration", "func_param": "params"}]' + migrate_start_state = "running" + variants: + - p2p: + virsh_migrate_options = "--live --p2p --verbose" + - non_p2p: + virsh_migrate_options = "--live --verbose" + variants set_bandwidth: + - bandwidth: + virsh_migrate_extra = "--bandwidth ${bandwidth}" + - setspeed_before_migration: + - setspeed_during_migration: + check_item_value = "9223372036853727232" + action_during_mig = '[{"func": "set_bandwidth", "after_event": "block-job", "func_param": "params", "wait_for_after_event_timeout": "600"}, {"func": "libvirt_disk.check_item_by_blockjob", "func_param": "params", "need_sleep_time": "3"}, {"func": "check_domjobinfo_during_mig", "func_param": "params"}]' + variants: + - copy_storage_all: + copy_storage_option = "--copy-storage-all" + - copy_storage_inc: + copy_storage_option = "--copy-storage-inc" diff --git a/libvirt/tests/cfg/migration_with_copy_storage/migration_retain_sparsity.cfg b/libvirt/tests/cfg/migration_with_copy_storage/migration_retain_sparsity.cfg new file mode 100644 index 00000000000..39d0e18fc04 --- /dev/null +++ b/libvirt/tests/cfg/migration_with_copy_storage/migration_retain_sparsity.cfg @@ -0,0 +1,100 @@ +- migration_with_copy_storage.migration_retain_sparsity: + type = migration_retain_sparsity + migration_setup = 'yes' + # 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" + image_convert = "no" + status_error = "no" + migrate_desturi_port = "16509" + migrate_desturi_type = "tcp" + virsh_migrate_desturi = "qemu+tcp://${migrate_dest_host}/system" + start_vm = "no" + setup_nfs = "no" + nfs_mount_dir = + setup_local_nfs = "no" + server_ip = "${migrate_dest_host}" + server_user = "root" + server_pwd = "${migrate_dest_pwd}" + client_ip = "${migrate_source_host}" + client_user = "root" + client_pwd = "${migrate_source_pwd}" + disk_type = "file" + disk_size = "1G" + dd_count = "100" + disk_path = "/var/lib/avocado/data/avocado-vt/images" + target_dev_1 = "sda" + virsh_migrate_options = "--live --p2p --verbose --migrate-disks-detect-zeroes ${target_dev_1}" + mon_host = "EXAMPLE_MON_HOST" + client_name = "EXAMPLE_CLIENT_NAME" + client_key = "EXAMPLE_CLIENT_KEY" + ceph_pool_name = "migration-retain-sparsity-pool" + check_disk_after_mig = "yes" + check_disk_kname_after_mig = "${target_dev_1}" + libvirtd_file_type = "virtqemud" + libvirtd_debug_level = "1" + libvirtd_debug_filters = "1:*" + libvirtd_debug_file = "/var/log/libvirt/virtqemud.log" + check_str_local_log = '['"discard":"unmap","detect-zeroes":"unmap"']' + variants: + - copy_storage_all: + copy_storage_option = "--copy-storage-all" + - copy_storage_inc: + copy_storage_option = "--copy-storage-inc" + variants: + - src1_rbd: + src_driver_type_1 = "rbd" + disk_size = "300M" + dd_count = "30" + src_disk1_name = "retain_sparsity_test_disk1" + src_disk1_dict = {"device": "disk", "type_name": "block", "driver": {"name": "qemu", "type": "raw"}, "target": {"dev": "${target_dev_1}", "bus": "scsi"}} + - src1_raw: + src_driver_type_1 = "raw" + src_disk1_name = "retain_sparsity_test_disk1.img" + src_disk1_dict = {"device": "disk", "type_name": "file", "driver": {"name": "qemu", "type": "raw"}, "target": {"dev": "${target_dev_1}", "bus": "scsi"}, "source": {"attrs": {"file": "${disk_path}/${src_disk1_name}"}}} + - src1_qcow2: + src_driver_type_1 = "qcow2" + src_disk1_name = "retain_sparsity_test_disk1.img" + src_disk1_dict = {"device": "disk", "type_name": "file", "driver": {"name": "qemu", "type": "qcow2"}, "target": {"dev": "${target_dev_1}", "bus": "scsi"}, "source": {"attrs": {"file": "${disk_path}/${src_disk1_name}"}}} + variants: + - dest1_rbd: + disk_size = "300M" + dd_count = "30" + dest_device_type_1 = "block" + dest_driver_type_1 = "rbd" + dest_disk1_name = "retain_sparsity_test_disk2" + dest_disk1_dict = {"device": "disk", "type_name": "${dest_device_type_1}", "driver": {"name": "qemu", "type": "raw", "discard": "unmap"}, "target": {"dev": "${target_dev_1}", "bus": "scsi"}} + - dest1_raw: + dest_device_type_1 = "file" + dest_driver_type_1 = "raw" + dest_disk1_name = "${src_disk1_name}" + dest_disk1_dict = {"device": "disk", "type_name": "${dest_device_type_1}", "driver": {"name": "qemu", "type": "raw", "discard": "unmap"}, "target": {"dev": "${target_dev_1}", "bus": "scsi"}, "source": {"attrs": {"file": "${disk_path}/${dest_disk1_name}"}}} + - dest1_qcow2: + dest_device_type_1 = "file" + dest_driver_type_1 = "qcow2" + dest_disk1_name = "${src_disk1_name}" + dest_disk1_dict = {"device": "disk", "type_name": "${dest_device_type_1}", "driver": {"name": "qemu", "type": "qcow2"}, "target": {"dev": "${target_dev_1}", "bus": "scsi"}, "source": {"attrs": {"file": "${disk_path}/${dest_disk1_name}"}}} + variants: + - disk_num_1: + - disk_num_2: + disk2_name = "retain_sparsity_test_disk2.img" + target_dev_2 = "sdb" + virsh_migrate_options = "--live --p2p --verbose --migrate-disks-detect-zeroes ${target_dev_1},${target_dev_2}" + variants: + - src2_raw: + src_driver_type_2 = "raw" + - src2_qcow2: + src_driver_type_2 = "qcow2" + variants: + - dest2_raw: + dest_driver_type_2 = "raw" + - dest2_qcow2: + dest_driver_type_2 = "qcow2" + src_disk2_dict = {"device": "disk", "type_name": "file", "driver": {"name": "qemu", "type": "${src_driver_type_2}", "discard": "unmap"}, "target": {"dev": "${target_dev_2}", "bus": "scsi"}, "source": {"attrs": {"file": "${disk_path}/${disk2_name}"}}} + dest_disk2_dict = {"device": "disk", "type_name": "file", "driver": {"name": "qemu", "type": "${dest_driver_type_2}", "discard": "unmap"}, "target": {"dev": "${target_dev_2}", "bus": "scsi"}, "source": {"attrs": {"file": "${disk_path}/${disk2_name}"}}} diff --git a/libvirt/tests/cfg/migration_with_copy_storage/migration_with_backingchain.cfg b/libvirt/tests/cfg/migration_with_copy_storage/migration_with_backingchain.cfg index c404c85f4b8..8f720bb4901 100644 --- a/libvirt/tests/cfg/migration_with_copy_storage/migration_with_backingchain.cfg +++ b/libvirt/tests/cfg/migration_with_copy_storage/migration_with_backingchain.cfg @@ -28,7 +28,6 @@ disk_target1 = "vdb" disk_target2 = "vdc" disk_size = "1G" - disk_diff_rate = "0.7" setup_nfs = "no" nfs_mount_dir = common_disk_dict = '"type_name":"file", "driver": {"name": "qemu", "type":"qcow2"}' diff --git a/libvirt/tests/cfg/migration_with_copy_storage/migration_with_vhostvdpa.cfg b/libvirt/tests/cfg/migration_with_copy_storage/migration_with_vhostvdpa.cfg new file mode 100644 index 00000000000..69581dfc57c --- /dev/null +++ b/libvirt/tests/cfg/migration_with_copy_storage/migration_with_vhostvdpa.cfg @@ -0,0 +1,41 @@ +- migration_with_copy_storage.migration_with_vhostvdpa: + type = migration_with_vhostvdpa + migration_setup = 'yes' + # 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" + image_convert = "no" + migrate_desturi_port = "16509" + migrate_desturi_type = "tcp" + virsh_migrate_desturi = "qemu+tcp://${migrate_dest_host}/system" + server_ip = "${migrate_dest_host}" + server_user = "${remote_user}" + server_pwd = "${migrate_dest_pwd}" + client_ip = "${migrate_source_host}" + client_user = "${remote_user}" + client_pwd = "${migrate_source_pwd}" + start_vm = "yes" + setup_local_nfs = "yes" + storage_type = "nfs" + mnt_path_name = ${nfs_mount_dir} + virsh_migrate_extra = "--migrate-disks vdb" + status_error = "no" + check_disk_after_mig = "yes" + vhost_vdpa_disk = "/dev/vhost-vdpa-0" + disk_dict = {"device": "disk", "type_name": "vhostvdpa", "driver": {"name": "qemu", "type": "raw", "cache": "none", "io": "threads", "copy_on_read": "on", "discard": "unmap", "detect_zeroes": "on"}, "target": {"dev": "vdb", "bus": "virtio"}, "source": {"attrs": {"dev": "${vhost_vdpa_disk}"}}} + func_supported_since_libvirt_ver = (10, 0, 0) + only x86_64 + variants: + - p2p: + virsh_migrate_options = "--live --p2p --verbose" + - non_p2p: + virsh_migrate_options = "--live --verbose" + variants: + - copy_storage_all: + copy_storage_option = "--copy-storage-all" diff --git a/libvirt/tests/cfg/migration_with_copy_storage/network_data_transport/tcp_disks_uri.cfg b/libvirt/tests/cfg/migration_with_copy_storage/network_data_transport/tcp_disks_uri.cfg new file mode 100644 index 00000000000..bbcc6770d2d --- /dev/null +++ b/libvirt/tests/cfg/migration_with_copy_storage/network_data_transport/tcp_disks_uri.cfg @@ -0,0 +1,102 @@ +- migration_with_copy_storage.network_data_transport.tcp_disks_uri: + type = tcp + migration_setup = 'yes' + # 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}" + client_ip = "${migrate_source_host}" + client_user = "root" + client_pwd = "${migrate_source_pwd}" + status_error = "no" + migrate_desturi_port = "16509" + migrate_desturi_type = "tcp" + virsh_migrate_desturi = "qemu+tcp://${migrate_dest_host}/system" + port_to_check = "49160" + setup_nfs = "no" + nfs_mount_dir = + setup_local_nfs = "no" + storage_type = "" + start_vm = "yes" + ipv6_addr_des = "ENTER.YOUR.IPv6.TRAGET" + variants: + - p2p: + virsh_migrate_options = '--live --p2p --verbose' + - non_p2p: + virsh_migrate_options = '--live --verbose' + variants: + - copy_storage_all: + copy_storage_option = "--copy-storage-all" + - copy_storage_inc: + copy_storage_option = "--copy-storage-inc" + variants: + - tcp: + variants: + - ipv4_addr_and_port: + variants: + - with_migrateuri_and_listen_addr: + virsh_migrate_extra = "--migrateuri tcp://${migrate_dest_host} --listen-address 0.0.0.0 --disks-uri tcp://${migrate_dest_host}:${port_to_check}" + check_patterns = [r'ESTAB .*${migrate_dest_host}:${port_to_check}', r'LISTEN .*0.0.0.0:49152', r'LISTEN .*${migrate_dest_host}:${port_to_check}'] + - without_migrateuri_and_listen_addr: + virsh_migrate_extra = "--disks-uri tcp://${migrate_dest_host}:${port_to_check}" + check_patterns = [r'ESTAB .*${migrate_dest_host}:${port_to_check}', r'LISTEN .*${migrate_dest_host}:${port_to_check}'] + action_during_mig = '[{"func": "libvirt_network.check_sockets_statistics", "func_param": {"server_ip": "${server_ip}", "server_user": "${server_user}", "server_pwd": "${server_pwd}", "check_patterns": "${check_patterns}"}, "need_sleep_time": "5"}]' + - ipv6_addr_and_port: + variants: + - with_migrateuri_and_listen_addr: + virsh_migrate_extra = "--disks-uri tcp://[${ipv6_addr_des}]:${port_to_check} --migrateuri tcp://${migrate_dest_host} --listen-address 0.0.0.0" + check_patterns = [r'ESTAB .*${migrate_dest_host}:49152', r'ESTAB .*\[${ipv6_addr_des}\]:${port_to_check}', r'LISTEN .*0.0.0.0:49152', r'LISTEN .*\[${ipv6_addr_des}\]:${port_to_check}'] + - without_migrateuri_and_listen_addr: + virsh_migrate_extra = "--disks-uri tcp://[${ipv6_addr_des}]:${port_to_check}" + check_patterns = [r'ESTAB .*\[${ipv6_addr_des}\]:${port_to_check}', r'LISTEN .*\[${ipv6_addr_des}\]:${port_to_check}'] + action_during_mig = '[{"func": "libvirt_network.check_sockets_statistics", "after_event": "block-job", "func_param": {"server_ip": "${server_ip}", "server_user": "${server_user}", "server_pwd": "${server_pwd}", "check_patterns": "${check_patterns}"}, "wait_for_after_event_timeout": "600"}]' + - hostname_and_port: + dest_host = "ENTER.YOUR.EXAMPLE.SERVER_CN" + variants: + - with_migrateuri_and_listen_addr: + virsh_migrate_extra = "--disks-uri tcp://${dest_host}:${port_to_check} --migrateuri tcp://${migrate_dest_host} --listen-address 0.0.0.0" + check_patterns = [r'ESTAB .*${migrate_dest_host}:${port_to_check}', r'LISTEN .*0.0.0.0:49152', r'LISTEN .*${migrate_dest_host}:${port_to_check}'] + - without_migrateuri_and_listen_addr: + virsh_migrate_extra = "--disks-uri tcp://${dest_host}:${port_to_check}" + check_patterns = [r'ESTAB .*${migrate_dest_host}:${port_to_check}', r'LISTEN .*${migrate_dest_host}:${port_to_check}'] + - ipv4_addr: + variants: + - with_migrateuri_and_listen_addr: + virsh_migrate_extra = "--disks-uri tcp://${migrate_dest_host} --migrateuri tcp://${migrate_dest_host} --listen-address 0.0.0.0" + check_patterns = [r'ESTAB .*${migrate_dest_host}', r'LISTEN .*0.0.0.0:49152', r'LISTEN .*${migrate_dest_host}'] + - without_migrateuri_and_listen_addr: + virsh_migrate_extra = "--disks-uri tcp://${migrate_dest_host}" + check_patterns = [r'ESTAB .*${migrate_dest_host}', r'LISTEN .*${migrate_dest_host}'] + - ipv6_addr: + variants: + - with_migrateuri_and_listen_addr: + virsh_migrate_extra = "--disks-uri tcp://[${ipv6_addr_des}] --migrateuri tcp://${migrate_dest_host} --listen-address 0.0.0.0" + check_patterns = [r'ESTAB .*${migrate_dest_host}', r'ESTAB .*\[${ipv6_addr_des}\]', r'LISTEN .*0.0.0.0:49152', r'LISTEN .*\[${ipv6_addr_des}\]'] + - without_migrateuri_and_listen_addr: + virsh_migrate_extra = "--disks-uri tcp://[${ipv6_addr_des}]" + check_patterns = [r'ESTAB .*${migrate_dest_host}', r'ESTAB .*\[${ipv6_addr_des}\]', r'LISTEN .*\[${ipv6_addr_des}\]'] + action_during_mig = '[{"func": "libvirt_network.check_sockets_statistics", "after_event": "block-job", "func_param": {"server_ip": "${server_ip}", "server_user": "${server_user}", "server_pwd": "${server_pwd}", "check_patterns": "${check_patterns}"}, "wait_for_after_event_timeout": "600"}]' + - invalid_disks_uri: + status_error = "yes" + variants: + - invalid_ip_addr: + virsh_migrate_extra = "--disks-uri tcp://10.10.10.10" + err_msg = "Failed to bind socket: Cannot assign requested address" + - invalid_hostname: + virsh_migrate_extra = "--disks-uri tcp://aaaaa" + err_msg = "address resolution failed for .*: Name or service not known" + - with_disks_uri_and_disks_port: + status_error = "yes" + virsh_migrate_extra = "--disks-uri tcp://${migrate_dest_host} --disks-port 49888" + err_msg = "invalid argument: Both port and URI requested for disk migration while being mutually exclusive" diff --git a/libvirt/tests/cfg/migration_with_copy_storage/network_data_transport/tcp_listen_address.cfg b/libvirt/tests/cfg/migration_with_copy_storage/network_data_transport/tcp_listen_address.cfg new file mode 100644 index 00000000000..3bbd925485f --- /dev/null +++ b/libvirt/tests/cfg/migration_with_copy_storage/network_data_transport/tcp_listen_address.cfg @@ -0,0 +1,64 @@ +- migration_with_copy_storage.network_data_transport.tcp_listen_address: + type = tcp + migration_setup = 'yes' + # 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}" + client_ip = "${migrate_source_host}" + client_user = "root" + client_pwd = "${migrate_source_pwd}" + status_error = "no" + check_network_accessibility_after_mig = "yes" + migrate_desturi_port = "16509" + migrate_desturi_type = "tcp" + virsh_migrate_desturi = "qemu+tcp://${migrate_dest_host}/system" + setup_nfs = "no" + nfs_mount_dir = + setup_local_nfs = "no" + storage_type = "" + start_vm = "yes" + variants: + - p2p: + virsh_migrate_options = '--live --p2p --verbose' + - non_p2p: + virsh_migrate_options = '--live --verbose' + variants: + - target_ipv4_address: + check_patterns = [r'LISTEN .*${migrate_dest_host}'] + virsh_migrate_extra = "--listen-address ${migrate_dest_host}" + action_during_mig = '[{"func": "libvirt_network.check_sockets_statistics", "func_param": {"server_ip": "${server_ip}", "server_user": "${server_user}", "server_pwd": "${server_pwd}", "check_patterns": "${check_patterns}"}, "need_sleep_time": "5"}]' + - target_ipv6_address: + ipv6_config = "yes" + ipv6_addr_des = "ENTER.YOUR.IPv6.TRAGET" + check_patterns = [r'LISTEN .*${ipv6_addr_des}'] + virsh_migrate_extra = "--migrateuri tcp://[${ipv6_addr_des}] --listen-address ${ipv6_addr_des}" + action_during_mig = '[{"func": "libvirt_network.check_sockets_statistics", "func_param": {"server_ip": "${server_ip}", "server_user": "${server_user}", "server_pwd": "${server_pwd}", "check_patterns": "${check_patterns}"}, "need_sleep_time": "5"}]' + - all_ipv4: + check_patterns = [r'LISTEN .*0.0.0.0'] + virsh_migrate_extra = "--listen-address 0.0.0.0" + action_during_mig = '[{"func": "libvirt_network.check_sockets_statistics", "func_param": {"server_ip": "${server_ip}", "server_user": "${server_user}", "server_pwd": "${server_pwd}", "check_patterns": "${check_patterns}"}, "need_sleep_time": "5"}]' + - all_ipv6: + check_patterns = [r'LISTEN .*\*'] + virsh_migrate_extra = "--listen-address ::" + action_during_mig = '[{"func": "libvirt_network.check_sockets_statistics", "func_param": {"server_ip": "${server_ip}", "server_user": "${server_user}", "server_pwd": "${server_pwd}", "check_patterns": "${check_patterns}"}, "need_sleep_time": "5"}]' + - invalid_address: + status_error = "yes" + err_msg = "nbd-server-start.*Cannot assign requested address" + virsh_migrate_extra = "--listen-address 10.10.10.10" + variants: + - copy_storage_all: + copy_storage_option = "--copy-storage-all" + - copy_storage_inc: + copy_storage_option = "--copy-storage-inc" diff --git a/libvirt/tests/cfg/migration_with_copy_storage/network_data_transport/tcp_migrateuri_and_disks_port.cfg b/libvirt/tests/cfg/migration_with_copy_storage/network_data_transport/tcp_migrateuri_and_disks_port.cfg new file mode 100644 index 00000000000..6c6ce6bce11 --- /dev/null +++ b/libvirt/tests/cfg/migration_with_copy_storage/network_data_transport/tcp_migrateuri_and_disks_port.cfg @@ -0,0 +1,83 @@ +- migration_with_copy_storage.network_data_transport.tcp_migrateuri_and_disks_port: + type = tcp_migrateuri_and_disks_port + migration_setup = 'yes' + # 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}" + client_ip = "${migrate_source_host}" + client_user = "root" + client_pwd = "${migrate_source_pwd}" + status_error = "no" + migrate_desturi_port = "16509" + migrate_desturi_type = "tcp" + virsh_migrate_desturi = "qemu+tcp://${migrate_dest_host}/system" + setup_nfs = "no" + nfs_mount_dir = + ipv6_addr_des = "ENTER.YOUR.IPv6.TRAGET" + variants: + - p2p: + virsh_migrate_options = '--live --p2p --verbose' + - non_p2p: + virsh_migrate_options = '--live --verbose' + variants: + - copy_storage_all: + copy_storage_option = "--copy-storage-all" + variants: + - migrateuri: + variants: + - ipv4_addr_and_port: + migrateuri_port = "49777" + variants: + - default_port: + virsh_migrate_extra = "--migrateuri tcp://${migrate_dest_host}:${migrateuri_port}" + check_patterns = [r'ESTAB .*${migrate_dest_host}\]:${migrateuri_port}', r'ESTAB .*${migrate_dest_host}\]:49152'] + - valid_port: + disks_port = "49888" + virsh_migrate_extra = "--migrateuri tcp://${migrate_dest_host}:${migrateuri_port} --disks-port ${disks_port}" + check_patterns = [r'ESTAB .*${migrate_dest_host}\]:${migrateuri_port}', r'ESTAB .*${migrate_dest_host}\]:${disks_port}'] + - ipv6_addr_and_port: + migrateuri_port = "49777" + variants: + - default_port: + virsh_migrate_extra = "--migrateuri tcp://[${ipv6_addr_des}]:${migrateuri_port}" + check_patterns = [r'ESTAB .*\[${ipv6_addr_des}\]:49152', r'ESTAB .*\[${ipv6_addr_des}\]:${migrateuri_port}'] + - valid_port: + disks_port = "49888" + virsh_migrate_extra = "--migrateuri tcp://[${ipv6_addr_des}]:${migrateuri_port} --disks-port ${disks_port}" + check_patterns = [r'ESTAB .*\[${ipv6_addr_des}\]:${migrateuri_port}', r'ESTAB .*\[${ipv6_addr_des}\]:${disks_port}'] + - ipv4_addr: + variants: + - default_port: + check_patterns = [r'ESTAB .*${migrate_dest_host}\]:49152', r'ESTAB .*${migrate_dest_host}\]:49153'] + virsh_migrate_extra = "--migrateuri tcp://${migrate_dest_host}" + - valid_port: + disks_port = "49888" + check_patterns = [r'ESTAB .*${migrate_dest_host}\]:49152', r'ESTAB .*${migrate_dest_host}\]:${disks_port}'] + virsh_migrate_extra = "--migrateuri tcp://${migrate_dest_host} --disks-port ${disks_port}" + action_during_mig = '[{"func": "libvirt_network.check_sockets_statistics", "after_event": "block-job", "func_param": {"server_ip": "${server_ip}", "server_user": "${server_user}", "server_pwd": "${server_pwd}", "check_patterns": "${check_patterns}"}, "wait_for_after_event_timeout": "600"}]' + - invalid_migrateuri: + status_error = "yes" + migrateuri_port = "49777" + virsh_migrate_extra = "--migrateuri tcp://10.10.10.10:${migrateuri_port}" + err_msg = "'blockdev-add'.* Connection timed out" + - invalid_disks_port: + status_error = "yes" + variants: + - no_permission_port: + virsh_migrate_extra = "--migrateuri tcp://${migrate_dest_host} --disks-port 1000" + err_msg = "unable to execute QEMU command 'nbd-server-start': Failed to bind socket: Permission denied" + - libvirt_reserved_port: + virsh_migrate_extra = "--migrateuri tcp://${migrate_dest_host} --disks-port 49152" + err_msg = "error: internal error: Failed to reserve port 49152" diff --git a/libvirt/tests/cfg/migration_with_copy_storage/network_data_transport/tcp_port_reuse.cfg b/libvirt/tests/cfg/migration_with_copy_storage/network_data_transport/tcp_port_reuse.cfg index 9ab62113cdc..e9ac7dfd43a 100644 --- a/libvirt/tests/cfg/migration_with_copy_storage/network_data_transport/tcp_port_reuse.cfg +++ b/libvirt/tests/cfg/migration_with_copy_storage/network_data_transport/tcp_port_reuse.cfg @@ -24,14 +24,10 @@ migrate_desturi_port = "16509" migrate_desturi_type = "tcp" virsh_migrate_desturi = "qemu+tcp://${migrate_dest_host}/system" - port_to_check = "49153" - action_during_mig = '[{"func": "libvirt_network.check_established", "before_pause": "yes", "func_param": "params"}]' - action_during_mig_again = '[{"func": "libvirt_network.check_established", "before_pause": "yes", "func_param": "params"}]' migrate_again = "yes" migrate_again_status_error = 'no' setup_nfs = "no" nfs_mount_dir = - variants: - p2p: virsh_migrate_options = '--live --p2p --verbose' @@ -40,3 +36,12 @@ variants: - copy_storage_all: copy_storage_option = "--copy-storage-all" + variants: + - specify_port: + disks_port = "49666" + check_patterns = [r'ESTAB .*${migrate_dest_host}]:${disks_port}', r'ESTAB .*${migrate_dest_host}]:49152'] + virsh_migrate_extra = "--disks-port ${disks_port}" + - default_port: + check_patterns = [r'ESTAB .*${migrate_dest_host}]:49153', r'ESTAB .*${migrate_dest_host}]:49152'] + action_during_mig = '[{"func": "libvirt_network.check_sockets_statistics", "after_event": "block-job", "func_param": {"server_ip": "${server_ip}", "server_user": "${server_user}", "server_pwd": "${server_pwd}", "check_patterns": "${check_patterns}"}, "wait_for_after_event_timeout": "600"}]' + action_during_mig_again = '[{"func": "libvirt_network.check_sockets_statistics", "after_event": "block-job", "func_param": {"server_ip": "${server_ip}", "server_user": "${server_user}", "server_pwd": "${server_pwd}", "check_patterns": "${check_patterns}"}, "wait_for_after_event_timeout": "600"}]' diff --git a/libvirt/tests/cfg/migration_with_copy_storage/network_data_transport/tls.cfg b/libvirt/tests/cfg/migration_with_copy_storage/network_data_transport/tls.cfg index fd963fad808..12d801f0a98 100644 --- a/libvirt/tests/cfg/migration_with_copy_storage/network_data_transport/tls.cfg +++ b/libvirt/tests/cfg/migration_with_copy_storage/network_data_transport/tls.cfg @@ -37,8 +37,6 @@ libvirtd_file_type = "virtqemud" libvirtd_debug_level = "1" libvirtd_debug_filters = "1:*" - check_str_local_log = '["blockdev-add.*tls-creds.*tls-hostname", "migrate-set-parameters.*tls-creds.*tls-hostname"]' - variants: - p2p: virsh_migrate_options = '--live --p2p --verbose' @@ -49,3 +47,9 @@ copy_storage_option = "--copy-storage-all" - copy_storage_inc: copy_storage_option = "--copy-storage-inc" + variants: + - with_precopy: + check_str_local_log = '["blockdev-add.*tls-creds.*tls-hostname", "migrate-set-parameters.*tls-creds.*tls-hostname"]' + - with_postcopy: + postcopy_options = '--postcopy --timeout 10 --timeout-postcopy' + check_str_local_log = '["blockdev-add.*tls-creds", "migrate-set-parameters.*tls-creds.*tls-hostname"]' diff --git a/libvirt/tests/cfg/migration_with_copy_storage/network_data_transport/tls_wrong_cert_configurations.cfg b/libvirt/tests/cfg/migration_with_copy_storage/network_data_transport/tls_wrong_cert_configurations.cfg index dd12dc4c481..ed1591a701d 100644 --- a/libvirt/tests/cfg/migration_with_copy_storage/network_data_transport/tls_wrong_cert_configurations.cfg +++ b/libvirt/tests/cfg/migration_with_copy_storage/network_data_transport/tls_wrong_cert_configurations.cfg @@ -46,7 +46,7 @@ variants cert_configuration: - no_client_cert_on_src: cert_path = "${custom_pki_path}/client-cert.pem" - err_msg = "Cannot read from TLS channel: Software caused connection abort" + err_msg = "Cannot read from TLS channel:" - no_server_cert_on_target: cert_path = "${custom_pki_path}/server-cert.pem" err_msg = "unable to execute QEMU command 'object-add': Unable to access credentials ${cert_path}: No such file or directory" diff --git a/libvirt/tests/cfg/migration_with_copy_storage/precreate_none_target_disk.cfg b/libvirt/tests/cfg/migration_with_copy_storage/precreate_none_target_disk.cfg new file mode 100644 index 00000000000..e3246e10497 --- /dev/null +++ b/libvirt/tests/cfg/migration_with_copy_storage/precreate_none_target_disk.cfg @@ -0,0 +1,49 @@ +- migration_with_copy_storage.precreate_none_target_disk: + type = precreate_none_target_disk + migration_setup = 'yes' + # 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" + image_convert = "no" + status_error = "no" + migrate_desturi_port = "16509" + migrate_desturi_type = "tcp" + virsh_migrate_desturi = "qemu+tcp://${migrate_dest_host}/system" + start_vm = "no" + setup_nfs = "no" + nfs_mount_dir = + server_ip = "${migrate_dest_host}" + server_user = "root" + server_pwd = "${migrate_dest_pwd}" + client_ip = "${migrate_source_host}" + client_user = "root" + client_pwd = "${migrate_source_pwd}" + target_pool_name = "no_precreate_target_disk_pool" + target_pool_target = "/var/lib/libvirt/migrate/" + target_pool_type = "dir" + disk_source_name = "/var/lib/libvirt/migrate/no_precreate_target_disk.img" + simple_disk_check_after_mig = "yes" + variants: + - p2p: + virsh_migrate_options = "--live --p2p --verbose" + - non_p2p: + virsh_migrate_options = "--live --verbose" + variants: + - raw_format: + disk_format = "raw" + - qcow2_format: + disk_format = "qcow2" + variants: + - copy_storage_all: + status_error = "no" + copy_storage_option = "--copy-storage-all" + - copy_storage_inc: + status_error = "yes" + err_msg = "Operation not supported: pre-creation of storage targets for incremental storage migration is not supported|Operation not supported: pre-creation of storage target.*for incremental storage migration of .* is not supported" + copy_storage_option = "--copy-storage-inc" diff --git a/libvirt/tests/cfg/migration_with_copy_storage/target_image_larger_than_source.cfg b/libvirt/tests/cfg/migration_with_copy_storage/target_image_larger_than_source.cfg new file mode 100644 index 00000000000..399a239ab64 --- /dev/null +++ b/libvirt/tests/cfg/migration_with_copy_storage/target_image_larger_than_source.cfg @@ -0,0 +1,60 @@ +- migration_with_copy_storage.target_image_larger_than_source: + type = target_image_larger_than_source + migration_setup = 'yes' + # 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" + image_convert = "no" + migrate_desturi_port = "16509" + migrate_desturi_type = "tcp" + virsh_migrate_desturi = "qemu+tcp://${migrate_dest_host}/system" + setup_nfs = "no" + server_ip = "${migrate_dest_host}" + server_user = "${remote_user}" + server_pwd = "${migrate_dest_pwd}" + client_ip = "${migrate_source_host}" + client_user = "${remote_user}" + client_pwd = "${migrate_source_pwd}" + status_error = "no" + start_vm = "no" + disk_size = "10G" + target_disk_size = "20G" + disk_format = "raw" + slice_offset = "0" + slice_size = "10737418240" + disk_source_name = "${nfs_mount_dir}/target_image_larger_than_source.raw" + disk_slice = {"slice_type": "storage", "slice_offset": "${slice_offset}", "slice_size": "${slice_size}"} + simple_disk_check_after_mig = "yes" + variants: + - p2p: + virsh_migrate_options = "--live --p2p --verbose --copy-storage-all" + - non_p2p: + virsh_migrate_options = "--live --verbose --copy-storage-all" + variants: + - src_disk_raw: + disk_type = "file" + src_disk_dict = {"type_name": "${disk_type}", "device": "disk", "driver": {"name": "qemu", "type":"raw"}, "source": {"attrs": {"file": "${disk_source_name}"}, "slices": ${disk_slice}}, "target":{"dev": "vda", "bus": "virtio"}} + - src_disk_block: + disk_type = "block" + src_iscsi_size = "11000M" + src_lv_name = "src_test_image" + src_vg_name = "src_copy_migration" + src_block_path = "/dev/${src_vg_name}/${src_lv_name}" + src_disk_dict = {"type_name": "${disk_type}", "device": "disk", "driver": {"name": "qemu", "type":"raw"}, "source": {"attrs": {"dev": "${src_block_path}"}, "slices": ${disk_slice}}, "target":{"dev": "vda", "bus": "virtio"}} + variants: + - target_disk_raw: + target_disk_type = "file" + target_disk_dict = {"type_name": "${target_disk_type}", "device": "disk", "driver": {"name": "qemu", "type":"raw"}, "source": {"attrs": {"file": "${disk_source_name}"}, "slices": ${disk_slice}}, "target":{"dev": "vda", "bus": "virtio"}} + - target_disk_block: + target_disk_type = "block" + target_iscsi_size = "21000M" + target_lv_name = "target_test_image" + target_vg_name = "target_copy_migration" + target_block_path = "/dev/${target_vg_name}/${target_lv_name}" + target_disk_dict = {"type_name": "${target_disk_type}", "device": "disk", "driver": {"name": "qemu", "type":"raw"}, "source": {"attrs": {"dev": "${target_block_path}"}, "slices": ${disk_slice}}, "target":{"dev": "vda", "bus": "virtio"}} diff --git a/libvirt/tests/cfg/migration_with_copy_storage/target_image_smaller_than_source.cfg b/libvirt/tests/cfg/migration_with_copy_storage/target_image_smaller_than_source.cfg new file mode 100644 index 00000000000..ab752b076dc --- /dev/null +++ b/libvirt/tests/cfg/migration_with_copy_storage/target_image_smaller_than_source.cfg @@ -0,0 +1,37 @@ +- migration_with_copy_storage.target_image_smaller_than_source: + type = target_image_smaller_than_source + migration_setup = 'yes' + # 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" + image_convert = "no" + migrate_desturi_port = "16509" + migrate_desturi_type = "tcp" + virsh_migrate_desturi = "qemu+tcp://${migrate_dest_host}/system" + setup_nfs = "no" + nfs_mount_dir = + server_ip = "${migrate_dest_host}" + server_user = "root" + server_pwd = "${migrate_dest_pwd}" + client_ip = "${migrate_source_host}" + client_user = "root" + client_pwd = "${migrate_source_pwd}" + status_error = "yes" + disk_size = "2G" + err_msg = "migration of disk vda failed: Source and target image have different sizes" + variants: + - p2p: + virsh_migrate_options = "--live --p2p --verbose" + - non_p2p: + virsh_migrate_options = "--live --verbose" + variants: + - copy_storage_all: + copy_storage_option = "--copy-storage-all" + - copy_storage_inc: + copy_storage_option = "--copy-storage-inc" diff --git a/libvirt/tests/cfg/numa/guest_numa.cfg b/libvirt/tests/cfg/numa/guest_numa.cfg index 00461ed5d82..38990953f66 100644 --- a/libvirt/tests/cfg/numa/guest_numa.cfg +++ b/libvirt/tests/cfg/numa/guest_numa.cfg @@ -7,6 +7,9 @@ max_mem = 2097152 hugepage_force_allocate = "yes" numa_cells_with_memory_required = 2 + cpu_mode = 'host-model' + aarch64: + cpu_mode = 'host-passthrough' variants: - possitive_test: cell_id_0 = "0" @@ -25,8 +28,8 @@ - no_numatune_mem: variants: - no_numatune_memnode: - qemu_cmdline_numa_cell_0 = "node,nodeid=0,cpus=0-1,mem=1024" - qemu_cmdline_numa_cell_1 = "node,nodeid=1,cpus=2-3,mem=1024" + qemu_cmdline_numa_cell_0 = "node,nodeid=0,cpus=0-1,memdev=ram-node0" + qemu_cmdline_numa_cell_1 = "node,nodeid=1,cpus=2-3,memdev=ram-node1" - numatune_memnode: memnode_nodeset_0 = 1 pseries: @@ -37,7 +40,6 @@ variants: - m_strict: memnode_mode_0 = "strict" - kernel_hp_file = "/sys/devices/system/node/node1/hugepages/hugepages-2048kB/nr_hugepages" - m_preferred: memnode_mode_0 = "preferred" - m_interleave: @@ -58,7 +60,6 @@ - mem_backend: no no_numatune_memnode..numatune_mem - hugepage: - vmpage_size_0 = "2048" vmpage_unit_0 = "KiB" vmpage_nodeset_0 = "0" qemu_cmdline_numa_cell_0 = "node,nodeid=0,cpus=0-1,memdev=ram-node0" @@ -69,6 +70,7 @@ cell_memory_1 = "1048576" variants: - 2M: + vmpage_size_0 = "2048" hugepage_size_0 = "2048" page_num_0 = "512" page_nodenum_0 = "1" @@ -83,6 +85,7 @@ pseries: page_nodenum_0 = "0" - 16M: + no aarch64, x86_64 max_mem = "2097152" vmpage_size_0 = "16384" hugepage_size_0 = "16384" @@ -91,7 +94,8 @@ pseries: page_nodenum_0 = "0" - host_total: - nr_pagesize_total = "1024" + vmpage_size_0 = "2048" + hugepage_mem_total = "2097152" - negative_test: status_error = "yes" cell_id_0 = "0" diff --git a/libvirt/tests/cfg/numa/guest_numa_hmat/hmat_info.cfg b/libvirt/tests/cfg/numa/guest_numa_hmat/hmat_info.cfg new file mode 100644 index 00000000000..c685b75b6a7 --- /dev/null +++ b/libvirt/tests/cfg/numa/guest_numa_hmat/hmat_info.cfg @@ -0,0 +1,50 @@ +- guest_numa_hmat.hmat_info: + type = hmat_info + take_regular_screendumps = no + start_vm = "no" + single_host_node = yes + cpu_mode = 'host-model' + no s390-virtio + aarch64: + cpu_mode = 'host-passthrough' + dmesg_pattern_0 = "Flags:00 Type:Access Latency Initiator, Initiator-Target[0-1]:10 nsec, Flags:00 Type:Read Latency Initiator, Initiator-Target[0-0]:6 nsec," + dmesg_pattern_1 = "Initiator-Target[1-1]:11 nsec, Flags:00 Type:Write Latency Initiator,Initiator-Target[0-0]:7 nsec, Initiator-Target[1-1]:12 nsec," + dmesg_pattern_2 = "Flags:00 Type:Access Bandwidth Initiator, Initiator-Target[0-1]:100 MB/s, Flags:00 Type:Read Bandwidth Initiator, Initiator-Target[0-0]:201 MB/s," + dmesg_pattern_3 = "Initiator-Target[1-1]:101 MB/s, Flags:00 Type:Write Bandwidth Initiator, Initiator-Target[0-0]:202 MB/s, Initiator-Target[1-1]:102 MB/s," + dmesg_pattern_4 = "Flags:01 Type:Read Latency Initiator, Initiator-Target[0-0]:5 nsec, Flags:01 Type:Access Bandwidth Initiator, Initiator-Target[0-0]:200 MB/s" + dmesg_pattern = "${dmesg_pattern_0}${dmesg_pattern_1}${dmesg_pattern_2}${dmesg_pattern_3}${dmesg_pattern_4}" + numa_cell0_cache0 = "{'size_unit': 'KiB', 'line_unit': 'B', 'policy': 'writeback', 'associativity': 'direct', 'line_value': '8', 'level': '1', 'size_value': '10'}" + numa_cell0_cache1 = "{'size_unit': 'KiB', 'line_unit': 'B', 'policy': 'writethrough', 'associativity': 'full', 'line_value': '16', 'level': '2', 'size_value': '128'}" + numa_cell0 = "{'caches': [${numa_cell0_cache0}, ${numa_cell0_cache1}], 'memory': '1048576', 'cpus': '0-1', 'unit': 'KiB', 'id': '0'}" + numa_cell1_cache0 = "{'size_unit': 'KiB', 'line_unit': 'B', 'policy': 'none', 'associativity': 'none','line_value': '8', 'level': '1', 'size_value': '10'}" + numa_cell1 = "{'caches': [${numa_cell1_cache0}], 'memory': '1048576', 'cpus': '2-3', 'unit': 'KiB', 'id': '1'}" + bandwidth0 = "{'cache': '1', 'initiator': '0', 'target': '0', 'type': 'access', 'unit': 'KiB', 'value': '204800'}" + bandwidth1 = "{'initiator': '0', 'target': '0', 'type': 'read', 'unit': 'KiB', 'value': '205824'}" + bandwidth2 = "{'initiator': '0', 'target': '0', 'type': 'write', 'unit': 'KiB', 'value': '206848'}" + bandwidth3 = "{'initiator': '0', 'target': '1', 'type': 'access', 'unit': 'KiB', 'value': '102400'}" + bandwidth4 = "{'initiator': '1', 'target': '1', 'type': 'read', 'unit': 'KiB', 'value': '103424'}" + bandwidth5 = "{'initiator': '1', 'target': '1', 'type': 'write', 'unit': 'KiB', 'value': '104448'}" + latency0 = "{'cache': '1', 'initiator': '0', 'target': '0', 'type': 'read', 'value': '5'}" + latency1 = "{'initiator': '0', 'target': '0', 'type': 'read', 'value': '6'}" + latency2 = "{'initiator': '0', 'target': '0', 'type': 'write', 'value': '7'}" + latency3 = "{'initiator': '0', 'target': '1', 'type': 'access', 'value': '10'}" + latency4 = "{'initiator': '1', 'target': '1', 'type': 'read', 'value': '11'}" + latency5 = "{'initiator': '1', 'target': '1', 'type': 'write', 'value': '12'}" + bandwidth = "[${bandwidth0}, ${bandwidth1}, ${bandwidth2}, ${bandwidth3}, ${bandwidth4}, ${bandwidth5}]" + latency = "[${latency0}, ${latency1}, ${latency2}, ${latency3}, ${latency4}, ${latency5}]" + interconnects = "'interconnects': {'bandwidth':${bandwidth}, 'latency': ${latency}}" + numa_cell = "'numa_cell': [${numa_cell0}, ${numa_cell1}]" + vm_attrs = "{'vcpu': 4, 'cpu': {'mode': '${cpu_mode}', ${numa_cell}, ${interconnects}}}" + qemu_check_initiator = "-numa node,nodeid=0,cpus=0-1,initiator=0,memdev=ram-node0 .*-numa node,nodeid=1,cpus=2-3,initiator=1,memdev=ram-node1" + qemu_check_lb_0 = "-numa hmat-lb,initiator=0,target=0,hierarchy=first-level,data-type=read-latency,latency=5 -numa hmat-lb,initiator=0,target=0,hierarchy=memory,data-type=read-latency,latency=6" + qemu_check_lb_1 = "-numa hmat-lb,initiator=0,target=0,hierarchy=memory,data-type=write-latency,latency=7 -numa hmat-lb,initiator=0,target=1,hierarchy=memory,data-type=access-latency,latency=10" + qemu_check_lb_2 = "-numa hmat-lb,initiator=1,target=1,hierarchy=memory,data-type=read-latency,latency=11 -numa hmat-lb,initiator=1,target=1,hierarchy=memory,data-type=write-latency,latency=12" + qemu_check_lb_3 = "-numa hmat-lb,initiator=0,target=0,hierarchy=first-level,data-type=access-bandwidth,bandwidth=204800K -numa hmat-lb,initiator=0,target=0,hierarchy=memory,data-type=read-bandwidth,bandwidth=205824K" + qemu_check_lb_4 = "-numa hmat-lb,initiator=0,target=0,hierarchy=memory,data-type=write-bandwidth,bandwidth=206848K -numa hmat-lb,initiator=0,target=1,hierarchy=memory,data-type=access-bandwidth,bandwidth=102400K" + qemu_check_lb_5 = "-numa hmat-lb,initiator=1,target=1,hierarchy=memory,data-type=read-bandwidth,bandwidth=103424K -numa hmat-lb,initiator=1,target=1,hierarchy=memory,data-type=write-bandwidth,bandwidth=104448K" + qemu_check_cache_0 = "-numa hmat-cache,node-id=0,size=10K,level=1,associativity=direct,policy=write-back,line=8" + qemu_check_cache_1 = "-numa hmat-cache,node-id=0,size=128K,level=2,associativity=complex,policy=write-through,line=16" + qemu_check_cache_2 = "-numa hmat-cache,node-id=1,size=10K,level=1,associativity=none,policy=none,line=8" + variants: + - @default: + func_supported_since_libvirt_ver = (7, 5, 0) \ No newline at end of file diff --git a/libvirt/tests/cfg/numa/guest_numa_node_tuning/auto_memory_placement_numad_fail.cfg b/libvirt/tests/cfg/numa/guest_numa_node_tuning/auto_memory_placement_numad_fail.cfg new file mode 100644 index 00000000000..bd0d4085590 --- /dev/null +++ b/libvirt/tests/cfg/numa/guest_numa_node_tuning/auto_memory_placement_numad_fail.cfg @@ -0,0 +1,15 @@ +- guest_numa_node_tuning.auto_memory_placement_numad_fail: + type = auto_memory_placement_numad_fail + take_regular_screendumps = no + start_vm = "no" + err_msg = "Failed to query numad for the advisory nodeset" + variants memory_binding_mode: + - mem_mode_strict: + mem_mode = 'strict' + - mem_mode_interleave: + mem_mode = 'interleave' + - mem_mode_preferred: + mem_mode = 'preferred' + - mem_mode_restrictive: + mem_mode = 'restrictive' + numa_memory = {'mode': '${mem_mode}', 'placement': 'auto'} diff --git a/libvirt/tests/cfg/numa/guest_numa_node_tuning/change_numa_tuning.cfg b/libvirt/tests/cfg/numa/guest_numa_node_tuning/change_numa_tuning.cfg index fb602b2837b..63fac1b29de 100644 --- a/libvirt/tests/cfg/numa/guest_numa_node_tuning/change_numa_tuning.cfg +++ b/libvirt/tests/cfg/numa/guest_numa_node_tuning/change_numa_tuning.cfg @@ -17,7 +17,4 @@ mem_mode = 'preferred' - mem_mode_restrictive: mem_mode = 'restrictive' - kernelpagesize_kB = '4' - aarch64: - kernelpagesize_kB = '64' numa_memory = {'mode': '${mem_mode}', 'nodeset': '%s'} diff --git a/libvirt/tests/cfg/numa/guest_numa_node_tuning/host_guest_mixed_memory_binding.cfg b/libvirt/tests/cfg/numa/guest_numa_node_tuning/host_guest_mixed_memory_binding.cfg new file mode 100644 index 00000000000..9e608912d7b --- /dev/null +++ b/libvirt/tests/cfg/numa/guest_numa_node_tuning/host_guest_mixed_memory_binding.cfg @@ -0,0 +1,51 @@ +- guest_numa_node_tuning.host_guest_mixed_memory_binding: + type = host_guest_mixed_memory_binding + take_regular_screendumps = no + start_vm = "no" + max_mem_value = "'max_mem_rt': 8388608, 'max_mem_rt_slots': 16, 'max_mem_rt_unit': 'KiB'" + mem_value = "'memory': 2072576, 'memory_unit': 'KiB'" + current_mem_value = ${mem_value} + vm_node0_mem = 1048576 + vm_node1_mem = 1024000 + numa_node0 = {'id': '0', 'cpus': '0', 'memory': '${vm_node0_mem}', 'unit': 'KiB'} + numa_node1 = {'id': '1', 'cpus': '1', 'memory': '${vm_node1_mem}', 'unit': 'KiB'} + numa_cell = "'numa_cell': [${numa_node0}, ${numa_node1}]" + cpu_mode = 'host-model' + no s390-virtio + aarch64: + mem_value = "'memory': 2097152, 'memory_unit': 'KiB'" + cpu_mode = 'host-passthrough' + variants host_numa: + - single_node: + single_host_node = yes + - multiple_nodes: + single_host_node = no + - no_node: + only no_mem_mode + variants memory_mode: + - mem_mode_strict: + mem_mode = 'strict' + numa_memory = {'mode': '${mem_mode}', 'nodeset': '%s'} + - mem_mode_interleave: + mem_mode = 'interleave' + numa_memory = {'mode': '${mem_mode}', 'nodeset': '%s'} + - mem_mode_preferred: + mem_mode = 'preferred' + numa_memory = {'mode': '${mem_mode}', 'nodeset': '%s'} + - mem_mode_restrictive: + func_supported_since_libvirt_ver = (9, 4, 0) + mem_mode = 'restrictive' + numa_memory = {'mode': '${mem_mode}', 'nodeset': '%s'} + - no_mem_mode: + variants memnode_mode: + - memnode_mode_strict: + memnode_mode = 'strict' + - memnode_mode_interleave: + memnode_mode = 'interleave' + - memnode_mode_preferred: + memnode_mode = 'preferred' + - memnode_mode_restrictive: + func_supported_since_libvirt_ver = (9, 4, 0) + memnode_mode = 'restrictive' + numa_memnode = [{'cellid': '0', 'mode': '${memnode_mode}', 'nodeset': '%s'}] + vm_attrs = {${max_mem_value}, ${mem_value}, ${current_mem_value}, 'vcpu': 2, 'cpu': {'mode': '${cpu_mode}', ${numa_cell}}} diff --git a/libvirt/tests/cfg/numa/guest_numa_node_tuning/memory_binding_setting.cfg b/libvirt/tests/cfg/numa/guest_numa_node_tuning/memory_binding_setting.cfg index 51be2e216d1..3eea87a728f 100644 --- a/libvirt/tests/cfg/numa/guest_numa_node_tuning/memory_binding_setting.cfg +++ b/libvirt/tests/cfg/numa/guest_numa_node_tuning/memory_binding_setting.cfg @@ -1,14 +1,14 @@ - guest_numa_node_tuning.memory_binding_setting: type = memory_binding_setting take_regular_screendumps = no - start_vm = "no" + start_vm = "no" mem_value = "'memory': 2072576, 'memory_unit': 'KiB'" - target_hugepages = "512" + hugepage_mem = 1048576 cpu_mode = 'host-model' aarch64: mem_value = "'memory': 2097152, 'memory_unit': 'KiB'" - target_hugepages = "3" cpu_mode = 'host-passthrough' + hugepage_mem = 1572864 current_mem_value = ${mem_value} vm_attrs = {${mem_value}, ${current_mem_value}, 'cpu': {'mode': '${cpu_mode}'}} variants memory_binding_nodeset: @@ -18,22 +18,16 @@ single_host_node = no variants memory_binding_mode: - mem_mode_strict: - mem_mode = 'strict' + mem_mode = 'strict' - mem_mode_interleave: - mem_mode = 'interleave' + mem_mode = 'interleave' - mem_mode_preferred: - mem_mode = 'preferred' + mem_mode = 'preferred' - mem_mode_restrictive: - mem_mode = 'restrictive' + mem_mode = 'restrictive' variants pagesize: - default_pagesize: only single_host_node - default_pagesize = 4 - aarch64: - default_pagesize = 64 - hugepage: memory_backing = {'hugepages': {}} - expected_hugepage_size = 2048 - aarch64: - expected_hugepage_size = 524288 numa_memory = {'mode': '${mem_mode}', 'nodeset': '%s'} diff --git a/libvirt/tests/cfg/numa/guest_numa_node_tuning/memory_binding_with_emulator_thread.cfg b/libvirt/tests/cfg/numa/guest_numa_node_tuning/memory_binding_with_emulator_thread.cfg index 58784a0ecc3..4136b619fa6 100644 --- a/libvirt/tests/cfg/numa/guest_numa_node_tuning/memory_binding_with_emulator_thread.cfg +++ b/libvirt/tests/cfg/numa/guest_numa_node_tuning/memory_binding_with_emulator_thread.cfg @@ -2,15 +2,19 @@ func_supported_since_libvirt_ver = (9, 3, 0) type = memory_binding_with_emulator_thread take_regular_screendumps = no - start_vm = "no" + start_vm = "no" numa_cell = "'numa_cell': [{'id': '0', 'cpus': '0-3', 'memory': '2097152', 'unit': 'KiB'}]" max_mem_value = "'max_mem_rt': 15360000, 'max_mem_rt_slots': 16, 'max_mem_rt_unit': 'KiB'" mem_value = "'memory': 2097152, 'memory_unit': 'KiB'" current_mem_value = ${mem_value} - vm_attrs = {${max_mem_value}, ${mem_value}, ${current_mem_value}, 'vcpu': 4, 'cpu': {'mode': 'host-model', ${numa_cell}}} + cpu_mode = 'host-model' + no s390-virtio + aarch64: + cpu_mode = 'host-passthrough' + vm_attrs = {${max_mem_value}, ${mem_value}, ${current_mem_value}, 'vcpu': 4, 'cpu': {'mode': '${cpu_mode}', ${numa_cell}}} mem_device_attrs = {'mem_model': 'dimm', 'target': {'size': 524288, 'node': 0, 'size_unit': 'KiB'}} qemu_line_hugepage_without_context = '-object {"qom-type":"memory-backend-file","id":"ram-node0".*"host-nodes":\[%s\].*-object {"qom-type":"memory-backend-file","id":"memdimm0".*"host-nodes":\[%s\]' - qemu_line_hugepage_with_context = '-object {"qom-type":"thread-context","id":"tc-ram-node0","node-affinity":\[%s\].*-object {"qom-type":"memory-backend-file","id":"ram-node0".*"host-nodes":\[%s\].*-object {"qom-type":"thread-context","id":"tc-memdimm0","node-affinity":\[%s\].*-object {"qom-type":"memory-backend-file","id":"memdimm0".*"host-nodes":\[%s\]' + qemu_line_hugepage_with_context = '-object {"qom-type":"thread-context","id":"tc-ram-node0","node-affinity":\[%s\].*-object {"qom-type":"memory-backend-file","id":"ram-node0".*"host-nodes":\[%s\].*-object {"qom-type":"thread-context","id":"tc-memdimm0","node-affinity":\[%s\].*-object {"qom-type":"memory-backend-file","id":"memdimm0".*"host-nodes":\[%s\]' qemu_line_default_mem_without_context = '-object {"qom-type":"memory-backend-ram","id":"ram-node0",.*"host-nodes":\[%s\].*-object {"qom-type":"memory-backend-ram","id":"memdimm0".*"host-nodes":\[%s\]' variants emulator_pin_cpu: - emulatorpin_single_node: @@ -24,7 +28,7 @@ overlap_emulatorpin_nodeset = yes variants memory_binding_mode: - mem_mode_strict: - mem_mode = 'strict' + mem_mode = 'strict' - mem_mode_interleave: mem_mode = 'interleave' - mem_mode_preferred: @@ -34,9 +38,8 @@ variants pagesize: - default_pagesize: - hugepage: - memory_backing = {'hugepages': {'pages': [{'size': '2', 'unit': 'M'}]}} - hugepage_size = 2048 - kernel_hp_file = '/sys/devices/system/node/node%s/hugepages/hugepages-${hugepage_size}kB/nr_hugepages' - target_hugepages = 1536 + hugepage_mem = 3145728 + memory_backing = {'hugepages': {'pages': [{'size': '%s', 'unit': 'KiB'}]}} + kernel_hp_file = '/sys/devices/system/node/node%s/hugepages/hugepages-%skB/nr_hugepages' numa_memory = {'mode': '${mem_mode}', 'nodeset': '%s'} numa_memnode = [{'cellid': '0', 'mode': '${mem_mode}', 'nodeset': '%s'}] diff --git a/libvirt/tests/cfg/numa/guest_numa_node_tuning/specific_numa_memory_bind_hugepage.cfg b/libvirt/tests/cfg/numa/guest_numa_node_tuning/specific_numa_memory_bind_hugepage.cfg index 9c83599718a..becb317ad9a 100644 --- a/libvirt/tests/cfg/numa/guest_numa_node_tuning/specific_numa_memory_bind_hugepage.cfg +++ b/libvirt/tests/cfg/numa/guest_numa_node_tuning/specific_numa_memory_bind_hugepage.cfg @@ -1,14 +1,13 @@ - guest_numa_node_tuning.specific_numa_memory_bind_hugepage: type = specific_numa_memory_bind_hugepage take_regular_screendumps = no - start_vm = "no" + start_vm = "no" max_mem_value = "'max_mem_rt': 15360000, 'max_mem_rt_slots': 16, 'max_mem_rt_unit': 'KiB'" mem_value = "'memory': 2097152, 'memory_unit': 'KiB'" - current_mem_value = ${mem_value} - hugepage_size = 2048 - memory_backing = {'hugepages': {'pages': [{'size': '${hugepage_size}', 'unit': 'KiB', 'nodeset': '0'}]}} - kernel_hp_file = '/sys/devices/system/node/node%s/hugepages/hugepages-${hugepage_size}kB/nr_hugepages' - target_hugepages = 500 + current_mem_value = ${mem_value} + hugepage_mem = 1048576 + memory_backing = {'hugepages': {'pages': [{'size': '%s', 'unit': 'KiB', 'nodeset': '0'}]}} + kernel_hp_file = '/sys/devices/system/node/node%s/hugepages/hugepages-%skB/nr_hugepages' single_host_node = yes cpu_mode = 'host-model' no s390x @@ -16,7 +15,7 @@ cpu_mode = 'host-passthrough' variants memory_binding_mode: - mem_mode_strict: - mem_mode = 'strict' + mem_mode = 'strict' - mem_mode_interleave: mem_mode = 'interleave' - mem_mode_preferred: @@ -26,12 +25,12 @@ numa_memory = {'mode': '${mem_mode}', 'nodeset': '%s'} variants: - enough_numa_mem: - vm_node0_mem = 1024000 + vm_node0_mem = 1048576 vm_node1_mem = 1073152 - scarce_numa_mem: - vm_node0_mem = 1048576 + vm_node0_mem = 1572864 vm_node1_mem = 1048576 err_msg = 'unable to map backing store for guest RAM: Cannot allocate memory' - numa_cell = "'numa_cell': [{'id': '0', 'cpus': '0-1', 'memory': '${vm_node0_mem}', 'unit': 'KiB'}, {'id': '1', 'cpus': '2-3', 'memory': '${vm_node1_mem}', 'unit': 'KiB'}]" + numa_cell = "'numa_cell': [{'id': '0', 'cpus': '0-1', 'memory': '${vm_node0_mem}', 'unit': 'KiB'}, {'id': '1', 'cpus': '2-3', 'memory': '${vm_node1_mem}', 'unit': 'KiB'}]" numa_memnode = [{'cellid': '0', 'mode': '${mem_mode}', 'nodeset': '%s'}] vm_attrs = {${max_mem_value}, ${mem_value}, ${current_mem_value}, 'vcpu': 4, 'cpu': {'mode': '${cpu_mode}', ${numa_cell}}} diff --git a/libvirt/tests/cfg/numa/guest_numa_topology/numa_topology_with_hugepage.cfg b/libvirt/tests/cfg/numa/guest_numa_topology/numa_topology_with_hugepage.cfg index 3bedd9c61b0..4f5fe193e4c 100644 --- a/libvirt/tests/cfg/numa/guest_numa_topology/numa_topology_with_hugepage.cfg +++ b/libvirt/tests/cfg/numa/guest_numa_topology/numa_topology_with_hugepage.cfg @@ -3,32 +3,50 @@ take_regular_screendumps = no start_vm = "no" max_mem_value = "'max_mem_rt': 8388608, 'max_mem_rt_slots': 16, 'max_mem_rt_unit': 'KiB'" - target_hugepages_2M = 500 - target_hugepages_1G = 1 - hugepage_path_1G = '/dev/hugepages1G' - hugepage_path_2M = '/dev/hugepages' pat_in_qemu_cmdline = '-object {"qom-type":".*","id":"ram-node0","mem-path":"%s","prealloc":true,"size":%d} .* -object {"qom-type":".*","id":"ram-node1",%s%s"size":%d}' + cpu_mode = 'host-model' + no s390-virtio + aarch64: + cpu_mode = 'host-passthrough' variants hp_size: - - 2M: - mem_value = "'memory': 2097152, 'memory_unit': 'KiB'" - vm_numa_node0_mem = 1024000 - vm_numa_node1_mem = 1073152 - memory_backing = {'hugepages': {'pages': [{'size': '2048', 'unit': 'KiB', 'nodeset': '0'}]}} + - default_hugepage: + mem_value = "'memory': 2121728, 'memory_unit': 'KiB'" + vm_numa_node0_mem = 1048576 + vm_numa_node1_mem = 1073152 + hugepage_mem = 1048576 + memory_backing = {'hugepages': {'pages': [{'size': '%s', 'unit': 'KiB', 'nodeset': '0'}]}} + kernel_hp_file = "/sys/kernel/mm/hugepages/hugepages-%skB/nr_hugepages" - 1G: mem_value = "'memory': 2121728, 'memory_unit': 'KiB'" vm_numa_node0_mem = 1048576 - vm_numa_node1_mem = 1073152 + vm_numa_node1_mem = 1073152 + hugepage_mem_by_size = {1048576: 1048576} memory_backing = {'hugepages': {'pages': [{'size': '1048576', 'unit': 'KiB', 'nodeset': '0'}]}} + kernel_hp_file = "/sys/kernel/mm/hugepages/hugepages-1048576kB/nr_hugepages" + - 512M_2M: + only aarch64 + mem_value = "'memory': 2072576, 'memory_unit': 'KiB'" + vm_numa_node0_mem = 1048576 + vm_numa_node1_mem = 1024000 + hugepage_mem_by_size = {524288: 1048576, 2048: 1024000} + memory_backing = {'hugepages': {'pages': [{'size': '512', 'unit': 'M', 'nodeset': '0'}, {'size': '2', 'unit': 'M', 'nodeset': '1'}]}} + kernel_hp_file = "/sys/kernel/mm/hugepages/hugepages-%skB/nr_hugepages" - 2M_1G: + only q35,aarch64 mem_value = "'memory': 2072576, 'memory_unit': 'KiB'" vm_numa_node0_mem = 1024000 - vm_numa_node1_mem = 1048576 - memory_backing = {'hugepages': {'pages': [{'size': '1', 'unit': 'G', 'nodeset': '1'}, {'size': '2', 'unit': 'M', 'nodeset': '0'}]}} + vm_numa_node1_mem = 1048576 + hugepage_mem_by_size = {2048: 1024000, 1048576: 1048576} + memory_backing = {'hugepages': {'pages': [{'size': '2', 'unit': 'M', 'nodeset': '0'}, {'size': '1', 'unit': 'G', 'nodeset': '1'}]}} + kernel_hp_file = "/sys/kernel/mm/hugepages/hugepages-%skB/nr_hugepages" - scarce_mem: mem_value = "'memory': 2097152, 'memory_unit': 'KiB'" vm_numa_node0_mem = 1048576 vm_numa_node1_mem = 1048576 - memory_backing = {'hugepages': {'pages': [{'size': '2048', 'unit': 'KiB', 'nodeset': '0'}]}} + hugepage_mem = 1024000 + memory_backing = {'hugepages': {'pages': [{'size': '%s', 'unit': 'KiB', 'nodeset': '0'}]}} + kernel_hp_file = "/sys/kernel/mm/hugepages/hugepages-%skB/nr_hugepages" + err_msg = "unable to map backing store for guest RAM: Cannot allocate memory" current_mem_value = ${mem_value} numa_cell = "'numa_cell': [{'cpus': '0-1', 'memory': '${vm_numa_node0_mem}'}, {'cpus': '2-3', 'memory': '${vm_numa_node1_mem}'}]" - vm_attrs = {${max_mem_value}, ${mem_value}, ${current_mem_value}, 'vcpu': 4, 'cpu': {'mode': 'host-model', ${numa_cell}}} + vm_attrs = {${max_mem_value}, ${mem_value}, ${current_mem_value}, 'vcpu': 4, 'cpu': {'mode': '${cpu_mode}', ${numa_cell}}} diff --git a/libvirt/tests/cfg/numa/guest_numa_topology/various_numa_topology_settings.cfg b/libvirt/tests/cfg/numa/guest_numa_topology/various_numa_topology_settings.cfg index f3865ae789b..9bc241d7039 100644 --- a/libvirt/tests/cfg/numa/guest_numa_topology/various_numa_topology_settings.cfg +++ b/libvirt/tests/cfg/numa/guest_numa_topology/various_numa_topology_settings.cfg @@ -8,11 +8,8 @@ qemu_monitor_option = '--hmp' qemu_monitor_cmd = 'info memdev' cpu_mode = 'host-model' - target_hugepages = 1024 aarch64: cpu_mode = 'host-passthrough' - target_hugepages = 32 - hugepage_size = 2048 numa_cell_0 = {'id': '0', 'memory': '1048576', 'cpus': '0-1'} numa_cell_1 = {'id': '1', 'memory': '1048576', 'cpus': '2-3'} numa_cells = [${numa_cell_0}, ${numa_cell_1}] diff --git a/libvirt/tests/cfg/numa/host_numa/host_numa_info.cfg b/libvirt/tests/cfg/numa/host_numa/host_numa_info.cfg new file mode 100644 index 00000000000..811e5695cbc --- /dev/null +++ b/libvirt/tests/cfg/numa/host_numa/host_numa_info.cfg @@ -0,0 +1,23 @@ +- host_numa.numa_info: + type = host_numa_info + take_regular_screendumps = no + start_vm = "no" + no s390-virtio + variants kernel_size: + - 4k: + default_pagesize = 4 + variants: + - all_hugepages: + allocate_dict = {2048: 200, 1048576: 2} + aarch64: + allocate_dict = {64: 100, 2048: 100, 32768: 4, 1048576: 1} + - 64k: + only aarch64 + default_pagesize = 64 + variants: + - all_hugepages: + required_kernel = [5.14.0,) + expect_nodes_num = 1 + allocate_dict = {2048: 200, 524288: 4, 16777216: 1} + - 512M_2M: + allocate_dict = {2048: 200, 524288: 4} diff --git a/libvirt/tests/cfg/numa/numa_capabilities.cfg b/libvirt/tests/cfg/numa/numa_capabilities.cfg index c5517496817..34254c60fdf 100644 --- a/libvirt/tests/cfg/numa/numa_capabilities.cfg +++ b/libvirt/tests/cfg/numa/numa_capabilities.cfg @@ -5,3 +5,6 @@ status_error = "no" variants: - default: + aarch64: + missing_cpu_topology_key = 'die_id' + diff --git a/libvirt/tests/cfg/numa/numa_numanode_cpu_info.cfg b/libvirt/tests/cfg/numa/numa_numanode_cpu_info.cfg index 1f44f494072..4e9de5800f7 100644 --- a/libvirt/tests/cfg/numa/numa_numanode_cpu_info.cfg +++ b/libvirt/tests/cfg/numa/numa_numanode_cpu_info.cfg @@ -6,5 +6,8 @@ variants: - default: err_msg = 'unable to map backing store for guest RAM: Cannot allocate memory' - nodes_pages = ['900', '300'] + current_memory_size = 4194304 + memory_size = 4194304 + nodes_memory = ['1572864', '524288'] memory_mode = "strict" + diff --git a/libvirt/tests/cfg/passthrough/ccw/libvirt_ccw_passthrough.cfg b/libvirt/tests/cfg/passthrough/ccw/libvirt_ccw_passthrough.cfg index ae7829012d0..fd1cf6768f5 100644 --- a/libvirt/tests/cfg/passthrough/ccw/libvirt_ccw_passthrough.cfg +++ b/libvirt/tests/cfg/passthrough/ccw/libvirt_ccw_passthrough.cfg @@ -1,7 +1,7 @@ - libvirt_ccw_passthrough: type = libvirt_ccw_passthrough only s390-virtio - devid = + devid = dasd variants: - happy_path: - device_removal: diff --git a/libvirt/tests/cfg/passthrough/ccw/libvirt_ccw_passthrough_read_write.cfg b/libvirt/tests/cfg/passthrough/ccw/libvirt_ccw_passthrough_read_write.cfg index 20ef06b6563..92398f1abad 100644 --- a/libvirt/tests/cfg/passthrough/ccw/libvirt_ccw_passthrough_read_write.cfg +++ b/libvirt/tests/cfg/passthrough/ccw/libvirt_ccw_passthrough_read_write.cfg @@ -1,6 +1,11 @@ - libvirt_ccw_passthrough.read_write: type = libvirt_ccw_passthrough_read_write only s390-virtio - devid = + devid = dasd + start_vm = yes variants: - happy_path: + variants plugmethod: + - hotplug_unplug: + - coldplug_unplug: + diff --git a/libvirt/tests/cfg/passthrough/pci/ism_pci_passthrough.cfg b/libvirt/tests/cfg/passthrough/pci/ism_pci_passthrough.cfg index d9d09e9b7c4..1ed996cd576 100644 --- a/libvirt/tests/cfg/passthrough/pci/ism_pci_passthrough.cfg +++ b/libvirt/tests/cfg/passthrough/pci/ism_pci_passthrough.cfg @@ -1,7 +1,7 @@ - libvirt_pci_passthrough.ism: only s390-virtio type = ism_pci_passthrough - start_vm = no + start_vm = yes pci_dev = LIBVIRT_PCI_NAME guest_iface = enc1 variants: @@ -13,3 +13,5 @@ check = start_after_reboot - connect: check = smc_functional + - hotplug: + check = available_hotplug diff --git a/libvirt/tests/cfg/passthrough/pci/libvirt_pci_passthrough.cfg b/libvirt/tests/cfg/passthrough/pci/libvirt_pci_passthrough.cfg index f0354e0c17a..cba3a9a29cb 100644 --- a/libvirt/tests/cfg/passthrough/pci/libvirt_pci_passthrough.cfg +++ b/libvirt/tests/cfg/passthrough/pci/libvirt_pci_passthrough.cfg @@ -45,3 +45,7 @@ operation = "suspend" - passthrough_shutdown_start: operation = "shutdown" + - passthrough_multiple_reboots: + number_of_reboots = 15 + operation = "reboot" + supported_err = "not supported by the connection driver: virDomainReboot" diff --git a/libvirt/tests/cfg/passthrough/robustness/passthrough_robustness.cfg b/libvirt/tests/cfg/passthrough/robustness/passthrough_robustness.cfg new file mode 100644 index 00000000000..033f8884a8f --- /dev/null +++ b/libvirt/tests/cfg/passthrough/robustness/passthrough_robustness.cfg @@ -0,0 +1,1427 @@ +- passthrough.robustness: + type = passthrough_robustness + only s390-virtio + start_vm = no + vms = avocado-vt-vm1 vm2 + variants: + - start_stop_ap: + cmds = start;ap-00.000e, + cmds += stop;ap-00.000e, + - start_stop_ism: + cmds = start;ism-0000:00:00.0, + cmds += stop;ism-0000:00:00.0, + - start_stop_roce: + cmds = start;roce-0002:00:00.0, + cmds += stop;roce-0002:00:00.0, + - start_stop_ccw: + cmds = start;ccw-0.0.401c, + cmds += stop;ccw-0.0.401c, + - start_destroy_vm: + cmds = vm_start;0, + cmds += vm_destroy;0, + - start_stop_all: + cmds = start;ap-00.000e, + cmds += start;ism-0000:00:00.0, + cmds += start;roce-0002:00:00.0, + cmds += start;ccw-0.0.401c, + cmds += stop;ap-00.000e, + cmds += stop;ism-0000:00:00.0, + cmds += stop;roce-0002:00:00.0, + cmds += stop;ccw-0.0.401c, + - hotplug_hotunplug_all: + cmds = start;ap-00.000e, + cmds += start;ism-0000:00:00.0, + cmds += start;roce-0002:00:00.0, + cmds += start;ccw-0.0.401c, + cmds += vm_start;0, + cmds += vm_attach;0;ap-00.000e, + cmds += vm_attach;0;ism-0000:00:00.0, + cmds += vm_attach;0;roce-0002:00:00.0, + cmds += vm_attach;0;ccw-0.0.401c, + cmds += vm_detach;0;ap-00.000e, + cmds += vm_detach;0;ism-0000:00:00.0, + cmds += vm_detach;0;roce-0002:00:00.0, + cmds += vm_detach;0;ccw-0.0.401c, + - hotplug_check_all: + cmds = start;ap-00.000e, + cmds += start;ism-0000:00:00.0, + cmds += start;roce-0002:00:00.0, + cmds += start;ccw-0.0.401c, + cmds += vm_start;0, + cmds += vm_attach;0;ap-00.000e, + cmds += vm_attach;0;ism-0000:00:00.0, + cmds += vm_attach;0;roce-0002:00:00.0, + cmds += vm_attach;0;ccw-0.0.401c, + cmds += vm_check_present;0;ap-00.000e, + cmds += vm_check_present;0;ism-0000:00:00.0, + cmds += vm_check_present;0;roce-0002:00:00.0, + cmds += vm_check_present;0;ccw-0.0.401c, + - hotplug_all_distribute_over_two: + cmds = start;ap-00.000e, + cmds += start;ism-0000:00:00.0, + cmds += start;roce-0002:00:00.0, + cmds += start;ccw-0.0.401c, + cmds += vm_start;0, + cmds += vm_start;1, + cmds += vm_attach;0;ap-00.000e, + cmds += vm_attach;1;ism-0000:00:00.0, + cmds += vm_attach;0;roce-0002:00:00.0, + cmds += vm_attach;1;ccw-0.0.401c, + cmds += vm_check_present;0;ap-00.000e, + cmds += vm_check_present;1;ism-0000:00:00.0, + cmds += vm_check_present;0;roce-0002:00:00.0, + cmds += vm_check_present;1;ccw-0.0.401c, + - vm_running_attach_pause_resume.ap: + cmds = vm_start;0, + cmds += start;ap-00.000e, + cmds += vm_attach;0;ap-00.000e, + cmds += vm_pause;0, + cmds += vm_resume;0, + cmds += vm_check_present;0;ap-00.000e, + - vm_running_attach_pause_resume.ccw: + cmds = vm_start;0, + cmds += start;ccw-0.0.401c, + cmds += vm_attach;0;ccw-0.0.401c, + cmds += vm_pause;0, + cmds += vm_resume;0, + cmds += vm_check_present;0;ccw-0.0.401c, + - vm_running_attach_pause_resume.ism: + cmds = vm_start;0, + cmds += start;ism-0000:00:00.0, + cmds += vm_attach;0;ism-0000:00:00.0, + cmds += vm_pause;0, + cmds += vm_resume;0, + cmds += vm_check_present;0;ism-0000:00:00.0, + - vm_running_attach_pause_resume.roce: + cmds = vm_start;0, + cmds += start;roce-0002:00:00.0, + cmds += vm_attach;0;roce-0002:00:00.0, + cmds += vm_pause;0, + cmds += vm_resume;0, + cmds += vm_check_present;0;roce-0002:00:00.0, + - vm_running_attach_pause_resume.all: + cmds = vm_start;0, + cmds += start;ap-00.000e, + cmds += vm_attach;0;ap-00.000e, + cmds += start;ccw-0.0.401c, + cmds += vm_attach;0;ccw-0.0.401c, + cmds += start;ism-0000:00:00.0, + cmds += vm_attach;0;ism-0000:00:00.0, + cmds += start;roce-0002:00:00.0, + cmds += vm_attach;0;roce-0002:00:00.0, + cmds += vm_pause;0, + cmds += vm_resume;0, + cmds += vm_check_present;0;ap-00.000e, + cmds += vm_check_present;0;ccw-0.0.401c, + cmds += vm_check_present;0;ism-0000:00:00.0, + cmds += vm_check_present;0;roce-0002:00:00.0, + - vm_running_attach_reboot.ap: + cmds = vm_start;0, + cmds += start;ap-00.000e, + cmds += vm_attach;0;ap-00.000e, + cmds += vm_reboot;0, + cmds += vm_check_present;0;ap-00.000e, + - vm_running_attach_reboot.ccw: + cmds = vm_start;0, + cmds += start;ccw-0.0.401c, + cmds += vm_attach;0;ccw-0.0.401c, + cmds += vm_reboot;0, + cmds += vm_check_present;0;ccw-0.0.401c, + - vm_running_attach_reboot.ism: + cmds = vm_start;0, + cmds += start;ism-0000:00:00.0, + cmds += vm_attach;0;ism-0000:00:00.0, + cmds += vm_reboot;0, + cmds += vm_check_present;0;ism-0000:00:00.0, + - vm_running_attach_reboot.roce: + cmds = vm_start;0, + cmds += start;roce-0002:00:00.0, + cmds += vm_attach;0;roce-0002:00:00.0, + cmds += vm_reboot;0, + cmds += vm_check_present;0;roce-0002:00:00.0, + - vm_running_attach_reboot.all: + cmds = vm_start;0, + cmds += start;ap-00.000e, + cmds += vm_attach;0;ap-00.000e, + cmds += start;ccw-0.0.401c, + cmds += vm_attach;0;ccw-0.0.401c, + cmds += start;ism-0000:00:00.0, + cmds += vm_attach;0;ism-0000:00:00.0, + cmds += start;roce-0002:00:00.0, + cmds += vm_attach;0;roce-0002:00:00.0, + cmds += vm_reboot;0, + cmds += vm_check_present;0;ap-00.000e, + cmds += vm_check_present;0;ccw-0.0.401c, + cmds += vm_check_present;0;ism-0000:00:00.0, + cmds += vm_check_present;0;roce-0002:00:00.0, + - vm_running_attach_detach_attach.ap: + cmds = vm_start;0, + cmds += start;ap-00.000e, + cmds += vm_attach;0;ap-00.000e, + cmds += vm_detach;0;ap-00.000e, + cmds += vm_attach;0;ap-00.000e, + cmds += vm_check_present;0;ap-00.000e, + - vm_running_attach_detach_attach.ccw: + cmds = vm_start;0, + cmds += start;ccw-0.0.401c, + cmds += vm_attach;0;ccw-0.0.401c, + cmds += vm_detach;0;ccw-0.0.401c, + cmds += vm_attach;0;ccw-0.0.401c, + cmds += vm_check_present;0;ccw-0.0.401c, + - vm_running_attach_detach_attach.ism: + cmds = vm_start;0, + cmds += start;ism-0000:00:00.0, + cmds += vm_attach;0;ism-0000:00:00.0, + cmds += vm_detach;0;ism-0000:00:00.0, + cmds += vm_attach;0;ism-0000:00:00.0, + cmds += vm_check_present;0;ism-0000:00:00.0, + - vm_running_attach_detach_attach.roce: + cmds = vm_start;0, + cmds += start;roce-0002:00:00.0, + cmds += vm_attach;0;roce-0002:00:00.0, + cmds += vm_detach;0;roce-0002:00:00.0, + cmds += vm_attach;0;roce-0002:00:00.0, + cmds += vm_check_present;0;roce-0002:00:00.0, + - vm_running_attach_detach_attach.all: + cmds = vm_start;0, + cmds += start;ap-00.000e, + cmds += start;ccw-0.0.401c, + cmds += start;roce-0002:00:00.0, + cmds += start;ism-0000:00:00.0, + cmds += vm_attach;0;ccw-0.0.401c, + cmds += vm_attach;0;ap-00.000e, + cmds += vm_attach;0;ism-0000:00:00.0, + cmds += vm_attach;0;roce-0002:00:00.0, + cmds += vm_detach;0;ccw-0.0.401c, + cmds += vm_detach;0;ap-00.000e, + cmds += vm_detach;0;ism-0000:00:00.0, + cmds += vm_detach;0;roce-0002:00:00.0, + cmds += vm_attach;0;ccw-0.0.401c, + cmds += vm_attach;0;ap-00.000e, + cmds += vm_attach;0;ism-0000:00:00.0, + cmds += vm_attach;0;roce-0002:00:00.0, + cmds += vm_check_present;0;ap-00.000e, + cmds += vm_check_present;0;ccw-0.0.401c, + cmds += vm_check_present;0;ism-0000:00:00.0, + cmds += vm_check_present;0;roce-0002:00:00.0, + - vm_running_attach_detach_attach_reboot.ap: + cmds = vm_start;0, + cmds += start;ap-00.000e, + cmds += vm_attach;0;ap-00.000e, + cmds += vm_detach;0;ap-00.000e, + cmds += vm_attach;0;ap-00.000e, + cmds += vm_reboot;0, + cmds += vm_check_present;0;ap-00.000e, + - vm_running_attach_detach_attach_reboot.ccw: + cmds = vm_start;0, + cmds += start;ccw-0.0.401c, + cmds += vm_attach;0;ccw-0.0.401c, + cmds += vm_detach;0;ccw-0.0.401c, + cmds += vm_attach;0;ccw-0.0.401c, + cmds += vm_reboot;0, + cmds += vm_check_present;0;ccw-0.0.401c, + - vm_running_attach_detach_attach_reboot.ism: + cmds = vm_start;0, + cmds += start;ism-0000:00:00.0, + cmds += vm_attach;0;ism-0000:00:00.0, + cmds += vm_detach;0;ism-0000:00:00.0, + cmds += vm_attach;0;ism-0000:00:00.0, + cmds += vm_reboot;0, + cmds += vm_check_present;0;ism-0000:00:00.0, + - vm_running_attach_detach_attach_reboot.roce: + cmds = vm_start;0, + cmds += start;roce-0002:00:00.0, + cmds += vm_attach;0;roce-0002:00:00.0, + cmds += vm_detach;0;roce-0002:00:00.0, + cmds += vm_attach;0;roce-0002:00:00.0, + cmds += vm_reboot;0, + cmds += vm_check_present;0;roce-0002:00:00.0, + - vm_running_attach_detach_attach_reboot.all: + cmds = vm_start;0, + cmds += start;ap-00.000e, + cmds += start;ccw-0.0.401c, + cmds += start;roce-0002:00:00.0, + cmds += start;ism-0000:00:00.0, + cmds += vm_attach;0;ccw-0.0.401c, + cmds += vm_attach;0;ap-00.000e, + cmds += vm_attach;0;ism-0000:00:00.0, + cmds += vm_attach;0;roce-0002:00:00.0, + cmds += vm_detach;0;ccw-0.0.401c, + cmds += vm_detach;0;ap-00.000e, + cmds += vm_detach;0;ism-0000:00:00.0, + cmds += vm_detach;0;roce-0002:00:00.0, + cmds += vm_attach;0;ccw-0.0.401c, + cmds += vm_attach;0;ap-00.000e, + cmds += vm_attach;0;ism-0000:00:00.0, + cmds += vm_attach;0;roce-0002:00:00.0, + cmds += vm_reboot;0, + cmds += vm_check_present;0;ap-00.000e, + cmds += vm_check_present;0;ccw-0.0.401c, + cmds += vm_check_present;0;ism-0000:00:00.0, + cmds += vm_check_present;0;roce-0002:00:00.0, + - vm_running_attach_shutdown_start_attach.ap: + cmds = vm_start;0, + cmds += start;ap-00.000e, + cmds += vm_attach;0;ap-00.000e, + cmds += vm_shutdown;0, + cmds += vm_start;0, + cmds += vm_attach;0;ap-00.000e, + cmds += vm_check_present;0;ap-00.000e, + - vm_running_attach_shutdown_start_attach.ccw: + cmds = vm_start;0, + cmds += start;ccw-0.0.401c, + cmds += vm_attach;0;ccw-0.0.401c, + cmds += vm_shutdown;0, + cmds += vm_start;0, + cmds += vm_attach;0;ccw-0.0.401c, + cmds += vm_check_present;0;ccw-0.0.401c, + - vm_running_attach_shutdown_start_attach.ism: + cmds = vm_start;0, + cmds += start;ism-0000:00:00.0, + cmds += vm_attach;0;ism-0000:00:00.0, + cmds += vm_shutdown;0, + cmds += vm_start;0, + cmds += vm_attach;0;ism-0000:00:00.0, + cmds += vm_check_present;0;ism-0000:00:00.0, + - vm_running_attach_shutdown_start_attach.roce: + cmds = vm_start;0, + cmds += start;roce-0002:00:00.0, + cmds += vm_attach;0;roce-0002:00:00.0, + cmds += vm_shutdown;0, + cmds += vm_start;0, + cmds += vm_attach;0;roce-0002:00:00.0, + cmds += vm_check_present;0;roce-0002:00:00.0, + - vm_running_attach_shutdown_start_attach.all: + cmds = vm_start;0, + cmds += start;ap-00.000e, + cmds += start;ccw-0.0.401c, + cmds += start;roce-0002:00:00.0, + cmds += start;ism-0000:00:00.0, + cmds += vm_attach;0;ccw-0.0.401c, + cmds += vm_attach;0;ap-00.000e, + cmds += vm_attach;0;ism-0000:00:00.0, + cmds += vm_attach;0;roce-0002:00:00.0, + cmds += vm_shutdown;0, + cmds += vm_start;0, + cmds += vm_attach;0;ccw-0.0.401c, + cmds += vm_attach;0;ap-00.000e, + cmds += vm_attach;0;ism-0000:00:00.0, + cmds += vm_attach;0;roce-0002:00:00.0, + cmds += vm_check_present;0;ap-00.000e, + cmds += vm_check_present;0;ccw-0.0.401c, + cmds += vm_check_present;0;ism-0000:00:00.0, + cmds += vm_check_present;0;roce-0002:00:00.0, + - vm_stopped_attach_start_detach_attach.ap: + cmds = start;ap-00.000e, + cmds += vm_attach;0;ap-00.000e, + cmds += vm_start;0, + cmds += vm_detach;0;ap-00.000e, + cmds += vm_attach;0;ap-00.000e, + cmds += vm_check_present;0;ap-00.000e, + - vm_stopped_attach_start_detach_attach.ccw: + cmds = start;ccw-0.0.401c, + cmds += vm_attach;0;ccw-0.0.401c, + cmds += vm_start;0, + cmds += vm_detach;0;ccw-0.0.401c, + cmds += vm_attach;0;ccw-0.0.401c, + cmds += vm_check_present;0;ccw-0.0.401c, + - vm_stopped_attach_start_detach_attach.ism: + cmds = start;ism-0000:00:00.0, + cmds += vm_attach;0;ism-0000:00:00.0, + cmds += vm_start;0, + cmds += vm_detach;0;ism-0000:00:00.0, + cmds += vm_attach;0;ism-0000:00:00.0, + cmds += vm_check_present;0;ism-0000:00:00.0, + - vm_stopped_attach_start_detach_attach.roce: + cmds = start;roce-0002:00:00.0, + cmds += vm_attach;0;roce-0002:00:00.0, + cmds += vm_start;0, + cmds += vm_detach;0;roce-0002:00:00.0, + cmds += vm_attach;0;roce-0002:00:00.0, + cmds += vm_check_present;0;roce-0002:00:00.0, + - vm_stopped_attach_start_detach_attach.all: + cmds = start;ap-00.000e, + cmds += start;ccw-0.0.401c, + cmds += start;roce-0002:00:00.0, + cmds += start;ism-0000:00:00.0, + cmds += vm_attach;0;ccw-0.0.401c, + cmds += vm_attach;0;ap-00.000e, + cmds += vm_attach;0;ism-0000:00:00.0, + cmds += vm_attach;0;roce-0002:00:00.0, + cmds += vm_start;0, + cmds += vm_detach;0;ccw-0.0.401c, + cmds += vm_detach;0;ap-00.000e, + cmds += vm_detach;0;ism-0000:00:00.0, + cmds += vm_detach;0;roce-0002:00:00.0, + cmds += vm_attach;0;ccw-0.0.401c, + cmds += vm_attach;0;ap-00.000e, + cmds += vm_attach;0;ism-0000:00:00.0, + cmds += vm_attach;0;roce-0002:00:00.0, + cmds += vm_check_present;0;ap-00.000e, + cmds += vm_check_present;0;ccw-0.0.401c, + cmds += vm_check_present;0;ism-0000:00:00.0, + cmds += vm_check_present;0;roce-0002:00:00.0, + - vm_stopped_attach_start_reboot.ap: + cmds = start;ap-00.000e, + cmds += vm_attach;0;ap-00.000e, + cmds += vm_start;0, + cmds += vm_reboot;0, + cmds += vm_check_present;0;ap-00.000e, + - vm_stopped_attach_start_reboot.ccw: + cmds = start;ccw-0.0.401c, + cmds += vm_attach;0;ccw-0.0.401c, + cmds += vm_start;0, + cmds += vm_reboot;0, + cmds += vm_check_present;0;ccw-0.0.401c, + - vm_stopped_attach_start_reboot.ism: + cmds = start;ism-0000:00:00.0, + cmds += vm_attach;0;ism-0000:00:00.0, + cmds += vm_start;0, + cmds += vm_reboot;0, + cmds += vm_check_present;0;ism-0000:00:00.0, + - vm_stopped_attach_start_reboot.roce: + cmds = start;roce-0002:00:00.0, + cmds += vm_attach;0;roce-0002:00:00.0, + cmds += vm_start;0, + cmds += vm_reboot;0, + cmds += vm_check_present;0;roce-0002:00:00.0, + - vm_stopped_attach_start_reboot.all: + cmds = start;ap-00.000e, + cmds += start;ccw-0.0.401c, + cmds += start;roce-0002:00:00.0, + cmds += start;ism-0000:00:00.0, + cmds += vm_attach;0;ccw-0.0.401c, + cmds += vm_attach;0;ap-00.000e, + cmds += vm_attach;0;ism-0000:00:00.0, + cmds += vm_attach;0;roce-0002:00:00.0, + cmds += vm_start;0, + cmds += vm_reboot;0, + cmds += vm_check_present;0;ap-00.000e, + cmds += vm_check_present;0;ccw-0.0.401c, + cmds += vm_check_present;0;ism-0000:00:00.0, + cmds += vm_check_present;0;roce-0002:00:00.0, + - vm_stopped_attach_start_shutdown_start.ap: + cmds = start;ap-00.000e, + cmds += vm_attach;0;ap-00.000e, + cmds += vm_start;0, + cmds += vm_shutdown;0, + cmds += vm_start;0, + cmds += vm_check_present;0;ap-00.000e, + - vm_stopped_attach_start_shutdown_start.ccw: + cmds = start;ccw-0.0.401c, + cmds += vm_attach;0;ccw-0.0.401c, + cmds += vm_start;0, + cmds += vm_shutdown;0, + cmds += vm_start;0, + cmds += vm_check_present;0;ccw-0.0.401c, + - vm_stopped_attach_start_shutdown_start.ism: + cmds = start;ism-0000:00:00.0, + cmds += vm_attach;0;ism-0000:00:00.0, + cmds += vm_start;0, + cmds += vm_shutdown;0, + cmds += vm_start;0, + cmds += vm_check_present;0;ism-0000:00:00.0, + - vm_stopped_attach_start_shutdown_start.roce: + cmds = start;roce-0002:00:00.0, + cmds += vm_attach;0;roce-0002:00:00.0, + cmds += vm_start;0, + cmds += vm_shutdown;0, + cmds += vm_start;0, + cmds += vm_check_present;0;roce-0002:00:00.0, + - vm_stopped_attach_start_shutdown_start.all: + cmds = start;ap-00.000e, + cmds += start;ccw-0.0.401c, + cmds += start;roce-0002:00:00.0, + cmds += start;ism-0000:00:00.0, + cmds += vm_attach;0;ccw-0.0.401c, + cmds += vm_attach;0;ap-00.000e, + cmds += vm_attach;0;ism-0000:00:00.0, + cmds += vm_attach;0;roce-0002:00:00.0, + cmds += vm_start;0, + cmds += vm_shutdown;0, + cmds += vm_start;0, + cmds += vm_check_present;0;ap-00.000e, + cmds += vm_check_present;0;ccw-0.0.401c, + cmds += vm_check_present;0;ism-0000:00:00.0, + cmds += vm_check_present;0;roce-0002:00:00.0, + - vm_stopped_attach_start_destroy_start.ap: + cmds = start;ap-00.000e, + cmds += vm_attach;0;ap-00.000e, + cmds += vm_start;0, + cmds += vm_destroy;0, + cmds += vm_start;0, + cmds += vm_check_present;0;ap-00.000e, + - vm_stopped_attach_start_destroy_start.ccw: + cmds = start;ccw-0.0.401c, + cmds += vm_attach;0;ccw-0.0.401c, + cmds += vm_start;0, + cmds += vm_destroy;0, + cmds += vm_start;0, + cmds += vm_check_present;0;ccw-0.0.401c, + - vm_stopped_attach_start_destroy_start.ism: + cmds = start;ism-0000:00:00.0, + cmds += vm_attach;0;ism-0000:00:00.0, + cmds += vm_start;0, + cmds += vm_destroy;0, + cmds += vm_start;0, + cmds += vm_check_present;0;ism-0000:00:00.0, + - vm_stopped_attach_start_destroy_start.roce: + cmds = start;roce-0002:00:00.0, + cmds += vm_attach;0;roce-0002:00:00.0, + cmds += vm_start;0, + cmds += vm_destroy;0, + cmds += vm_start;0, + cmds += vm_check_present;0;roce-0002:00:00.0, + - vm_stopped_attach_start_destroy_start.all: + cmds = start;ap-00.000e, + cmds += start;ccw-0.0.401c, + cmds += start;roce-0002:00:00.0, + cmds += start;ism-0000:00:00.0, + cmds += vm_attach;0;ccw-0.0.401c, + cmds += vm_attach;0;ap-00.000e, + cmds += vm_attach;0;ism-0000:00:00.0, + cmds += vm_attach;0;roce-0002:00:00.0, + cmds += vm_start;0, + cmds += vm_destroy;0, + cmds += vm_start;0, + cmds += vm_check_present;0;ap-00.000e, + cmds += vm_check_present;0;ccw-0.0.401c, + cmds += vm_check_present;0;ism-0000:00:00.0, + cmds += vm_check_present;0;roce-0002:00:00.0, + - vm_stopped_attach_start_pause_resume.ap: + cmds = start;ap-00.000e, + cmds += vm_attach;0;ap-00.000e, + cmds += vm_start;0, + cmds += vm_pause;0, + cmds += vm_resume;0, + cmds += vm_check_present;0;ap-00.000e, + - vm_stopped_attach_start_pause_resume.ccw: + cmds = start;ccw-0.0.401c, + cmds += vm_attach;0;ccw-0.0.401c, + cmds += vm_start;0, + cmds += vm_pause;0, + cmds += vm_resume;0, + cmds += vm_check_present;0;ccw-0.0.401c, + - vm_stopped_attach_start_pause_resume.ism: + cmds = start;ism-0000:00:00.0, + cmds += vm_attach;0;ism-0000:00:00.0, + cmds += vm_start;0, + cmds += vm_pause;0, + cmds += vm_resume;0, + cmds += vm_check_present;0;ism-0000:00:00.0, + - vm_stopped_attach_start_pause_resume.roce: + cmds = start;roce-0002:00:00.0, + cmds += vm_attach;0;roce-0002:00:00.0, + cmds += vm_start;0, + cmds += vm_pause;0, + cmds += vm_resume;0, + cmds += vm_check_present;0;roce-0002:00:00.0, + - vm_stopped_attach_start_pause_resume.all: + cmds = start;ap-00.000e, + cmds += start;ccw-0.0.401c, + cmds += start;roce-0002:00:00.0, + cmds += start;ism-0000:00:00.0, + cmds += vm_attach;0;ccw-0.0.401c, + cmds += vm_attach;0;ap-00.000e, + cmds += vm_attach;0;ism-0000:00:00.0, + cmds += vm_attach;0;roce-0002:00:00.0, + cmds += vm_start;0, + cmds += vm_pause;0, + cmds += vm_resume;0, + cmds += vm_check_present;0;ap-00.000e, + cmds += vm_check_present;0;ccw-0.0.401c, + cmds += vm_check_present;0;ism-0000:00:00.0, + cmds += vm_check_present;0;roce-0002:00:00.0, + - vm_running_attach_10_times_detach_attach.ap: + cmds = vm_start;0, + cmds += start;ap-00.000e, + cmds += vm_attach;0;ap-00.000e, + cmds += vm_detach;0;ap-00.000e, + cmds += vm_attach;0;ap-00.000e, + cmds += vm_detach;0;ap-00.000e, + cmds += vm_attach;0;ap-00.000e, + cmds += vm_detach;0;ap-00.000e, + cmds += vm_attach;0;ap-00.000e, + cmds += vm_detach;0;ap-00.000e, + cmds += vm_attach;0;ap-00.000e, + cmds += vm_detach;0;ap-00.000e, + cmds += vm_attach;0;ap-00.000e, + cmds += vm_detach;0;ap-00.000e, + cmds += vm_attach;0;ap-00.000e, + cmds += vm_detach;0;ap-00.000e, + cmds += vm_attach;0;ap-00.000e, + cmds += vm_detach;0;ap-00.000e, + cmds += vm_attach;0;ap-00.000e, + cmds += vm_detach;0;ap-00.000e, + cmds += vm_attach;0;ap-00.000e, + cmds += vm_detach;0;ap-00.000e, + cmds += vm_attach;0;ap-00.000e, + cmds += vm_check_present;0;ap-00.000e, + - vm_running_attach_10_times_detach_attach.ccw: + cmds = vm_start;0, + cmds += start;ccw-0.0.401c, + cmds += vm_attach;0;ccw-0.0.401c, + cmds += vm_detach;0;ccw-0.0.401c, + cmds += vm_attach;0;ccw-0.0.401c, + cmds += vm_detach;0;ccw-0.0.401c, + cmds += vm_attach;0;ccw-0.0.401c, + cmds += vm_detach;0;ccw-0.0.401c, + cmds += vm_attach;0;ccw-0.0.401c, + cmds += vm_detach;0;ccw-0.0.401c, + cmds += vm_attach;0;ccw-0.0.401c, + cmds += vm_detach;0;ccw-0.0.401c, + cmds += vm_attach;0;ccw-0.0.401c, + cmds += vm_detach;0;ccw-0.0.401c, + cmds += vm_attach;0;ccw-0.0.401c, + cmds += vm_detach;0;ccw-0.0.401c, + cmds += vm_attach;0;ccw-0.0.401c, + cmds += vm_detach;0;ccw-0.0.401c, + cmds += vm_attach;0;ccw-0.0.401c, + cmds += vm_detach;0;ccw-0.0.401c, + cmds += vm_attach;0;ccw-0.0.401c, + cmds += vm_detach;0;ccw-0.0.401c, + cmds += vm_attach;0;ccw-0.0.401c, + cmds += vm_check_present;0;ccw-0.0.401c, + - vm_running_attach_10_times_detach_attach.ism: + cmds = vm_start;0, + cmds += start;ism-0000:00:00.0, + cmds += vm_attach;0;ism-0000:00:00.0, + cmds += vm_detach;0;ism-0000:00:00.0, + cmds += vm_attach;0;ism-0000:00:00.0, + cmds += vm_detach;0;ism-0000:00:00.0, + cmds += vm_attach;0;ism-0000:00:00.0, + cmds += vm_detach;0;ism-0000:00:00.0, + cmds += vm_attach;0;ism-0000:00:00.0, + cmds += vm_detach;0;ism-0000:00:00.0, + cmds += vm_attach;0;ism-0000:00:00.0, + cmds += vm_detach;0;ism-0000:00:00.0, + cmds += vm_attach;0;ism-0000:00:00.0, + cmds += vm_detach;0;ism-0000:00:00.0, + cmds += vm_attach;0;ism-0000:00:00.0, + cmds += vm_detach;0;ism-0000:00:00.0, + cmds += vm_attach;0;ism-0000:00:00.0, + cmds += vm_detach;0;ism-0000:00:00.0, + cmds += vm_attach;0;ism-0000:00:00.0, + cmds += vm_detach;0;ism-0000:00:00.0, + cmds += vm_attach;0;ism-0000:00:00.0, + cmds += vm_detach;0;ism-0000:00:00.0, + cmds += vm_attach;0;ism-0000:00:00.0, + cmds += vm_check_present;0;ism-0000:00:00.0, + - vm_running_attach_10_times_detach_attach.roce: + cmds = vm_start;0, + cmds += start;roce-0002:00:00.0, + cmds += vm_attach;0;roce-0002:00:00.0, + cmds += vm_detach;0;roce-0002:00:00.0, + cmds += vm_attach;0;roce-0002:00:00.0, + cmds += vm_detach;0;roce-0002:00:00.0, + cmds += vm_attach;0;roce-0002:00:00.0, + cmds += vm_detach;0;roce-0002:00:00.0, + cmds += vm_attach;0;roce-0002:00:00.0, + cmds += vm_detach;0;roce-0002:00:00.0, + cmds += vm_attach;0;roce-0002:00:00.0, + cmds += vm_detach;0;roce-0002:00:00.0, + cmds += vm_attach;0;roce-0002:00:00.0, + cmds += vm_detach;0;roce-0002:00:00.0, + cmds += vm_attach;0;roce-0002:00:00.0, + cmds += vm_detach;0;roce-0002:00:00.0, + cmds += vm_attach;0;roce-0002:00:00.0, + cmds += vm_detach;0;roce-0002:00:00.0, + cmds += vm_attach;0;roce-0002:00:00.0, + cmds += vm_detach;0;roce-0002:00:00.0, + cmds += vm_attach;0;roce-0002:00:00.0, + cmds += vm_detach;0;roce-0002:00:00.0, + cmds += vm_attach;0;roce-0002:00:00.0, + cmds += vm_check_present;0;roce-0002:00:00.0, + - vm_running_attach_10_times_detach_attach.all: + cmds = vm_start;0, + cmds += start;ap-00.000e, + cmds += start;ccw-0.0.401c, + cmds += start;roce-0002:00:00.0, + cmds += start;ism-0000:00:00.0, + cmds += vm_attach;0;ccw-0.0.401c, + cmds += vm_attach;0;ap-00.000e, + cmds += vm_attach;0;ism-0000:00:00.0, + cmds += vm_attach;0;roce-0002:00:00.0, + cmds += vm_detach;0;ccw-0.0.401c, + cmds += vm_detach;0;ap-00.000e, + cmds += vm_detach;0;ism-0000:00:00.0, + cmds += vm_detach;0;roce-0002:00:00.0, + cmds += vm_attach;0;ccw-0.0.401c, + cmds += vm_attach;0;ap-00.000e, + cmds += vm_attach;0;ism-0000:00:00.0, + cmds += vm_attach;0;roce-0002:00:00.0, + cmds += vm_detach;0;ccw-0.0.401c, + cmds += vm_detach;0;ap-00.000e, + cmds += vm_detach;0;ism-0000:00:00.0, + cmds += vm_detach;0;roce-0002:00:00.0, + cmds += vm_attach;0;ccw-0.0.401c, + cmds += vm_attach;0;ap-00.000e, + cmds += vm_attach;0;ism-0000:00:00.0, + cmds += vm_attach;0;roce-0002:00:00.0, + cmds += vm_detach;0;ccw-0.0.401c, + cmds += vm_detach;0;ap-00.000e, + cmds += vm_detach;0;ism-0000:00:00.0, + cmds += vm_detach;0;roce-0002:00:00.0, + cmds += vm_attach;0;ccw-0.0.401c, + cmds += vm_attach;0;ap-00.000e, + cmds += vm_attach;0;ism-0000:00:00.0, + cmds += vm_attach;0;roce-0002:00:00.0, + cmds += vm_detach;0;ccw-0.0.401c, + cmds += vm_detach;0;ap-00.000e, + cmds += vm_detach;0;ism-0000:00:00.0, + cmds += vm_detach;0;roce-0002:00:00.0, + cmds += vm_attach;0;ccw-0.0.401c, + cmds += vm_attach;0;ap-00.000e, + cmds += vm_attach;0;ism-0000:00:00.0, + cmds += vm_attach;0;roce-0002:00:00.0, + cmds += vm_detach;0;ccw-0.0.401c, + cmds += vm_detach;0;ap-00.000e, + cmds += vm_detach;0;ism-0000:00:00.0, + cmds += vm_detach;0;roce-0002:00:00.0, + cmds += vm_attach;0;ccw-0.0.401c, + cmds += vm_attach;0;ap-00.000e, + cmds += vm_attach;0;ism-0000:00:00.0, + cmds += vm_attach;0;roce-0002:00:00.0, + cmds += vm_detach;0;ccw-0.0.401c, + cmds += vm_detach;0;ap-00.000e, + cmds += vm_detach;0;ism-0000:00:00.0, + cmds += vm_detach;0;roce-0002:00:00.0, + cmds += vm_attach;0;ccw-0.0.401c, + cmds += vm_attach;0;ap-00.000e, + cmds += vm_attach;0;ism-0000:00:00.0, + cmds += vm_attach;0;roce-0002:00:00.0, + cmds += vm_detach;0;ccw-0.0.401c, + cmds += vm_detach;0;ap-00.000e, + cmds += vm_detach;0;ism-0000:00:00.0, + cmds += vm_detach;0;roce-0002:00:00.0, + cmds += vm_attach;0;ccw-0.0.401c, + cmds += vm_attach;0;ap-00.000e, + cmds += vm_attach;0;ism-0000:00:00.0, + cmds += vm_attach;0;roce-0002:00:00.0, + cmds += vm_detach;0;ccw-0.0.401c, + cmds += vm_detach;0;ap-00.000e, + cmds += vm_detach;0;ism-0000:00:00.0, + cmds += vm_detach;0;roce-0002:00:00.0, + cmds += vm_attach;0;ccw-0.0.401c, + cmds += vm_attach;0;ap-00.000e, + cmds += vm_attach;0;ism-0000:00:00.0, + cmds += vm_attach;0;roce-0002:00:00.0, + cmds += vm_detach;0;ccw-0.0.401c, + cmds += vm_detach;0;ap-00.000e, + cmds += vm_detach;0;ism-0000:00:00.0, + cmds += vm_detach;0;roce-0002:00:00.0, + cmds += vm_attach;0;ccw-0.0.401c, + cmds += vm_attach;0;ap-00.000e, + cmds += vm_attach;0;ism-0000:00:00.0, + cmds += vm_attach;0;roce-0002:00:00.0, + cmds += vm_detach;0;ccw-0.0.401c, + cmds += vm_detach;0;ap-00.000e, + cmds += vm_detach;0;ism-0000:00:00.0, + cmds += vm_detach;0;roce-0002:00:00.0, + cmds += vm_attach;0;ccw-0.0.401c, + cmds += vm_attach;0;ap-00.000e, + cmds += vm_attach;0;ism-0000:00:00.0, + cmds += vm_attach;0;roce-0002:00:00.0, + cmds += vm_check_present;0;ap-00.000e, + cmds += vm_check_present;0;ccw-0.0.401c, + cmds += vm_check_present;0;ism-0000:00:00.0, + cmds += vm_check_present;0;roce-0002:00:00.0, + - vm_stopped_attach_start_10_times_detach_attach_reboot.ap: + cmds = start;ap-00.000e, + cmds += vm_attach;0;ap-00.000e, + cmds += vm_start;0, + cmds += vm_detach;0;ap-00.000e, + cmds += vm_attach;0;ap-00.000e, + cmds += vm_reboot;0, + cmds += vm_detach;0;ap-00.000e, + cmds += vm_attach;0;ap-00.000e, + cmds += vm_reboot;0, + cmds += vm_detach;0;ap-00.000e, + cmds += vm_attach;0;ap-00.000e, + cmds += vm_reboot;0, + cmds += vm_detach;0;ap-00.000e, + cmds += vm_attach;0;ap-00.000e, + cmds += vm_reboot;0, + cmds += vm_detach;0;ap-00.000e, + cmds += vm_attach;0;ap-00.000e, + cmds += vm_reboot;0, + cmds += vm_detach;0;ap-00.000e, + cmds += vm_attach;0;ap-00.000e, + cmds += vm_reboot;0, + cmds += vm_detach;0;ap-00.000e, + cmds += vm_attach;0;ap-00.000e, + cmds += vm_reboot;0, + cmds += vm_detach;0;ap-00.000e, + cmds += vm_attach;0;ap-00.000e, + cmds += vm_reboot;0, + cmds += vm_detach;0;ap-00.000e, + cmds += vm_attach;0;ap-00.000e, + cmds += vm_reboot;0, + cmds += vm_detach;0;ap-00.000e, + cmds += vm_attach;0;ap-00.000e, + cmds += vm_reboot;0, + cmds += vm_check_present;0;ap-00.000e, + - vm_stopped_attach_start_10_times_detach_attach_reboot.ccw: + cmds = start;ccw-0.0.401c, + cmds += vm_attach;0;ccw-0.0.401c, + cmds += vm_start;0, + cmds += vm_detach;0;ccw-0.0.401c, + cmds += vm_attach;0;ccw-0.0.401c, + cmds += vm_reboot;0, + cmds += vm_detach;0;ccw-0.0.401c, + cmds += vm_attach;0;ccw-0.0.401c, + cmds += vm_reboot;0, + cmds += vm_detach;0;ccw-0.0.401c, + cmds += vm_attach;0;ccw-0.0.401c, + cmds += vm_reboot;0, + cmds += vm_detach;0;ccw-0.0.401c, + cmds += vm_attach;0;ccw-0.0.401c, + cmds += vm_reboot;0, + cmds += vm_detach;0;ccw-0.0.401c, + cmds += vm_attach;0;ccw-0.0.401c, + cmds += vm_reboot;0, + cmds += vm_detach;0;ccw-0.0.401c, + cmds += vm_attach;0;ccw-0.0.401c, + cmds += vm_reboot;0, + cmds += vm_detach;0;ccw-0.0.401c, + cmds += vm_attach;0;ccw-0.0.401c, + cmds += vm_reboot;0, + cmds += vm_detach;0;ccw-0.0.401c, + cmds += vm_attach;0;ccw-0.0.401c, + cmds += vm_reboot;0, + cmds += vm_detach;0;ccw-0.0.401c, + cmds += vm_attach;0;ccw-0.0.401c, + cmds += vm_reboot;0, + cmds += vm_detach;0;ccw-0.0.401c, + cmds += vm_attach;0;ccw-0.0.401c, + cmds += vm_reboot;0, + cmds += vm_check_present;0;ccw-0.0.401c, + - vm_stopped_attach_start_10_times_detach_attach_reboot.ism: + cmds = start;ism-0000:00:00.0, + cmds += vm_attach;0;ism-0000:00:00.0, + cmds += vm_start;0, + cmds += vm_detach;0;ism-0000:00:00.0, + cmds += vm_attach;0;ism-0000:00:00.0, + cmds += vm_reboot;0, + cmds += vm_reboot;0, + cmds += vm_reboot;0, + cmds += vm_reboot;0, + cmds += vm_reboot;0, + cmds += vm_reboot;0, + cmds += vm_reboot;0, + cmds += vm_reboot;0, + cmds += vm_reboot;0, + cmds += vm_reboot;0, + cmds += vm_check_present;0;ism-0000:00:00.0, + - vm_stopped_attach_start_10_times_detach_attach_reboot.roce: + cmds = start;roce-0002:00:00.0, + cmds += vm_attach;0;roce-0002:00:00.0, + cmds += vm_start;0, + cmds += vm_detach;0;roce-0002:00:00.0, + cmds += vm_attach;0;roce-0002:00:00.0, + cmds += vm_reboot;0, + cmds += vm_detach;0;roce-0002:00:00.0, + cmds += vm_attach;0;roce-0002:00:00.0, + cmds += vm_reboot;0, + cmds += vm_detach;0;roce-0002:00:00.0, + cmds += vm_attach;0;roce-0002:00:00.0, + cmds += vm_reboot;0, + cmds += vm_detach;0;roce-0002:00:00.0, + cmds += vm_attach;0;roce-0002:00:00.0, + cmds += vm_reboot;0, + cmds += vm_detach;0;roce-0002:00:00.0, + cmds += vm_attach;0;roce-0002:00:00.0, + cmds += vm_reboot;0, + cmds += vm_detach;0;roce-0002:00:00.0, + cmds += vm_attach;0;roce-0002:00:00.0, + cmds += vm_reboot;0, + cmds += vm_detach;0;roce-0002:00:00.0, + cmds += vm_attach;0;roce-0002:00:00.0, + cmds += vm_reboot;0, + cmds += vm_detach;0;roce-0002:00:00.0, + cmds += vm_attach;0;roce-0002:00:00.0, + cmds += vm_reboot;0, + cmds += vm_detach;0;roce-0002:00:00.0, + cmds += vm_attach;0;roce-0002:00:00.0, + cmds += vm_reboot;0, + cmds += vm_detach;0;roce-0002:00:00.0, + cmds += vm_attach;0;roce-0002:00:00.0, + cmds += vm_reboot;0, + cmds += vm_check_present;0;roce-0002:00:00.0, + - vm_stopped_attach_start_10_times_detach_attach_reboot.all: + cmds = start;ap-00.000e, + cmds += start;ccw-0.0.401c, + cmds += start;roce-0002:00:00.0, + cmds += start;ism-0000:00:00.0, + cmds += vm_attach;0;ccw-0.0.401c, + cmds += vm_attach;0;ap-00.000e, + cmds += vm_attach;0;ism-0000:00:00.0, + cmds += vm_attach;0;roce-0002:00:00.0, + cmds += vm_start;0, + cmds += vm_detach;0;ccw-0.0.401c, + cmds += vm_detach;0;ap-00.000e, + cmds += vm_detach;0;ism-0000:00:00.0, + cmds += vm_detach;0;roce-0002:00:00.0, + cmds += vm_attach;0;ccw-0.0.401c, + cmds += vm_attach;0;ap-00.000e, + cmds += vm_attach;0;ism-0000:00:00.0, + cmds += vm_attach;0;roce-0002:00:00.0, + cmds += vm_reboot;0, + cmds += vm_detach;0;ccw-0.0.401c, + cmds += vm_detach;0;ap-00.000e, + cmds += vm_detach;0;ism-0000:00:00.0, + cmds += vm_detach;0;roce-0002:00:00.0, + cmds += vm_attach;0;ccw-0.0.401c, + cmds += vm_attach;0;ap-00.000e, + cmds += vm_attach;0;ism-0000:00:00.0, + cmds += vm_attach;0;roce-0002:00:00.0, + cmds += vm_reboot;0, + cmds += vm_detach;0;ccw-0.0.401c, + cmds += vm_detach;0;ap-00.000e, + cmds += vm_detach;0;ism-0000:00:00.0, + cmds += vm_detach;0;roce-0002:00:00.0, + cmds += vm_attach;0;ccw-0.0.401c, + cmds += vm_attach;0;ap-00.000e, + cmds += vm_attach;0;ism-0000:00:00.0, + cmds += vm_attach;0;roce-0002:00:00.0, + cmds += vm_reboot;0, + cmds += vm_detach;0;ccw-0.0.401c, + cmds += vm_detach;0;ap-00.000e, + cmds += vm_detach;0;ism-0000:00:00.0, + cmds += vm_detach;0;roce-0002:00:00.0, + cmds += vm_attach;0;ccw-0.0.401c, + cmds += vm_attach;0;ap-00.000e, + cmds += vm_attach;0;ism-0000:00:00.0, + cmds += vm_attach;0;roce-0002:00:00.0, + cmds += vm_reboot;0, + cmds += vm_detach;0;ccw-0.0.401c, + cmds += vm_detach;0;ap-00.000e, + cmds += vm_detach;0;ism-0000:00:00.0, + cmds += vm_detach;0;roce-0002:00:00.0, + cmds += vm_attach;0;ccw-0.0.401c, + cmds += vm_attach;0;ap-00.000e, + cmds += vm_attach;0;ism-0000:00:00.0, + cmds += vm_attach;0;roce-0002:00:00.0, + cmds += vm_reboot;0, + cmds += vm_detach;0;ccw-0.0.401c, + cmds += vm_detach;0;ap-00.000e, + cmds += vm_detach;0;ism-0000:00:00.0, + cmds += vm_detach;0;roce-0002:00:00.0, + cmds += vm_attach;0;ccw-0.0.401c, + cmds += vm_attach;0;ap-00.000e, + cmds += vm_attach;0;ism-0000:00:00.0, + cmds += vm_attach;0;roce-0002:00:00.0, + cmds += vm_reboot;0, + cmds += vm_detach;0;ccw-0.0.401c, + cmds += vm_detach;0;ap-00.000e, + cmds += vm_detach;0;ism-0000:00:00.0, + cmds += vm_detach;0;roce-0002:00:00.0, + cmds += vm_attach;0;ccw-0.0.401c, + cmds += vm_attach;0;ap-00.000e, + cmds += vm_attach;0;ism-0000:00:00.0, + cmds += vm_attach;0;roce-0002:00:00.0, + cmds += vm_reboot;0, + cmds += vm_detach;0;ccw-0.0.401c, + cmds += vm_detach;0;ap-00.000e, + cmds += vm_detach;0;ism-0000:00:00.0, + cmds += vm_detach;0;roce-0002:00:00.0, + cmds += vm_attach;0;ccw-0.0.401c, + cmds += vm_attach;0;ap-00.000e, + cmds += vm_attach;0;ism-0000:00:00.0, + cmds += vm_attach;0;roce-0002:00:00.0, + cmds += vm_reboot;0, + cmds += vm_detach;0;ccw-0.0.401c, + cmds += vm_detach;0;ap-00.000e, + cmds += vm_detach;0;ism-0000:00:00.0, + cmds += vm_detach;0;roce-0002:00:00.0, + cmds += vm_attach;0;ccw-0.0.401c, + cmds += vm_attach;0;ap-00.000e, + cmds += vm_attach;0;ism-0000:00:00.0, + cmds += vm_attach;0;roce-0002:00:00.0, + cmds += vm_reboot;0, + cmds += vm_detach;0;ccw-0.0.401c, + cmds += vm_detach;0;ap-00.000e, + cmds += vm_detach;0;ism-0000:00:00.0, + cmds += vm_detach;0;roce-0002:00:00.0, + cmds += vm_attach;0;ccw-0.0.401c, + cmds += vm_attach;0;ap-00.000e, + cmds += vm_attach;0;ism-0000:00:00.0, + cmds += vm_attach;0;roce-0002:00:00.0, + cmds += vm_reboot;0, + cmds += vm_check_present;0;ap-00.000e, + cmds += vm_check_present;0;ccw-0.0.401c, + cmds += vm_check_present;0;ism-0000:00:00.0, + cmds += vm_check_present;0;roce-0002:00:00.0, + - vm_running_attach_attach.ccw: + cmds = vm_start;0, + cmds += start;ccw-0.0.401c, + cmds += vm_attach;0;ccw-0.0.401c, + cmds += start;ccw-0.0.401d, + cmds += vm_attach;0;ccw-0.0.401d, + cmds += vm_check_present;0;ccw-0.0.401c, + cmds += vm_check_present;0;ccw-0.0.401d, + - vm_running_attach_attach.ism: + cmds = vm_start;0, + cmds += start;ism-0000:00:00.0, + cmds += vm_attach;0;ism-0000:00:00.0, + cmds += start;ism-0001:00:00.0, + cmds += vm_attach;0;ism-0001:00:00.0, + cmds += vm_check_present;0;ism-0000:00:00.0, + cmds += vm_check_present;0;ism-0001:00:00.0, + - vm_running_attach_attach.roce: + cmds = vm_start;0, + cmds += start;roce-0002:00:00.0, + cmds += vm_attach;0;roce-0002:00:00.0, + cmds += start;roce-0003:00:00.0, + cmds += vm_attach;0;roce-0003:00:00.0, + cmds += vm_check_present;0;roce-0002:00:00.0, + cmds += vm_check_present;0;roce-0003:00:00.0, + - vm_running_attach_attach.all: + cmds = vm_start;0, + cmds += start;ap-00.000e, + cmds += vm_attach;0;ap-00.000e, + cmds += start;ccw-0.0.401c, + cmds += vm_attach;0;ccw-0.0.401c, + cmds += start;ccw-0.0.401d, + cmds += vm_attach;0;ccw-0.0.401d, + cmds += start;ism-0000:00:00.0, + cmds += vm_attach;0;ism-0000:00:00.0, + cmds += start;ism-0001:00:00.0, + cmds += vm_attach;0;ism-0001:00:00.0, + cmds += start;roce-0002:00:00.0, + cmds += vm_attach;0;roce-0002:00:00.0, + cmds += start;roce-0003:00:00.0, + cmds += vm_attach;0;roce-0003:00:00.0, + cmds += vm_check_present;0;ccw-0.0.401c, + cmds += vm_check_present;0;ccw-0.0.401d, + cmds += vm_check_present;0;ism-0000:00:00.0, + cmds += vm_check_present;0;ism-0001:00:00.0, + cmds += vm_check_present;0;roce-0002:00:00.0, + cmds += vm_check_present;0;roce-0003:00:00.0, + cmds += vm_check_present;0;ap-00.000e, + - vm_running_attach_attach_reboot.ccw: + cmds = vm_start;0, + cmds += start;ccw-0.0.401c, + cmds += vm_attach;0;ccw-0.0.401c, + cmds += start;ccw-0.0.401d, + cmds += vm_attach;0;ccw-0.0.401d, + cmds += vm_reboot;0, + cmds += vm_check_present;0;ccw-0.0.401c, + cmds += vm_check_present;0;ccw-0.0.401d, + - vm_running_attach_attach_reboot.ism: + cmds = vm_start;0, + cmds += start;ism-0000:00:00.0, + cmds += vm_attach;0;ism-0000:00:00.0, + cmds += start;ism-0001:00:00.0, + cmds += vm_attach;0;ism-0001:00:00.0, + cmds += vm_reboot;0, + cmds += vm_check_present;0;ism-0000:00:00.0, + cmds += vm_check_present;0;ism-0001:00:00.0, + - vm_running_attach_attach_reboot.roce: + cmds = vm_start;0, + cmds += start;roce-0002:00:00.0, + cmds += vm_attach;0;roce-0002:00:00.0, + cmds += start;roce-0003:00:00.0, + cmds += vm_attach;0;roce-0003:00:00.0, + cmds += vm_reboot;0, + cmds += vm_check_present;0;roce-0002:00:00.0, + cmds += vm_check_present;0;roce-0003:00:00.0, + - vm_running_attach_attach_reboot.all: + cmds = vm_start;0, + cmds += start;ap-00.000e, + cmds += vm_attach;0;ap-00.000e, + cmds += start;ccw-0.0.401c, + cmds += vm_attach;0;ccw-0.0.401c, + cmds += start;ccw-0.0.401d, + cmds += vm_attach;0;ccw-0.0.401d, + cmds += start;ism-0000:00:00.0, + cmds += vm_attach;0;ism-0000:00:00.0, + cmds += start;ism-0001:00:00.0, + cmds += vm_attach;0;ism-0001:00:00.0, + cmds += start;roce-0002:00:00.0, + cmds += vm_attach;0;roce-0002:00:00.0, + cmds += start;roce-0003:00:00.0, + cmds += vm_attach;0;roce-0003:00:00.0, + cmds += vm_reboot;0, + cmds += vm_check_present;0;ccw-0.0.401c, + cmds += vm_check_present;0;ccw-0.0.401d, + cmds += vm_check_present;0;ism-0000:00:00.0, + cmds += vm_check_present;0;ism-0001:00:00.0, + cmds += vm_check_present;0;roce-0002:00:00.0, + cmds += vm_check_present;0;roce-0003:00:00.0, + cmds += vm_check_present;0;ap-00.000e, + - vm_running_attach_attach_pause_resume.ccw: + cmds = vm_start;0, + cmds += start;ccw-0.0.401c, + cmds += vm_attach;0;ccw-0.0.401c, + cmds += start;ccw-0.0.401d, + cmds += vm_attach;0;ccw-0.0.401d, + cmds += vm_pause;0, + cmds += vm_resume;0, + cmds += vm_check_present;0;ccw-0.0.401c, + cmds += vm_check_present;0;ccw-0.0.401d, + - vm_running_attach_attach_pause_resume.ism: + cmds = vm_start;0, + cmds += start;ism-0000:00:00.0, + cmds += vm_attach;0;ism-0000:00:00.0, + cmds += start;ism-0001:00:00.0, + cmds += vm_attach;0;ism-0001:00:00.0, + cmds += vm_pause;0, + cmds += vm_resume;0, + cmds += vm_check_present;0;ism-0000:00:00.0, + cmds += vm_check_present;0;ism-0001:00:00.0, + - vm_running_attach_attach_pause_resume.roce: + cmds = vm_start;0, + cmds += start;roce-0002:00:00.0, + cmds += vm_attach;0;roce-0002:00:00.0, + cmds += start;roce-0003:00:00.0, + cmds += vm_attach;0;roce-0003:00:00.0, + cmds += vm_pause;0, + cmds += vm_resume;0, + cmds += vm_check_present;0;roce-0002:00:00.0, + cmds += vm_check_present;0;roce-0003:00:00.0, + - vm_running_attach_attach_pause_resume.all: + cmds = vm_start;0, + cmds += start;ap-00.000e, + cmds += vm_attach;0;ap-00.000e, + cmds += start;ccw-0.0.401c, + cmds += vm_attach;0;ccw-0.0.401c, + cmds += start;ccw-0.0.401d, + cmds += vm_attach;0;ccw-0.0.401d, + cmds += start;ism-0000:00:00.0, + cmds += vm_attach;0;ism-0000:00:00.0, + cmds += start;ism-0001:00:00.0, + cmds += vm_attach;0;ism-0001:00:00.0, + cmds += start;roce-0002:00:00.0, + cmds += vm_attach;0;roce-0002:00:00.0, + cmds += start;roce-0003:00:00.0, + cmds += vm_attach;0;roce-0003:00:00.0, + cmds += vm_pause;0, + cmds += vm_resume;0, + cmds += vm_check_present;0;ccw-0.0.401c, + cmds += vm_check_present;0;ccw-0.0.401d, + cmds += vm_check_present;0;ism-0000:00:00.0, + cmds += vm_check_present;0;ism-0001:00:00.0, + cmds += vm_check_present;0;roce-0002:00:00.0, + cmds += vm_check_present;0;roce-0003:00:00.0, + cmds += vm_check_present;0;ap-00.000e, + - vm_running_attach_attach_detach_attach_detach_attach.ccw: + cmds = vm_start;0, + cmds += start;ccw-0.0.401c, + cmds += vm_attach;0;ccw-0.0.401c, + cmds += start;ccw-0.0.401d, + cmds += vm_attach;0;ccw-0.0.401d, + cmds += vm_detach;0;ccw-0.0.401c, + cmds += vm_detach;0;ccw-0.0.401d, + cmds += vm_attach;0;ccw-0.0.401c, + cmds += vm_attach;0;ccw-0.0.401d, + cmds += vm_check_present;0;ccw-0.0.401c, + cmds += vm_check_present;0;ccw-0.0.401d, + - vm_running_attach_attach_detach_attach_detach_attach.ism: + cmds = vm_start;0, + cmds += start;ism-0000:00:00.0, + cmds += vm_attach;0;ism-0000:00:00.0, + cmds += start;ism-0001:00:00.0, + cmds += vm_attach;0;ism-0001:00:00.0, + cmds += vm_detach;0;ism-0000:00:00.0, + cmds += vm_detach;0;ism-0001:00:00.0, + cmds += vm_attach;0;ism-0000:00:00.0, + cmds += vm_attach;0;ism-0001:00:00.0, + cmds += vm_check_present;0;ism-0000:00:00.0, + cmds += vm_check_present;0;ism-0001:00:00.0, + - vm_running_attach_attach_detach_attach_detach_attach.roce: + cmds = vm_start;0, + cmds += start;roce-0002:00:00.0, + cmds += vm_attach;0;roce-0002:00:00.0, + cmds += start;roce-0003:00:00.0, + cmds += vm_attach;0;roce-0003:00:00.0, + cmds += vm_detach;0;roce-0002:00:00.0, + cmds += vm_detach;0;roce-0003:00:00.0, + cmds += vm_attach;0;roce-0002:00:00.0, + cmds += vm_attach;0;roce-0003:00:00.0, + cmds += vm_check_present;0;roce-0002:00:00.0, + cmds += vm_check_present;0;roce-0003:00:00.0, + - vm_running_attach_attach_detach_attach_detach_attach.all: + cmds = vm_start;0, + cmds += start;ap-00.000e, + cmds += vm_attach;0;ap-00.000e, + cmds += start;ccw-0.0.401c, + cmds += vm_attach;0;ccw-0.0.401c, + cmds += start;ccw-0.0.401d, + cmds += vm_attach;0;ccw-0.0.401d, + cmds += start;ism-0000:00:00.0, + cmds += vm_attach;0;ism-0000:00:00.0, + cmds += start;ism-0001:00:00.0, + cmds += vm_attach;0;ism-0001:00:00.0, + cmds += start;roce-0002:00:00.0, + cmds += vm_attach;0;roce-0002:00:00.0, + cmds += start;roce-0003:00:00.0, + cmds += vm_attach;0;roce-0003:00:00.0, + cmds += vm_detach;0;ap-00.000e, + cmds += vm_detach;0;ccw-0.0.401c, + cmds += vm_detach;0;ccw-0.0.401d, + cmds += vm_detach;0;ism-0000:00:00.0, + cmds += vm_detach;0;ism-0001:00:00.0, + cmds += vm_detach;0;roce-0002:00:00.0, + cmds += vm_detach;0;roce-0003:00:00.0, + cmds += vm_attach;0;ap-00.000e, + cmds += vm_attach;0;ccw-0.0.401c, + cmds += vm_attach;0;ccw-0.0.401d, + cmds += vm_attach;0;ism-0000:00:00.0, + cmds += vm_attach;0;ism-0001:00:00.0, + cmds += vm_attach;0;roce-0002:00:00.0, + cmds += vm_attach;0;roce-0003:00:00.0, + cmds += vm_check_present;0;ccw-0.0.401c, + cmds += vm_check_present;0;ccw-0.0.401d, + cmds += vm_check_present;0;ism-0000:00:00.0, + cmds += vm_check_present;0;ism-0001:00:00.0, + cmds += vm_check_present;0;roce-0002:00:00.0, + cmds += vm_check_present;0;roce-0003:00:00.0, + cmds += vm_check_present;0;ap-00.000e, + - vm_running_attach_attach_reboot_detach_attach_detach_attach.ccw: + cmds = vm_start;0, + cmds += start;ccw-0.0.401c, + cmds += vm_attach;0;ccw-0.0.401c, + cmds += start;ccw-0.0.401d, + cmds += vm_attach;0;ccw-0.0.401d, + cmds += vm_reboot;0, + cmds += vm_detach;0;ccw-0.0.401c, + cmds += vm_detach;0;ccw-0.0.401d, + cmds += vm_attach;0;ccw-0.0.401c, + cmds += vm_attach;0;ccw-0.0.401d, + cmds += vm_check_present;0;ccw-0.0.401c, + cmds += vm_check_present;0;ccw-0.0.401d, + - vm_running_attach_attach_reboot_detach_attach_detach_attach.ism: + cmds = vm_start;0, + cmds += start;ism-0000:00:00.0, + cmds += vm_attach;0;ism-0000:00:00.0, + cmds += start;ism-0001:00:00.0, + cmds += vm_attach;0;ism-0001:00:00.0, + cmds += vm_reboot;0, + cmds += vm_detach;0;ism-0000:00:00.0, + cmds += vm_detach;0;ism-0001:00:00.0, + cmds += vm_attach;0;ism-0000:00:00.0, + cmds += vm_attach;0;ism-0001:00:00.0, + cmds += vm_check_present;0;ism-0000:00:00.0, + cmds += vm_check_present;0;ism-0001:00:00.0, + - vm_running_attach_attach_reboot_detach_attach_detach_attach.roce: + cmds = vm_start;0, + cmds += start;roce-0002:00:00.0, + cmds += vm_attach;0;roce-0002:00:00.0, + cmds += start;roce-0003:00:00.0, + cmds += vm_attach;0;roce-0003:00:00.0, + cmds += vm_reboot;0, + cmds += vm_detach;0;roce-0002:00:00.0, + cmds += vm_detach;0;roce-0003:00:00.0, + cmds += vm_attach;0;roce-0002:00:00.0, + cmds += vm_attach;0;roce-0003:00:00.0, + cmds += vm_check_present;0;roce-0002:00:00.0, + cmds += vm_check_present;0;roce-0003:00:00.0, + - vm_running_attach_attach_reboot_detach_attach_detach_attach.all: + cmds = vm_start;0, + cmds += start;ap-00.000e, + cmds += vm_attach;0;ap-00.000e, + cmds += start;ccw-0.0.401c, + cmds += vm_attach;0;ccw-0.0.401c, + cmds += start;ccw-0.0.401d, + cmds += vm_attach;0;ccw-0.0.401d, + cmds += start;ism-0000:00:00.0, + cmds += vm_attach;0;ism-0000:00:00.0, + cmds += start;ism-0001:00:00.0, + cmds += vm_attach;0;ism-0001:00:00.0, + cmds += start;roce-0002:00:00.0, + cmds += vm_attach;0;roce-0002:00:00.0, + cmds += start;roce-0003:00:00.0, + cmds += vm_attach;0;roce-0003:00:00.0, + cmds += vm_reboot;0, + cmds += vm_detach;0;ap-00.000e, + cmds += vm_detach;0;ccw-0.0.401c, + cmds += vm_detach;0;ccw-0.0.401d, + cmds += vm_detach;0;ism-0000:00:00.0, + cmds += vm_detach;0;ism-0001:00:00.0, + cmds += vm_detach;0;roce-0002:00:00.0, + cmds += vm_detach;0;roce-0003:00:00.0, + cmds += vm_attach;0;ap-00.000e, + cmds += vm_attach;0;ccw-0.0.401c, + cmds += vm_attach;0;ccw-0.0.401d, + cmds += vm_attach;0;ism-0000:00:00.0, + cmds += vm_attach;0;ism-0001:00:00.0, + cmds += vm_attach;0;roce-0002:00:00.0, + cmds += vm_attach;0;roce-0003:00:00.0, + cmds += vm_check_present;0;ccw-0.0.401c, + cmds += vm_check_present;0;ccw-0.0.401d, + cmds += vm_check_present;0;ism-0000:00:00.0, + cmds += vm_check_present;0;ism-0001:00:00.0, + cmds += vm_check_present;0;roce-0002:00:00.0, + cmds += vm_check_present;0;roce-0003:00:00.0, + cmds += vm_check_present;0;ap-00.000e, + - vm_running_attach_detach_mdevrestart_attach.ap: + cmds = vm_start;0, + cmds += start;ap-00.000e, + cmds += vm_attach;0;ap-00.000e, + cmds += vm_detach;0;ap-00.000e, + cmds += stop;ap-00.000e, + cmds += start;ap-00.000e, + cmds += vm_attach;0;ap-00.000e, + cmds += vm_check_present;0;ap-00.000e, + - vm_running_attach_detach_mdevrestart_attach.ccw: + cmds = vm_start;0, + cmds += start;ccw-0.0.401c, + cmds += vm_attach;0;ccw-0.0.401c, + cmds += vm_detach;0;ccw-0.0.401c, + cmds += stop;ccw-0.0.401c, + cmds += start;ccw-0.0.401c, + cmds += vm_attach;0;ccw-0.0.401c, + cmds += vm_check_present;0;ccw-0.0.401c, + - vm_running_attach_detach_mdevrestart_attach.all: + cmds = vm_start;0, + cmds += start;ap-00.000e, + cmds += start;ccw-0.0.401c, + cmds += start;roce-0002:00:00.0, + cmds += start;ism-0000:00:00.0, + cmds += vm_attach;0;ccw-0.0.401c, + cmds += vm_attach;0;ap-00.000e, + cmds += vm_attach;0;ism-0000:00:00.0, + cmds += vm_attach;0;roce-0002:00:00.0, + cmds += vm_detach;0;ccw-0.0.401c, + cmds += vm_detach;0;ap-00.000e, + cmds += vm_detach;0;ism-0000:00:00.0, + cmds += vm_detach;0;roce-0002:00:00.0, + cmds += stop;ap-00.000e, + cmds += start;ap-00.000e, + cmds += stop;ccw-0.0.401c, + cmds += start;ccw-0.0.401c, + cmds += vm_attach;0;ccw-0.0.401c, + cmds += vm_attach;0;ap-00.000e, + cmds += vm_attach;0;ism-0000:00:00.0, + cmds += vm_attach;0;roce-0002:00:00.0, + cmds += vm_check_present;0;ap-00.000e, + cmds += vm_check_present;0;ccw-0.0.401c, + cmds += vm_check_present;0;ism-0000:00:00.0, + cmds += vm_check_present;0;roce-0002:00:00.0, + - vm_running_attach_detach_vm2_attach.ap: + cmds = vm_start;0, + cmds += vm_start;1, + cmds += start;ap-00.000e, + cmds += vm_attach;0;ap-00.000e, + cmds += vm_detach;0;ap-00.000e, + cmds += vm_attach;1;ap-00.000e, + cmds += vm_check_present;1;ap-00.000e, + - vm_running_attach_detach_vm2_attach.ccw: + cmds = vm_start;0, + cmds += vm_start;1, + cmds += start;ccw-0.0.401c, + cmds += vm_attach;0;ccw-0.0.401c, + cmds += vm_detach;0;ccw-0.0.401c, + cmds += vm_attach;1;ccw-0.0.401c, + cmds += vm_check_present;1;ccw-0.0.401c, + - vm_running_attach_detach_vm2_attach.ism: + cmds = vm_start;0, + cmds += vm_start;1, + cmds += start;ism-0000:00:00.0, + cmds += vm_attach;0;ism-0000:00:00.0, + cmds += vm_detach;0;ism-0000:00:00.0, + cmds += vm_attach;1;ism-0000:00:00.0, + cmds += vm_check_present;1;ism-0000:00:00.0, + - vm_running_attach_detach_vm2_attach.roce: + cmds = vm_start;0, + cmds += vm_start;1, + cmds += start;roce-0002:00:00.0, + cmds += vm_attach;0;roce-0002:00:00.0, + cmds += vm_detach;0;roce-0002:00:00.0, + cmds += vm_attach;1;roce-0002:00:00.0, + cmds += vm_check_present;1;roce-0002:00:00.0, + - vm_running_attach_detach_vm2_attach.all: + cmds = vm_start;0, + cmds += vm_start;1, + cmds += start;ap-00.000e, + cmds += start;ccw-0.0.401c, + cmds += start;roce-0002:00:00.0, + cmds += start;ism-0000:00:00.0, + cmds += vm_attach;0;ccw-0.0.401c, + cmds += vm_attach;0;ap-00.000e, + cmds += vm_attach;0;ism-0000:00:00.0, + cmds += vm_attach;0;roce-0002:00:00.0, + cmds += vm_detach;0;ccw-0.0.401c, + cmds += vm_detach;0;ap-00.000e, + cmds += vm_detach;0;ism-0000:00:00.0, + cmds += vm_detach;0;roce-0002:00:00.0, + cmds += vm_attach;1;ccw-0.0.401c, + cmds += vm_attach;1;ap-00.000e, + cmds += vm_attach;1;ism-0000:00:00.0, + cmds += vm_attach;1;roce-0002:00:00.0, + cmds += vm_check_present;1;ap-00.000e, + cmds += vm_check_present;1;ccw-0.0.401c, + cmds += vm_check_present;1;ism-0000:00:00.0, + cmds += vm_check_present;1;roce-0002:00:00.0, + - vm_running_attach_detach_vm2_attach_detach_vm_attach.ap: + cmds = vm_start;0, + cmds += vm_start;1, + cmds += start;ap-00.000e, + cmds += vm_attach;0;ap-00.000e, + cmds += vm_detach;0;ap-00.000e, + cmds += vm_attach;1;ap-00.000e, + cmds += vm_detach;1;ap-00.000e, + cmds += vm_attach;0;ap-00.000e, + cmds += vm_check_present;0;ap-00.000e, + - vm_running_attach_detach_vm2_attach_detach_vm_attach.ccw: + cmds = vm_start;0, + cmds += vm_start;1, + cmds += start;ccw-0.0.401c, + cmds += vm_attach;0;ccw-0.0.401c, + cmds += vm_detach;0;ccw-0.0.401c, + cmds += vm_attach;1;ccw-0.0.401c, + cmds += vm_detach;1;ccw-0.0.401c, + cmds += vm_attach;0;ccw-0.0.401c, + cmds += vm_check_present;0;ccw-0.0.401c, + - vm_running_attach_detach_vm2_attach_detach_vm_attach.ism: + cmds = vm_start;0, + cmds += vm_start;1, + cmds += start;ism-0000:00:00.0, + cmds += vm_attach;0;ism-0000:00:00.0, + cmds += vm_detach;0;ism-0000:00:00.0, + cmds += vm_attach;1;ism-0000:00:00.0, + cmds += vm_detach;1;ism-0000:00:00.0, + cmds += vm_attach;0;ism-0000:00:00.0, + cmds += vm_check_present;0;ism-0000:00:00.0, + - vm_running_attach_detach_vm2_attach_detach_vm_attach.roce: + cmds = vm_start;0, + cmds += vm_start;1, + cmds += start;roce-0002:00:00.0, + cmds += vm_attach;0;roce-0002:00:00.0, + cmds += vm_detach;0;roce-0002:00:00.0, + cmds += vm_attach;1;roce-0002:00:00.0, + cmds += vm_detach;1;roce-0002:00:00.0, + cmds += vm_attach;0;roce-0002:00:00.0, + cmds += vm_check_present;0;roce-0002:00:00.0, + - vm_running_attach_detach_vm2_attach_detach_vm_attach.all: + cmds = vm_start;0, + cmds += vm_start;1, + cmds += start;ap-00.000e, + cmds += start;ccw-0.0.401c, + cmds += start;roce-0002:00:00.0, + cmds += start;ism-0000:00:00.0, + cmds += vm_attach;0;ccw-0.0.401c, + cmds += vm_attach;0;ap-00.000e, + cmds += vm_attach;0;ism-0000:00:00.0, + cmds += vm_attach;0;roce-0002:00:00.0, + cmds += vm_detach;0;ccw-0.0.401c, + cmds += vm_detach;0;ap-00.000e, + cmds += vm_detach;0;ism-0000:00:00.0, + cmds += vm_detach;0;roce-0002:00:00.0, + cmds += vm_attach;1;ccw-0.0.401c, + cmds += vm_attach;1;ap-00.000e, + cmds += vm_attach;1;ism-0000:00:00.0, + cmds += vm_attach;1;roce-0002:00:00.0, + cmds += vm_detach;1;ccw-0.0.401c, + cmds += vm_detach;1;ap-00.000e, + cmds += vm_detach;1;ism-0000:00:00.0, + cmds += vm_detach;1;roce-0002:00:00.0, + cmds += vm_attach;0;ccw-0.0.401c, + cmds += vm_attach;0;ap-00.000e, + cmds += vm_attach;0;ism-0000:00:00.0, + cmds += vm_attach;0;roce-0002:00:00.0, + cmds += vm_check_present;0;ap-00.000e, + cmds += vm_check_present;0;ccw-0.0.401c, + cmds += vm_check_present;0;ism-0000:00:00.0, + cmds += vm_check_present;0;roce-0002:00:00.0, diff --git a/libvirt/tests/cfg/remote_access/remote_with_tls.cfg b/libvirt/tests/cfg/remote_access/remote_with_tls.cfg index de0d07681e1..939c10c343a 100644 --- a/libvirt/tests/cfg/remote_access/remote_with_tls.cfg +++ b/libvirt/tests/cfg/remote_access/remote_with_tls.cfg @@ -55,7 +55,7 @@ server_ip = "${ipv6_addr_des}" - default_tls_port_and_auth_tls: - default_tls_priority_specifier: - filter_pattern = "Setting priority string \'@LIBVIRT\,SYSTEM\'" + filter_pattern = "Setting priority string '@LIBVIRT,SYSTEM'" log_level= "LIBVIRT_DEBUG=1" - no_verify_certificate: tls_verify_cert = "no" diff --git a/libvirt/tests/cfg/save_and_restore/abort_managedsave.cfg b/libvirt/tests/cfg/save_and_restore/abort_managedsave.cfg new file mode 100644 index 00000000000..7c35152c459 --- /dev/null +++ b/libvirt/tests/cfg/save_and_restore/abort_managedsave.cfg @@ -0,0 +1,9 @@ +- save_and_restore.abort_managedsave: + type = abort_managedsave + save_opt = + start_vm = no + default_path = "/var/lib/libvirt/qemu/save" + event_cmd = "event --loop --all" + expected_event = ["Suspended Paused", "Resumed Unpaused"] + stress_type = "stress" + stress_cmds = "stress --cpu 8 --io 4 --vm 2 --vm-bytes 128M --vm-keep" diff --git a/libvirt/tests/cfg/save_and_restore/abort_save.cfg b/libvirt/tests/cfg/save_and_restore/abort_save.cfg new file mode 100644 index 00000000000..02ea2f052f9 --- /dev/null +++ b/libvirt/tests/cfg/save_and_restore/abort_save.cfg @@ -0,0 +1,6 @@ +- save_and_restore.abort_save: + type = abort_save + start_vm = no + stress_type = "stress" + stress_cmds = "stress --cpu 8 --io 4 --vm 2 --vm-bytes 128M --vm-keep" + diff --git a/libvirt/tests/cfg/save_and_restore/managedsave_dumpxml.cfg b/libvirt/tests/cfg/save_and_restore/managedsave_dumpxml.cfg new file mode 100644 index 00000000000..f839742e367 --- /dev/null +++ b/libvirt/tests/cfg/save_and_restore/managedsave_dumpxml.cfg @@ -0,0 +1,21 @@ +- save_and_restore.managedsave_dumpxml: + type = managedsave_dumpxml + graphic_attrs = {'listen_attrs': {'type': 'address'}, 'type_name': 'vnc', 'autoport': 'yes', 'passwd': '12345'} + variants: + - no_option: + option = "" + - security_info: + option = "--security-info" + - xpath: + option = "--xpath //os" + - wrap: + option = "--xpath //os --wrap" + variants: + - not_readonly: + - readonly: + only no_option, security_info + readonly = "yes" + security_info: + err_msg = "operation forbidden: virDomainManagedSaveGetXMLDesc with secure flag" + + diff --git a/libvirt/tests/cfg/save_and_restore/managedsave_remove.cfg b/libvirt/tests/cfg/save_and_restore/managedsave_remove.cfg new file mode 100644 index 00000000000..6e68079bb2d --- /dev/null +++ b/libvirt/tests/cfg/save_and_restore/managedsave_remove.cfg @@ -0,0 +1,17 @@ +- save_and_restore.managedsave_remove: + type = managedsave_remove + start_vm = yes + status_error = no + variants: + - normal: + file_state = normal + only managedsaved + - corrupt: + file_state = corrupt + - nonexist: + file_state = nonexist + variants: + - managedsaved: + vm_managedsaved = yes + - not_managedsaved: + vm_managedsaved = no diff --git a/libvirt/tests/cfg/save_and_restore/save_with_formats.cfg b/libvirt/tests/cfg/save_and_restore/save_with_formats.cfg index 702bbbda463..b08d15a27ff 100644 --- a/libvirt/tests/cfg/save_and_restore/save_with_formats.cfg +++ b/libvirt/tests/cfg/save_and_restore/save_with_formats.cfg @@ -12,8 +12,3 @@ - gzip: - bzip2: - xz: - - negative_test: - status_error = yes - variants save_format: - - abc: - error_msg = Invalid save image format specified in configuration file diff --git a/libvirt/tests/cfg/save_and_restore/save_with_options.cfg b/libvirt/tests/cfg/save_and_restore/save_with_options.cfg index 1e2d8056768..606b78223e9 100644 --- a/libvirt/tests/cfg/save_and_restore/save_with_options.cfg +++ b/libvirt/tests/cfg/save_and_restore/save_with_options.cfg @@ -3,6 +3,10 @@ variants scenario: - no_opt: options = + check_reason = yes + check_reason_cmd = "while true; do virsh domjobinfo avocado-vt-vm1; done" + pattern_running = "Job type:\s*Unbounded\s*Operation:\s*Save" + pattern_completed = "Job type:\s*Completed\s*Operation:\s*Save" - verbose_opt: options = --verbose expect_msg = 'Save:\s\[100.*%\]' @@ -21,9 +25,11 @@ variants: - running_vm: pre_state = running + domst_reason = restored - paused_vm: no verbose_opt, xml_opt, bypass_cache_opt pre_state = paused + domst_reason = migrating variants mode: - readonly: only running_vm.no_opt diff --git a/libvirt/tests/cfg/scalability/define_create_vm_with_more_vcpus.cfg b/libvirt/tests/cfg/scalability/define_create_vm_with_more_vcpus.cfg new file mode 100644 index 00000000000..25f5de09d82 --- /dev/null +++ b/libvirt/tests/cfg/scalability/define_create_vm_with_more_vcpus.cfg @@ -0,0 +1,28 @@ +- scalability.intel_iommu.define_create_vm_with_more_vcpus: + type = define_create_vm_with_more_vcpus + start_vm = "yes" + enable_guest_iommu = "yes" + feature_name = "ioapic" + func_supported_since_libvirt_ver = (10, 10, 0) + vm_attrs = {"vcpu": 384} + exp_iommu_dict = {"model": "intel", "driver": {"intremap": "on", "eim": "on"}} + + only q35 + variants: + - with_ioapic: + with_ioapic = "yes" + feature_attr = ["driver", "qemu"] + - without_ioapic: + variants: + - with_iommu: + variants: + - default: + only without_ioapic + iommu_dict = {"model": "intel"} + - with_intremap_on: + iommu_dict = {"model": "intel", "driver": {"intremap": "on"}} + - without_iommu: + variants: + - define_vm: + define_vm = "yes" + - create_vm: diff --git a/libvirt/tests/cfg/scsi/scsi_command_test_hostdev.cfg b/libvirt/tests/cfg/scsi/scsi_command_test_hostdev.cfg new file mode 100644 index 00000000000..0574c474ed6 --- /dev/null +++ b/libvirt/tests/cfg/scsi/scsi_command_test_hostdev.cfg @@ -0,0 +1,10 @@ +- scsi_device.scsi_command_test.with_hostdev: + type = scsi_command_test_hostdev + start_vm = no + variants: + - guest_multipath: + emulated_image = "emulated-iscsi" + second_target = "iqn.2024-11.com.virttest:emulated-iscsi.target-2" + mpath_conf_path = "/etc/multipath.conf" + pkg_list = "['device-mapper-multipath', 'python3-rtslib']" + hostdev_dict = {'type': 'scsi', 'source': {'untyped_address': {'target': '0', 'unit': '0', 'bus': '0'}, 'adapter_name': 'scsi_host%s'}, 'mode': 'subsystem', 'type_name': 'scsi', 'rawio': 'yes', 'sgio': 'filtered', 'managed': 'no'} diff --git a/libvirt/tests/cfg/scsi/scsi_controller_driver_plug_unplug.cfg b/libvirt/tests/cfg/scsi/scsi_controller_driver_plug_unplug.cfg new file mode 100644 index 00000000000..8eea456d46e --- /dev/null +++ b/libvirt/tests/cfg/scsi/scsi_controller_driver_plug_unplug.cfg @@ -0,0 +1,27 @@ +- scsi_controller.driver.plug_unplug: + type = scsi_controller_driver_plug_unplug + start_vm = no + take_regular_screendumps = no + controller_dict = {'type': 'scsi', 'model': 'virtio-scsi', 'index': '%s'} + no s390-virtio + variants driver_config: + - with_driver: + iothread_num = 1 + iothread_id = 1 + - without_driver: + variants contr_num: + - one_contr: + contr_index = [0] + - two_contrs: + only with_driver + contr_index = [0, 1] + variants scenarios: + - cold_first_hot_second: + - hotplug_same_index: + only two_contrs + same_index = 0 + err_msg = "target scsi:${same_index} already exists" + - hotplug_same_address: + only two_contrs + same_address = { "domain": '0x0000', 'funtion': '0x0', 'bus': '0x08', 'slot': '0x00'} + err_msg = "Attempted double use of PCI Address" diff --git a/libvirt/tests/cfg/scsi/scsi_disk_attributes.cfg b/libvirt/tests/cfg/scsi/scsi_disk_attributes.cfg new file mode 100644 index 00000000000..b5e66db8000 --- /dev/null +++ b/libvirt/tests/cfg/scsi/scsi_disk_attributes.cfg @@ -0,0 +1,13 @@ +- scsi_device.scsi_disk_attributes.rawio: + type = scsi_disk_attributes + start_vm = no + target_disk = "sdb" + disk_type = "block" + variants: + - rawio_yes: + rawio_value = "yes" + expected_xpaths = [{'element_attrs': [".//disk[@rawio='yes']"]}] + - rawio_no: + rawio_value = "no" + expected_xpaths = [{'element_attrs': [".//disk[@rawio='no']"]}] + disk_dict = {'target': {'dev': '${target_disk}', 'bus': 'scsi'}, 'driver': {'name': 'qemu', 'type': 'raw'}, 'device': 'lun', 'sgio': 'filtered', 'rawio': '${rawio_value}', 'type_name': 'block', 'source': {'attrs': {'dev': '%s'}}} diff --git a/libvirt/tests/cfg/libvirt_rng.cfg b/libvirt/tests/cfg/security/rng/libvirt_rng.cfg similarity index 86% rename from libvirt/tests/cfg/libvirt_rng.cfg rename to libvirt/tests/cfg/security/rng/libvirt_rng.cfg index 2e8b5165479..76a44c0ce4b 100644 --- a/libvirt/tests/cfg/libvirt_rng.cfg +++ b/libvirt/tests/cfg/security/rng/libvirt_rng.cfg @@ -7,7 +7,9 @@ set_virtio_current = yes # Devices that might be present though not configured via . # For example, devices that are provided by the CPU. - ignored_devices = s390-trng,trng,tpm-rng-0 + ignored_devices = s390-trng,trng,tpm-rng-0,smccc_trng + dd_throughput = "bs=512 count=10" + snap_options = " %s" variants: - hotplug_unplug: only backend_rdm.default, backend_tcp, backend_udp, backend_builtin @@ -15,6 +17,8 @@ variants: - positive: rng_random_source = "yes" + test_guest_rng_file = "yes" + guest_required_kernel = [5.14.0,) variants: - no_options: - persistent: @@ -59,10 +63,10 @@ driver_packed = "on" - invalid_address: address = "{ 'domain': '0x9999', 'bus': '0x00', 'slot': '0x00', 'function': '0x0'}" - expected_create_error = "Invalid PCI address" + expected_create_error = ".*Invalid PCI address.*" - invalid_model: rng_model = virtio-abc - expected_create_error = "RNG model" + expected_create_error = ".*(RNG model|model.*rng.*virtio-abc).*" - backend_udp: backend_model = "egd" backend_type = "udp" @@ -89,6 +93,8 @@ - rng_rate: test_qemu_cmd = "yes" test_guest = "yes" + aarch64: + dd_throughput = "bs=512 count=100" variants: - back_rdm: rng_rate = "{'bytes':'5000','period':'2000'}" @@ -103,15 +109,14 @@ rng_rate = "{'bytes':'5000','period':'2000'}" backend_model = "builtin" - rng_snapshot: - snapshot_name = "rng.s" + test_snapshot = "yes" variants: - snapshot_running: + snap_options = "%s --memspec " + mem_files = ["/var/lib/libvirt/images/avocado-memory.s1", "/var/lib/libvirt/images/avocado-memory.s2"] snapshot_vm_running = "yes" - test_snapshot = "yes" - snapshot_with_rng = "yes" - snapshot_shutoff: - test_snapshot = "yes" - snapshot_with_rng = "no" + snap_options = "%s --disk-only" variants: - back_rdm: backend_dev = "/dev/random" @@ -128,13 +133,13 @@ - back_udp: backend_model = "egd" backend_type = "udp" - backend_source = "{'mode':'bind','service':'1234'} {'mode':'connect','host':'1.2.3.4','service':'1234'}" + backend_source = "{'mode':'bind','service':'1024'} {'mode':'connect','host':'127.0.0.1','service':'1234'}" - multiple_rng: device_num = 3 backend_dev_0 = "/dev/random" backend_dev_1 = "/dev/random" backend_model_2 = "egd" backend_type_2 = "udp" - backend_source_2 = "{'mode':'connect','host':'1.2.3.4','service':'1234'}" + backend_source_2 = "{'mode':'connect','host':'127.0.0.1','service':'1234'}" test_qemu_cmd = "yes" test_guest = "yes" diff --git a/libvirt/tests/cfg/virtual_device/virtio_rng.cfg b/libvirt/tests/cfg/security/rng/virtio_rng.cfg similarity index 100% rename from libvirt/tests/cfg/virtual_device/virtio_rng.cfg rename to libvirt/tests/cfg/security/rng/virtio_rng.cfg diff --git a/libvirt/tests/cfg/security/virt_what_cvm.cfg b/libvirt/tests/cfg/security/virt_what_cvm.cfg new file mode 100644 index 00000000000..bf61a130b08 --- /dev/null +++ b/libvirt/tests/cfg/security/virt_what_cvm.cfg @@ -0,0 +1,9 @@ +- virt_what.cvm: + type = virt_what_cvm + start_vm = yes + variants: + - expected_value: + # The EXPECTED_VALUE depends on the VM. A normal VM would have "". + # man virt-what-cvm lists the available values for VM where + # confidentiality is enabled + expected_cvm = diff --git a/libvirt/tests/cfg/serial/serial_functional.cfg b/libvirt/tests/cfg/serial/serial_functional.cfg index 1e22c394d95..c2845dabcc4 100644 --- a/libvirt/tests/cfg/serial/serial_functional.cfg +++ b/libvirt/tests/cfg/serial/serial_functional.cfg @@ -48,6 +48,19 @@ no s390-virtio serial_dev_type = pty target_type = pci-serial + - type_pty_system_serial: + only aarch64 + serial_dev_type = pty + target_type = system-serial + - type_file_system_serial: + only aarch64 + func_supported_since_libvirt_ver = (10, 10, 0) + serial_dev_type = file + target_model = pl011 + serial_sources = path:/var/lib/libvirt/virt-test + hotplug_serial = "yes" + hotunplug_serial = "yes" + error_msg = "unsupported configuration: Cannot {} platform device" - type_spicevmc: serial_dev_type = spicevmc - type_spiceport: @@ -66,6 +79,11 @@ serial_dev_type = pty console_target_type = virtio second_serial_console = yes + - connect_to_console_no_serial_device: + serial_dev_type = pty + error_msg = ["cannot find character device","error: Cannot run interactive console without a controlling TTY"] + connect_to_console_without_serial_device = "yes" + func_supported_since_libvirt_ver = (10, 3, 0) - type_tls_server: serial_dev_type = tls serial_sources = mode:bind,host:${local_ip_address},service:5556,tls:yes diff --git a/libvirt/tests/cfg/serial/serial_pty_log.cfg b/libvirt/tests/cfg/serial/serial_pty_log.cfg index b0002048c8c..36c35f4c1fd 100644 --- a/libvirt/tests/cfg/serial/serial_pty_log.cfg +++ b/libvirt/tests/cfg/serial/serial_pty_log.cfg @@ -2,6 +2,7 @@ type = serial_pty_log start_vm = no remove_devices = "['serial','console']" + boot_prompt = 'localhost login,Login Prompts' variants: - file: serial_dev_type = pty @@ -11,11 +12,9 @@ aarch64: target_type = system-serial target_model = pl011 - boot_prompt = 'localhost login' s390x: target_type = sclp-serial target_model = sclpconsole - boot_prompt = 'localhost login' stdio_handler = 'file' - logd: serial_dev_type = pty @@ -25,9 +24,7 @@ aarch64: target_type = system-serial target_model = pl011 - boot_prompt = 'localhost login' s390x: target_type = sclp-serial target_model = sclpconsole - boot_prompt = 'localhost login' stdio_handler = 'logd' diff --git a/libvirt/tests/cfg/snapshot/check_delete_and_revert_snap_event_in_multiple_branch.cfg b/libvirt/tests/cfg/snapshot/check_delete_and_revert_snap_event_in_multiple_branch.cfg new file mode 100644 index 00000000000..f7c9b242d1e --- /dev/null +++ b/libvirt/tests/cfg/snapshot/check_delete_and_revert_snap_event_in_multiple_branch.cfg @@ -0,0 +1,14 @@ +- snapshot_event.multiple_branch: + type = check_delete_and_revert_snap_event_in_multiple_branch + start_vm = no + snap_names = ['s1', 's2', 's3', 's4', 's5'] + system_disk = "vda" + external_path = "/tmp/${system_disk}" + snap_options = "%s --memspec snapshot=external,file=/tmp/mem.%s --diskspec ${system_disk},snapshot=external,file=${external_path}.%s" + func_supported_since_libvirt_ver = (9, 10, 0) + variants case: + - del_and_revert: + del_event = ["block-job.*${external_path}.* completed", "block-job-2.*${system_disk} completed"] + extra_del_devent = ["block-job.*%s completed"] + revert_event1 = ["lifecycle.*Stopped Snapshot", "lifecycle.*Started Snapshot","lifecycle.*Resumed Snapshot", "lifecycle.*Defined Snapshot"] + revert_event2 = ["agent-lifecycle.*'disconnected' reason: 'domain started'", "agent-lifecycle.*state: 'connected' reason: 'channel event'"] diff --git a/libvirt/tests/cfg/snapshot/delete_disk_and_memory_snapshot.cfg b/libvirt/tests/cfg/snapshot/delete_disk_and_memory_snapshot.cfg new file mode 100644 index 00000000000..67feadf19e3 --- /dev/null +++ b/libvirt/tests/cfg/snapshot/delete_disk_and_memory_snapshot.cfg @@ -0,0 +1,16 @@ +- snapshot_delete.disk_and_memory_snap: + type = delete_disk_and_memory_snapshot + start_vm = no + func_supported_since_libvirt_ver = (9, 10, 0) + snap_names = ["s1", "s2"] + file_path = "/mnt/data.txt" + target_disk = "vdb" + snapshot_disk_list = "[{'disk_name': 'vda', 'disk_snapshot': 'no'}, {'disk_name': '${target_disk}', 'disk_snapshot': 'external', 'source':{'attrs': {'file': '%s'}}}]" + snapshot_dict = {'description': 'Snapshot test', 'snap_name': '%s', 'mem_snap_type': 'external', 'mem_file': '%s'} + variants disk: + - qcow2_format: + disk_type = "file" + disk_dict = {"type_name":"${disk_type}", "target":{"dev": "${target_disk}", "bus": "virtio"}, "driver": {"name": "qemu", "type":"qcow2"}} + variants vm_status: + - vm_running: + - vm_paused: diff --git a/libvirt/tests/cfg/snapshot/delete_disk_only_snapshot.cfg b/libvirt/tests/cfg/snapshot/delete_disk_only_snapshot.cfg new file mode 100644 index 00000000000..00dbd60fc53 --- /dev/null +++ b/libvirt/tests/cfg/snapshot/delete_disk_only_snapshot.cfg @@ -0,0 +1,17 @@ +- snapshot_delete.disk_only_snap: + type = delete_disk_only_snapshot + func_supported_since_libvirt_ver = (9, 10, 0) + start_vm = no + snap_names = ['s1', 's2'] + snap_options = " --disk-only" + disk1 = 'vda' + disk2 = 'vdb' + file_name = '/tmp/test.txt' + mem_path = "/tmp/mem." + disk_type = 'file' + disk_driver = {'driver': {'name': 'qemu', 'type': 'qcow2'}} + disk_target = {'target': {'dev': '${disk2}', 'bus': 'virtio'}} + disk_dict = {"type_name": '${disk_type}', 'device': 'disk', **${disk_target}, **${disk_driver}} + snapshot_disk_list = "[{'disk_name': 'vda', 'disk_snapshot': 'no'}, {'disk_name': '${disk2}', 'disk_snapshot': 'external', 'source':{'attrs': {'file': '%s'}}}]" + snapshot_dict = {'description': 'Snapshot test', 'snap_name': '%s'} + diff --git a/libvirt/tests/cfg/snapshot/delete_external_after_reverting_internal.cfg b/libvirt/tests/cfg/snapshot/delete_external_after_reverting_internal.cfg new file mode 100644 index 00000000000..ea0f1fce2c2 --- /dev/null +++ b/libvirt/tests/cfg/snapshot/delete_external_after_reverting_internal.cfg @@ -0,0 +1,19 @@ +- snapshot_delete.after_reverting_internal: + type = delete_external_after_reverting_internal + start_vm = no + internal_snap_name = s1 + internal_snap_option = "${internal_snap_name}" + external_snap_name = s2 + external_snap_option = "${external_snap_name} --memspec file=%s,snapshot=external" + disk_xpath = [{'element_attrs':[".//devices/disk/source[@file='%s']"]}, {'element_attrs':[".//devices/disk/backingStore[@type='file']"]}, {'element_attrs':[".//devices/disk/backingStore/source[@file='%s']"]}] + variants: + - seabios: + only x86_64 + firmware_type = "seabios" + - ovmf: + only aarch64 + func_supported_since_libvirt_ver = (10, 10, 0) + firmware_type = "ovmf" + - no_firmware: + only s390-virtio + diff --git a/libvirt/tests/cfg/snapshot/delete_external_snap_with_references.cfg b/libvirt/tests/cfg/snapshot/delete_external_snap_with_references.cfg new file mode 100644 index 00000000000..771117f1121 --- /dev/null +++ b/libvirt/tests/cfg/snapshot/delete_external_snap_with_references.cfg @@ -0,0 +1,21 @@ +- snapshot_delete.multiple_children: + type = delete_external_snap_with_references + start_vm = no + snap_options = "%s --memspec snapshot=external,file=/tmp/mem.%s --diskspec vda,snapshot=external,file=/tmp/vda.%s" + func_supported_since_libvirt_ver = (9, 10, 0) + variants case: + - del_parent_snap: + del_snap = 's1' + error_msg = "unsupported configuration: deletion of external disk snapshot with multiple children snapshots not supported" + - del_current_branch: + del_index = [2, 1, 0] + error_msg = "unsupported configuration: deletion of active external snapshot that is not a leaf snapshot is not supported" + - del_non_current_branch: + func_supported_since_libvirt_ver = (10, 0, 0) + error_msg = "deletion of non-leaf external snapshot that is not in active chain is not supported" + variants: + - tail_to_head: + del_index = [4, 3, 0] + - head_to_tail: + del_index = [0, 3, 4] + diff --git a/libvirt/tests/cfg/snapshot/delete_snapshot_after_disk_attached.cfg b/libvirt/tests/cfg/snapshot/delete_snapshot_after_disk_attached.cfg new file mode 100644 index 00000000000..2fa03e263bf --- /dev/null +++ b/libvirt/tests/cfg/snapshot/delete_snapshot_after_disk_attached.cfg @@ -0,0 +1,15 @@ +- snapshot_delete.disk_attached: + type = delete_snapshot_after_disk_attached + func_supported_since_libvirt_ver = (9, 10, 0) + start_vm = yes + snap_names = ['s1', 's2', 's3','s4'] + disk1 = 'vda' + disk1_snap_option = " %s --disk-only" + disk2 = 'vdb' + mem_path = "/tmp/mem." + snap_deleting_ongoing_tag = "" + disk2_snap_option = "%s --memspec ${mem_path}%s,snapshot=external --diskspec ${disk1},snapshot=external ${disk2},snapshot=external" + disk_type = 'file' + disk_driver = {'driver': {'name': 'qemu', 'type': 'qcow2'}} + disk_target = {'target': {'dev': '${disk2}', 'bus': 'virtio'}} + disk_dict = {"type_name": '${disk_type}', 'device': 'disk', **${disk_target}, **${disk_driver}} diff --git a/libvirt/tests/cfg/snapshot/delete_snapshot_metadata.cfg b/libvirt/tests/cfg/snapshot/delete_snapshot_metadata.cfg new file mode 100644 index 00000000000..602037d0847 --- /dev/null +++ b/libvirt/tests/cfg/snapshot/delete_snapshot_metadata.cfg @@ -0,0 +1,19 @@ +- snapshot_delete.metadata: + type = delete_snapshot_metadata + start_vm = no + snap_name = ['s1', 's2', 's3'] + func_supported_since_libvirt_ver = (9, 10, 0) + del_option = " --metadata" + variants disk_format: + - type_qcow2: + format = "qcow2" + disk_type = "file" + original_disk = 'vda' + new_disk = "vdb" + disk_driver = {'driver': {'name': 'qemu', 'type': '${format}'}} + disk_target = {'target': {'dev': '${new_disk}', 'bus': 'virtio'}} + disk_dict = {"type_name": '${disk_type}', 'device': 'disk', **${disk_target}, **${disk_driver}} + mem_path = "/tmp/mem.s" + disk_path = "/tmp/vdb.s" + snap_options = "%s --diskspec vda,snapshot=no --diskspec vdb,snapshot=external,file=${disk_path}%d --memspec snapshot=external,file=${mem_path}%d" + diff --git a/libvirt/tests/cfg/snapshot/memory_snapshot_delete.cfg b/libvirt/tests/cfg/snapshot/memory_snapshot_delete.cfg index 4e4f45b0fb8..f31a376fc95 100644 --- a/libvirt/tests/cfg/snapshot/memory_snapshot_delete.cfg +++ b/libvirt/tests/cfg/snapshot/memory_snapshot_delete.cfg @@ -4,7 +4,7 @@ start_vm = no snapshot_disk_list = "[{'disk_name': 'vda', 'disk_snapshot': 'no'}, {'disk_name': 'vdb', 'disk_snapshot': 'no'}]" snapshot_dict = {'description': 'Snapshot test', 'snap_name': '%s', 'mem_snap_type': 'external', 'mem_file': '%s'} - func_supported_since_libvirt_ver = (9, 0, 0) + func_supported_since_libvirt_ver = (9, 10, 0) variants disk_format: - type_qcow2: disk_driver = {'driver': {'name': 'qemu', 'type': 'qcow2'}} diff --git a/libvirt/tests/cfg/snapshot/revert_disk_external_snap.cfg b/libvirt/tests/cfg/snapshot/revert_disk_external_snap.cfg new file mode 100644 index 00000000000..ee065f7ee23 --- /dev/null +++ b/libvirt/tests/cfg/snapshot/revert_disk_external_snap.cfg @@ -0,0 +1,20 @@ +- snapshot_revert.disk_external_snap: + type = revert_disk_external_snap + start_vm = no + snap_names = ['s1', 's2', 's3'] + file_list = ["/mnt/s1", "/mnt/s2", "/mnt/s3"] + func_supported_since_libvirt_ver = (9, 10, 0) + variants: + - with_datastore: + with_data_file = "yes" + disk_target = "vdb" + disk_type = "file" + disk_dict = {"type_name":"${disk_type}", "target":{"dev":"${disk_target}", "bus":"virtio"}, "driver": {"name":"qemu", "type":"qcow2"}} + func_supported_since_libvirt_ver = (10, 10, 0) + data_file_option = " -o data_file=%s" + - without_datastore: + variants snap_type: + - disk_only: + snap_options = " %s --disk-only %s" + - disk_and_memory: + snap_options = "%s --memspec snapshot=external,file=/tmp/mem.%s" diff --git a/libvirt/tests/cfg/snapshot/revert_memory_only_snap.cfg b/libvirt/tests/cfg/snapshot/revert_memory_only_snap.cfg new file mode 100644 index 00000000000..0de26981c8a --- /dev/null +++ b/libvirt/tests/cfg/snapshot/revert_memory_only_snap.cfg @@ -0,0 +1,8 @@ +- snapshot_revert.memory_only_snap: + type = revert_memory_only_snap + start_vm = no + snap_names = ['s1', 's2', 's3'] + target_disk = 'vda' + disk_type = 'file' + snap_options = "%s --memspec snapshot=external,file=/tmp/mem.%s --diskspec ${target_disk},snapshot=no" + func_supported_since_libvirt_ver = (9, 10, 0) diff --git a/libvirt/tests/cfg/snapshot/revert_snap_based_on_state.cfg b/libvirt/tests/cfg/snapshot/revert_snap_based_on_state.cfg new file mode 100644 index 00000000000..aabdc2c963b --- /dev/null +++ b/libvirt/tests/cfg/snapshot/revert_snap_based_on_state.cfg @@ -0,0 +1,19 @@ +- snapshot_revert.snap_and_domain_state: + type = revert_snap_based_on_state + start_vm = no + snap_name = 's1' + func_supported_since_libvirt_ver = (9, 10, 0) + variants: + - snap_running: + snap_state = "running" + expected_state = "${snap_state}" + snap_options = " %s --memspec snapshot=external,file=/tmp/mem.s1 --diskspec vda,snapshot=external,file=/tmp/vda.s1" + - snap_shutoff: + snap_state = "shutoff" + expected_state = "shut off" + snap_options = " %s --diskspec vda,snapshot=external,file=/tmp/vda.s1" + variants: + - vm_running: + vm_state = "running" + - vm_shutoff: + vm_state = "shut off" diff --git a/libvirt/tests/cfg/snapshot/revert_snap_for_guest_with_genid.cfg b/libvirt/tests/cfg/snapshot/revert_snap_for_guest_with_genid.cfg new file mode 100644 index 00000000000..0091b1c9f96 --- /dev/null +++ b/libvirt/tests/cfg/snapshot/revert_snap_for_guest_with_genid.cfg @@ -0,0 +1,8 @@ +- snapshot_revert.with_genid: + no s390-virtio,aarch64 + type = revert_snap_for_guest_with_genid + start_vm = no + func_supported_since_libvirt_ver = (9, 10, 0) + snap_names = ['s1', 's2'] + snap_options = "%s --memspec snapshot=external,file=/tmp/mem.%s --diskspec vda,snapshot=external,file=/tmp/vda.%s" + diff --git a/libvirt/tests/cfg/snapshot/revert_snap_with_flags.cfg b/libvirt/tests/cfg/snapshot/revert_snap_with_flags.cfg new file mode 100644 index 00000000000..367823378b0 --- /dev/null +++ b/libvirt/tests/cfg/snapshot/revert_snap_with_flags.cfg @@ -0,0 +1,16 @@ +- snapshot_revert.with_flags: + type = revert_snap_with_flags + start_vm = no + snap_names = ['s1', 's2'] + target_disk = 'vda' + disk_type = 'file' + vars_path = "/var/lib/libvirt/qemu/nvram/${main_vm}_VARS.fd" + aarch64: + vars_path = "/var/lib/libvirt/qemu/nvram/${main_vm}_VARS.qcow2" + snap1_options = "%s --diskspec vda,snapshot=external,file=/tmp/vda.%s" + snap2_options = "%s --memspec snapshot=external,file=/tmp/mem.%s --diskspec vda,snapshot=external,file=/tmp/vda.%s" + flags = [" --current --paused"," --running --reset-nvram", " --force"] + func_supported_since_libvirt_ver = (9, 10, 0) + s390-virtio: + vars_path = + flags = [" --current --paused"," --running", " --force"] diff --git a/libvirt/tests/cfg/snapshot/revert_snapshot_after_xml_updated.cfg b/libvirt/tests/cfg/snapshot/revert_snapshot_after_xml_updated.cfg new file mode 100644 index 00000000000..28bac6d4e01 --- /dev/null +++ b/libvirt/tests/cfg/snapshot/revert_snapshot_after_xml_updated.cfg @@ -0,0 +1,26 @@ +- snapshot_revert.xml_updated: + type = revert_snapshot_after_xml_updated + start_vm = no + snap_names = ["s1", "s2"] + file_list = ["/mnt/s1", "/mnt/s2"] + snap_options = "%s --memspec snapshot=external,file=/tmp/mem.%s --diskspec vda,snapshot=external,file=/tmp/vda.%s" + func_supported_since_libvirt_ver = (9, 10, 0) + variants updated_type: + - hotplug_disk: + disk_type = "file" + system_disk = "vda" + new_disk = "vdb" + disk_dict = {"type_name":"${disk_type}", "target":{"dev": "${new_disk}", "bus": "virtio"}, "driver": {"name": "qemu", "type":"qcow2"}} + system_disk_pattern ="${system_disk}\s+.*\d{2,}\s*" + new_disk_pattern ="${new_disk}\s+.*\d{2,}\s*" + - hotplug_vcpus: + vm_attrs = {"vcpu":4, "vcpus": {"vcpu": [{"id":"0", "enabled":"yes", "hotpluggable":"no"}, {"id":"1", "enabled":"no", "hotpluggable":"yes"},{"id":"2", "enabled":"no", "hotpluggable":"yes"}, {"id":"3", "enabled":"no", "hotpluggable":"yes"}]}} + vcpus_ele = "" + set_cpu = 1 + original_vcpu = {"enabled":'no', 'hotpluggable':'yes'} + new_vcpu = {"enabled":'yes', 'hotpluggable':'yes'} + - blkiotune: + mode_cmd = "modprobe scsi_debug dev_size_mb=500" + weight = "400" + setting_type = "device-write-bytes-sec" + blkiotune_cmd = "${setting_type} %s,${weight}" diff --git a/libvirt/tests/cfg/snapshot/snapshot_list_with_options.cfg b/libvirt/tests/cfg/snapshot/snapshot_list_with_options.cfg new file mode 100644 index 00000000000..079241a0075 --- /dev/null +++ b/libvirt/tests/cfg/snapshot/snapshot_list_with_options.cfg @@ -0,0 +1,38 @@ +- snapshot_list.with_options: + type = snapshot_list_with_options + start_vm = "no" + snap_names = ['s1', 's2', 's3', 's4'] + snap_options = "%s --memspec snapshot=external,file=/tmp/mem.%s" + variants: + - roots: + list_options = "--roots" + expected_list = ['s1'] + - leaves: + list_options = "--leaves" + expected_list = ['s4'] + - no_leaves: + option = "--no-leaves" + variants: + - with_external: + list_options = "${option} --external" + expected_list = ['s1', 's2'] + - with_inactive: + list_options = "${option} --inactive" + expected_list = ['s1'] + - with_active: + list_options = "${option} --active" + expected_list = ['s3'] + - with_disk_only: + list_options = "${option} --disk-only" + expected_list = ['s2'] + - from_and_descendants: + list_options = "--from s2 --descendants" + expected_list = ['s3', 's4'] + - topological: + list_options = "--topological" + expected_list = ['s1', 's2', 's3', 's4'] + - parent: + func_supported_since_libvirt_ver = (10, 3, 0) + special_check = "yes" + list_options = "--name --parent" + expected_dict = {'s1':'', 's2':'s1', 's3':'s2', 's4':'s3'} diff --git a/libvirt/tests/cfg/sriov/capabilities/sriov_capabilities_iommu_support.cfg b/libvirt/tests/cfg/sriov/capabilities/sriov_capabilities_iommu_support.cfg index fd69ca40cab..0fb5eae16c3 100644 --- a/libvirt/tests/cfg/sriov/capabilities/sriov_capabilities_iommu_support.cfg +++ b/libvirt/tests/cfg/sriov/capabilities/sriov_capabilities_iommu_support.cfg @@ -1,4 +1,4 @@ - sriov.capabilities.iommu_support: type = sriov_capabilities_iommu_support start_vm = "no" - only x86_64 + only x86_64, aarch64 diff --git a/libvirt/tests/cfg/sriov/locked_memory_check/sriov_with_hotplug_memory.cfg b/libvirt/tests/cfg/sriov/locked_memory_check/sriov_with_hotplug_memory.cfg new file mode 100644 index 00000000000..053ff627211 --- /dev/null +++ b/libvirt/tests/cfg/sriov/locked_memory_check/sriov_with_hotplug_memory.cfg @@ -0,0 +1,25 @@ +- sriov.locked_memory_check.hotplug_memory: + type = sriov_with_hotplug_memory + start_vm = "yes" + mem_dict1 = {'mem_model': 'dimm', 'target': {'size': 1, 'size_unit': 'G', 'node': 0}, 'alias': {'name': 'ua-d9cbe3cc-40fe-4aed-b245-874c534e8362'}} + mem_dict2 = {'mem_model': 'dimm', 'target': {'size': 1, 'size_unit': 'G', 'node': 0}} + vm_attrs = {'max_mem_rt': 6291456, 'max_mem_rt_slots': 32, 'max_mem_rt_unit': 'K', 'vcpu': 8, 'cpu': {'numa_cell': [{'id': '0', 'cpus': '0-3', 'memory': '%s', 'unit': 'K'}, {'id': '1', 'cpus': '4-7', 'memory': '%s', 'unit': 'K'}]}} + kernel_extra_params_add = "memhp_default_state=online_movable" + only x86_64, aarch64 + variants dev_type: + - hostdev_interface: + iface_dict = {'managed': 'yes', 'type_name': 'hostdev', 'hostdev_address': {'type_name': 'pci', 'attrs': vf_pci_addr}, 'alias': {'name': 'ua-89cbe690-6c6c-4f2f-adac-5826fe52ea74'}} + - hostdev_device: + variants dev_source: + - vf_address: + hostdev_dict = {'alias': {'name': 'ua-1bcbabff-f022-4d4f-ae8c-13f2d3a07906'}, 'mode': 'subsystem', 'type': 'pci', 'source': {'untyped_address': vf_pci_addr}, 'managed': 'yes'} + - pf_address: + hostdev_dict = {'alias': {'name': 'ua-1bcbabff-f022-4d4f-ae8c-13f2d3a07906'}, 'mode': 'subsystem', 'type': 'pci', 'source': {'untyped_address': pf_pci_addr}, 'managed': 'yes'} + variants: + - start_vm_with_hostdev: + - start_vm_without_hostdev: + without_hostdev = "yes" + variants mem_set: + - without_hardlimit: + - with_hardlimit: + vm_attrs = {**${vm_attrs}, 'memtune': {'hard_limit': 10485760, 'hard_limit_unit': 'K'}} diff --git a/libvirt/tests/cfg/sriov/network/sriov_check_net_info_by_network_lifecycle_cmds.cfg b/libvirt/tests/cfg/sriov/network/sriov_check_net_info_by_network_lifecycle_cmds.cfg index 551d4f99b5b..c7b0df841d4 100644 --- a/libvirt/tests/cfg/sriov/network/sriov_check_net_info_by_network_lifecycle_cmds.cfg +++ b/libvirt/tests/cfg/sriov/network/sriov_check_net_info_by_network_lifecycle_cmds.cfg @@ -1,6 +1,6 @@ - sriov.network.check_net_info_by_network_lifecycle_cmds: type = sriov_check_net_info_by_network_lifecycle_cmds - only x86_64 + only x86_64, aarch64 start_vm = "no" network_dict = {'forward': {'mode': 'hostdev', 'managed': 'yes'}, 'name': 'hostnet', 'vf_list': [{'type_name': 'pci', 'attrs': vf_pci_addr}], 'uuid': 'e6ddbb96-5be5-494d-92f0-f7473e185876'} network_update_dict = {'portgroups': [{'name': 'dontpanic'}]} diff --git a/libvirt/tests/cfg/sriov/network/sriov_check_network_connections.cfg b/libvirt/tests/cfg/sriov/network/sriov_check_network_connections.cfg new file mode 100644 index 00000000000..d38f5ca79b0 --- /dev/null +++ b/libvirt/tests/cfg/sriov/network/sriov_check_network_connections.cfg @@ -0,0 +1,8 @@ +- sriov.network.check_connections: + type = sriov_check_network_connections + only x86_64, aarch64 + + start_vm = "no" + network_dict = {'forward': {'mode': 'hostdev', 'managed': 'yes'}, 'name': 'hostdev_net', 'pf': {'dev': pf_name}} + iface_dict = {'type_name': 'network', 'source': {'network': 'hostdev_net'}} + iface_nums = 2 diff --git a/libvirt/tests/cfg/sriov/network/sriov_define_or_start_network_with_pf_addr.cfg b/libvirt/tests/cfg/sriov/network/sriov_define_or_start_network_with_pf_addr.cfg index 8c6de9e0646..449d547fb71 100644 --- a/libvirt/tests/cfg/sriov/network/sriov_define_or_start_network_with_pf_addr.cfg +++ b/libvirt/tests/cfg/sriov/network/sriov_define_or_start_network_with_pf_addr.cfg @@ -1,6 +1,6 @@ - sriov.network.define_or_start_network_with_pf_addr: type = sriov_define_or_start_network_with_pf_addr - only x86_64 + only x86_64, aarch64 start_vm = "no" - err_msg = "SR-IOV Virtual Function" + err_msg = "SR-IOV Virtual Function" network_dict = {'forward': {'mode': 'hostdev', 'managed': 'yes'}, 'name': 'hostnet', 'vf_list': [{'type_name': 'pci', 'attrs': pf_pci_addr}], 'uuid': 'e6ddbb96-5be5-494d-92f0-f7473e185876'} diff --git a/libvirt/tests/cfg/sriov/nodedev/sriov_nodedev_non_driver.cfg b/libvirt/tests/cfg/sriov/nodedev/sriov_nodedev_non_driver.cfg index 736a1da56fb..4ec4df7c5da 100644 --- a/libvirt/tests/cfg/sriov/nodedev/sriov_nodedev_non_driver.cfg +++ b/libvirt/tests/cfg/sriov/nodedev/sriov_nodedev_non_driver.cfg @@ -1,4 +1,4 @@ - sriov.nodedev.non_driver: - type = sriov_nodedev_non_driver + type = sriov_nodedev_non_driver start_vm = "no" - only x86_64 + only x86_64, aarch64 diff --git a/libvirt/tests/cfg/sriov/nodedev/sriov_nodedev_reattach_detach.cfg b/libvirt/tests/cfg/sriov/nodedev/sriov_nodedev_reattach_detach.cfg index 06527657aea..81b62c9571f 100644 --- a/libvirt/tests/cfg/sriov/nodedev/sriov_nodedev_reattach_detach.cfg +++ b/libvirt/tests/cfg/sriov/nodedev/sriov_nodedev_reattach_detach.cfg @@ -1,7 +1,7 @@ - sriov.nodedev.nodedev_reattach_detach: type = sriov_nodedev_reattach_detach start_vm = "no" - only x86_64 + only x86_64, aarch64 variants dev_name: - vf: - pf: diff --git a/libvirt/tests/cfg/sriov/nodedev/sriov_reattach_detach_nodedev_in_use.cfg b/libvirt/tests/cfg/sriov/nodedev/sriov_reattach_detach_nodedev_in_use.cfg index 191cfdb2ac8..b84152fc9d9 100644 --- a/libvirt/tests/cfg/sriov/nodedev/sriov_reattach_detach_nodedev_in_use.cfg +++ b/libvirt/tests/cfg/sriov/nodedev/sriov_reattach_detach_nodedev_in_use.cfg @@ -2,7 +2,7 @@ type = sriov_reattach_detach_nodedev_in_use start_vm = "no" err_msg = "PCI device.* is in use by driver" - only x86_64 + only x86_64, aarch64 variants dev_type: - hostdev_interface: diff --git a/libvirt/tests/cfg/sriov/plug_unplug/sriov_attach_detach_device.cfg b/libvirt/tests/cfg/sriov/plug_unplug/sriov_attach_detach_device.cfg index 36475dcdcb7..58edefb2a44 100644 --- a/libvirt/tests/cfg/sriov/plug_unplug/sriov_attach_detach_device.cfg +++ b/libvirt/tests/cfg/sriov/plug_unplug/sriov_attach_detach_device.cfg @@ -2,7 +2,7 @@ type = sriov_attach_detach_device start_vm = "no" - only x86_64 + only x86_64, aarch64 variants dev_type: - hostdev_interface: variants dev_source: diff --git a/libvirt/tests/cfg/sriov/plug_unplug/sriov_attach_detach_device_after_restarting_service.cfg b/libvirt/tests/cfg/sriov/plug_unplug/sriov_attach_detach_device_after_restarting_service.cfg index 3335269c33d..f094be79fe2 100644 --- a/libvirt/tests/cfg/sriov/plug_unplug/sriov_attach_detach_device_after_restarting_service.cfg +++ b/libvirt/tests/cfg/sriov/plug_unplug/sriov_attach_detach_device_after_restarting_service.cfg @@ -4,7 +4,7 @@ network_dict = {'forward': {'mode': 'hostdev', 'managed': 'yes'}, 'name': 'hostnet', 'vf_list': [{'type_name': 'pci', 'attrs': vf_pci_addr}, {'type_name': 'pci', 'attrs': vf_pci_addr2}], 'uuid': 'e6ddbb96-5be5-494d-92f0-f7473e185876'} pre_iface_dict = {'type_name': 'network', 'source': {'network': 'hostnet'}} - only x86_64 + only x86_64, aarch64 variants dev_type: - hostdev_interface: iface_dict = {'managed': 'yes', 'type_name': 'hostdev', 'hostdev_address': {'type_name': 'pci', 'attrs': vf_pci_addr2}, 'driver': {'driver_attr': {'name': 'vfio'}}, 'alias': {'name': 'ua-89cbe690-6c6c-4f2f-adac-5826fe52ea74'}, 'mac_address': mac_addr} diff --git a/libvirt/tests/cfg/sriov/plug_unplug/sriov_attach_detach_device_special_situations.cfg b/libvirt/tests/cfg/sriov/plug_unplug/sriov_attach_detach_device_special_situations.cfg index 26d5b369fcf..b5197768cca 100644 --- a/libvirt/tests/cfg/sriov/plug_unplug/sriov_attach_detach_device_special_situations.cfg +++ b/libvirt/tests/cfg/sriov/plug_unplug/sriov_attach_detach_device_special_situations.cfg @@ -2,7 +2,7 @@ type = sriov_attach_detach_device_special_situations start_vm = "no" - only x86_64 + only x86_64, aarch64 variants dev_type: - hostdev_interface: variants test_scenario: diff --git a/libvirt/tests/cfg/sriov/plug_unplug/sriov_attach_detach_device_vfio_variant_driver.cfg b/libvirt/tests/cfg/sriov/plug_unplug/sriov_attach_detach_device_vfio_variant_driver.cfg new file mode 100644 index 00000000000..e64afe3483e --- /dev/null +++ b/libvirt/tests/cfg/sriov/plug_unplug/sriov_attach_detach_device_vfio_variant_driver.cfg @@ -0,0 +1,24 @@ +- sriov.plug_unplug.vfio_variant_driver: + type = sriov_attach_detach_device_vfio_variant_driver + start_vm = "no" + expr_driver = "mlx5_vfio_pci" + ping_dest = "www.redhat.com" + + only x86_64, aarch64 + variants: + - mlx5_vfio: + driver_dict = {'driver': {'driver_attr': {'name': 'vfio', 'model': 'mlx5_vfio_pci'}}} + - vfio_vfio: + driver_dict = {'driver': {'driver_attr': {'name': 'vfio', 'model': 'vfio_pci'}}} + - @default: + driver_dict = {} + variants dev_type: + - hostdev_interface: + iface_dict = {'type_name': 'hostdev', 'hostdev_address': {'type_name': 'pci', 'attrs': vf_pci_addr}, 'mac_address': mac_addr, 'managed': 'yes'} + - hostdev_device: + hostdev_dict = {'mode': 'subsystem', 'type': 'pci', 'source': {'untyped_address': vf_pci_addr}, 'managed': 'yes'} + variants: + - single_iface: + iface_number = 1 + - multiple_ifaces: + iface_number = 4 diff --git a/libvirt/tests/cfg/sriov/plug_unplug/sriov_attach_detach_device_with_flags.cfg b/libvirt/tests/cfg/sriov/plug_unplug/sriov_attach_detach_device_with_flags.cfg index 2076fca786e..d0365fc7488 100644 --- a/libvirt/tests/cfg/sriov/plug_unplug/sriov_attach_detach_device_with_flags.cfg +++ b/libvirt/tests/cfg/sriov/plug_unplug/sriov_attach_detach_device_with_flags.cfg @@ -1,6 +1,6 @@ - sriov.plug_unplug.attach_detach_device_with_flags: type = sriov_attach_detach_device_with_flags - only x86_64 + only x86_64, aarch64 variants: - offline_domain: diff --git a/libvirt/tests/cfg/sriov/plug_unplug/sriov_attach_detach_device_with_unsupported_settings.cfg b/libvirt/tests/cfg/sriov/plug_unplug/sriov_attach_detach_device_with_unsupported_settings.cfg index 20c45312784..5fe79f9e5a3 100644 --- a/libvirt/tests/cfg/sriov/plug_unplug/sriov_attach_detach_device_with_unsupported_settings.cfg +++ b/libvirt/tests/cfg/sriov/plug_unplug/sriov_attach_detach_device_with_unsupported_settings.cfg @@ -2,7 +2,7 @@ type = sriov_attach_detach_device_with_unsupported_settings start_vm = "no" - only x86_64 + only x86_64, aarch64 variants dev_type: - hostdev_interface: variants test_scenario: diff --git a/libvirt/tests/cfg/sriov/plug_unplug/sriov_attach_detach_interface.cfg b/libvirt/tests/cfg/sriov/plug_unplug/sriov_attach_detach_interface.cfg index 40fa3567657..280c1bb9a75 100644 --- a/libvirt/tests/cfg/sriov/plug_unplug/sriov_attach_detach_interface.cfg +++ b/libvirt/tests/cfg/sriov/plug_unplug/sriov_attach_detach_interface.cfg @@ -1,7 +1,7 @@ - sriov.plug_unplug.attach_detach_interface: type = sriov_attach_detach_interface start_vm = "no" - only x86_64 + only x86_64, aarch64 variants: - with_managed: diff --git a/libvirt/tests/cfg/sriov/plug_unplug/sriov_attach_detach_interface_check_connections.cfg b/libvirt/tests/cfg/sriov/plug_unplug/sriov_attach_detach_interface_check_connections.cfg index 7ab29341d72..dee2d44bf0b 100644 --- a/libvirt/tests/cfg/sriov/plug_unplug/sriov_attach_detach_interface_check_connections.cfg +++ b/libvirt/tests/cfg/sriov/plug_unplug/sriov_attach_detach_interface_check_connections.cfg @@ -1,6 +1,6 @@ - sriov.plug_unplug.attach_detach_interface_check_connections: type = sriov_attach_detach_interface_check_connections - only x86_64 + only x86_64, aarch64 start_vm = "no" vf_no = 4 diff --git a/libvirt/tests/cfg/sriov/plug_unplug/sriov_attach_detach_interface_from_network.cfg b/libvirt/tests/cfg/sriov/plug_unplug/sriov_attach_detach_interface_from_network.cfg index 518cad3d870..229b64f696a 100644 --- a/libvirt/tests/cfg/sriov/plug_unplug/sriov_attach_detach_interface_from_network.cfg +++ b/libvirt/tests/cfg/sriov/plug_unplug/sriov_attach_detach_interface_from_network.cfg @@ -2,4 +2,4 @@ type = sriov_attach_detach_interface_from_network start_vm = "no" network_dict = {'forward': {'mode': 'hostdev', 'managed': 'yes'}, 'name': 'hostdev_net', 'vf_list': [{'type_name': 'pci', 'attrs': vf_pci_addr}]} - only x86_64 + only x86_64, aarch64 diff --git a/libvirt/tests/cfg/sriov/plug_unplug/sriov_attach_detach_interface_special_situations.cfg b/libvirt/tests/cfg/sriov/plug_unplug/sriov_attach_detach_interface_special_situations.cfg index b9769092801..3c2efa9c472 100644 --- a/libvirt/tests/cfg/sriov/plug_unplug/sriov_attach_detach_interface_special_situations.cfg +++ b/libvirt/tests/cfg/sriov/plug_unplug/sriov_attach_detach_interface_special_situations.cfg @@ -1,7 +1,7 @@ - sriov.plug_unplug.attach_detach_interface_special_situations: type = sriov_attach_detach_interface_special_situations start_vm = "no" - only x86_64 + only x86_64, aarch64 attach_opt = "--managed" variants test_scenario: diff --git a/libvirt/tests/cfg/sriov/plug_unplug/sriov_attach_detach_interface_with_flags.cfg b/libvirt/tests/cfg/sriov/plug_unplug/sriov_attach_detach_interface_with_flags.cfg index fdec6a76da0..f8e07702bfa 100644 --- a/libvirt/tests/cfg/sriov/plug_unplug/sriov_attach_detach_interface_with_flags.cfg +++ b/libvirt/tests/cfg/sriov/plug_unplug/sriov_attach_detach_interface_with_flags.cfg @@ -1,6 +1,6 @@ - sriov.plug_unplug.attach_detach_interface_with_flags: type = sriov_attach_detach_interface_with_flags - only x86_64 + only x86_64, aarch64 variants: - offline_domain: diff --git a/libvirt/tests/cfg/sriov/plug_unplug/sriov_attach_interface_to_vm_with_vf.cfg b/libvirt/tests/cfg/sriov/plug_unplug/sriov_attach_interface_to_vm_with_vf.cfg index ac4e9504174..308ba9f837b 100644 --- a/libvirt/tests/cfg/sriov/plug_unplug/sriov_attach_interface_to_vm_with_vf.cfg +++ b/libvirt/tests/cfg/sriov/plug_unplug/sriov_attach_interface_to_vm_with_vf.cfg @@ -3,4 +3,4 @@ start_vm = "no" network_dict = {'forward': {'mode': 'hostdev', 'managed': 'yes'}, 'name': 'hostnet', 'vf_list': [{'type_name': 'pci', 'attrs': vf_pci_addr}, {'type_name': 'pci', 'attrs': vf_pci_addr2}]} pre_iface_dict = {'type_name': 'network', 'source': {'network': 'hostnet'}} - only x86_64 + only x86_64, aarch64 diff --git a/libvirt/tests/cfg/sriov/plug_unplug/sriov_attach_released_hostdev.cfg b/libvirt/tests/cfg/sriov/plug_unplug/sriov_attach_released_hostdev.cfg index 5d724125b07..2ed26edec73 100644 --- a/libvirt/tests/cfg/sriov/plug_unplug/sriov_attach_released_hostdev.cfg +++ b/libvirt/tests/cfg/sriov/plug_unplug/sriov_attach_released_hostdev.cfg @@ -3,7 +3,7 @@ start_vm = "no" dev_type = "hostdev_interface" iface_dict = {'managed': 'yes', 'type_name': 'hostdev', 'hostdev_address': {'type_name': 'pci', 'attrs': vf_pci_addr}} - only x86_64 + only x86_64, aarch64 variants test_scenario: - to_2nd_vm: vms = "ENTER.YOUR.VM1 ENTER.YOUR.VM2" diff --git a/libvirt/tests/cfg/sriov/scalability/sriov_scalability_max_vf.cfg b/libvirt/tests/cfg/sriov/scalability/sriov_scalability_max_vf.cfg index a7ce6a099c9..56c505f571a 100644 --- a/libvirt/tests/cfg/sriov/scalability/sriov_scalability_max_vf.cfg +++ b/libvirt/tests/cfg/sriov/scalability/sriov_scalability_max_vf.cfg @@ -1,5 +1,12 @@ - sriov.scalability.max_vfs: type = sriov_scalability_max_vfs start_vm = "no" + only x86_64 vf_no = 63 net_forward = {"mode": "hostdev", "managed": "yes"} + variants: + - maximum: + iface_num = 64 + - exceed_maximum: + iface_num = 65 + start_error = yes diff --git a/libvirt/tests/cfg/sriov/update_device/sriov_update_device.cfg b/libvirt/tests/cfg/sriov/update_device/sriov_update_device.cfg index ac8baec7d0f..a91be9ddaaa 100644 --- a/libvirt/tests/cfg/sriov/update_device/sriov_update_device.cfg +++ b/libvirt/tests/cfg/sriov/update_device/sriov_update_device.cfg @@ -4,4 +4,4 @@ iface_dict = {'managed': 'yes', 'type_name': 'hostdev', 'hostdev_address': {'type_name': 'pci', 'attrs': vf_pci_addr}} update_iface = {'managed': 'no'} err_msg = "cannot change config of 'hostdev'" - only x86_64 + only x86_64, aarch64 diff --git a/libvirt/tests/cfg/sriov/vIOMMU/attach_iommu_device.cfg b/libvirt/tests/cfg/sriov/vIOMMU/attach_iommu_device.cfg new file mode 100644 index 00000000000..a0d420b4dc7 --- /dev/null +++ b/libvirt/tests/cfg/sriov/vIOMMU/attach_iommu_device.cfg @@ -0,0 +1,20 @@ +- vIOMMU.attach_iommu_device: + type = attach_iommu_device + start_vm = "no" + err_msg = "attach of device 'iommu' is not supported" + variants: + - virtio: + only q35, aarch64 + func_supported_since_libvirt_ver = (8, 3, 0) + iommu_dict = {'model': 'virtio'} + - intel: + only q35 + iommu_dict = {'model': 'intel', 'driver': {'intremap': 'on', 'caching_mode': 'on'}} + - smmuv3: + only aarch64 + func_supported_since_libvirt_ver = (5, 5, 0) + iommu_dict = {'model': 'smmuv3'} + variants: + - cold_plug: + attach_option = "--config" + - hot_plug: diff --git a/libvirt/tests/cfg/sriov/vIOMMU/hotplug_device_with_iommu_enabled.cfg b/libvirt/tests/cfg/sriov/vIOMMU/hotplug_device_with_iommu_enabled.cfg new file mode 100644 index 00000000000..5705f62b3b0 --- /dev/null +++ b/libvirt/tests/cfg/sriov/vIOMMU/hotplug_device_with_iommu_enabled.cfg @@ -0,0 +1,74 @@ +- vIOMMU.hotplug_device_with_iommu_enabled: + type = hotplug_device_with_iommu_enabled + start_vm = "no" + ping_dest = '8.8.8.8' + disk_driver = {'name': 'qemu', 'type': 'qcow2', 'iommu': 'on'} + variants: + - virtio: + only q35, aarch64 + no ats_on + func_supported_since_libvirt_ver = (8, 3, 0) + iommu_dict = {'model': 'virtio'} + - intel: + only q35 + start_vm = "yes" + enable_guest_iommu = "yes" + iommu_dict = {'model': 'intel', 'driver': {'intremap': 'on', 'caching_mode': 'on', 'eim': 'on', 'iotlb': 'on', 'aw_bits': '48'}} + - smmuv3: + only aarch64 + no ats_on + func_supported_since_libvirt_ver = (5, 5, 0) + iommu_dict = {'model': 'smmuv3'} + variants: + - e1000e: + only q35 + iface_model = 'e1000e' + iface_dict = {'type_name': 'network', 'model': '${iface_model}', 'source': {'network': 'default'}} + test_devices = ["Eth"] + - rtl8139: + only q35 + iface_model = 'rtl8139' + iface_dict = {'type_name': 'network', 'model': '${iface_model}', 'source': {'network': 'default'}} + controller_dicts = [{'type': 'pci', 'model': 'pcie-to-pci-bridge'}] + - virtio_muti_devices: + disk_dict = {'target': {'dev': 'vdb', 'bus': 'virtio'}, 'device': 'disk', 'driver': ${disk_driver}} + test_devices = ["Eth", "block"] + variants: + - vhost_on: + interface_driver_name = "vhost" + - vhost_off: + interface_driver_name = "qemu" + interface_driver = {'driver_attr': {'name': '${interface_driver_name}', 'iommu': 'on'}} + iface_dict = {'type_name': 'network', 'model': 'virtio', 'driver': ${interface_driver}, 'source': {'network': 'default'}} + - hostdev_iface: + only virtio + need_sriov = yes + ping_dest = '' + test_devices = ["Eth"] + iface_dict = {'managed': 'yes', 'type_name': 'hostdev', 'hostdev_address': {'type_name': 'pci', 'attrs': vf_pci_addr}} + - scsi_controller: + test_devices = ["scsi"] + controller_dicts = [{'type': 'scsi', 'model': 'virtio-scsi','driver': {'iommu': 'on'}}] + disk_dict = {'target': {'dev': 'sda', 'bus': 'scsi'}} + cleanup_ifaces = no + - ats_on: + test_devices = ["Eth", "block"] + disk_driver = {'name': 'qemu', 'type': 'qcow2', 'iommu': 'on', 'ats': 'on'} + disk_dict = {'target': {'dev': 'vdb', 'bus': 'virtio'}, 'device': 'disk', 'driver': ${disk_driver}} + interface_driver = {'driver_attr': {'name': 'vhost', 'iommu': 'on', 'ats': 'on'}} + iface_dict = {'type_name': 'network', 'model': 'virtio', 'driver': ${interface_driver}, 'source': {'network': 'default'}} + - pcie_downstream_port: + test_devices = ["Eth", "block"] + upstream_port = {'type': 'pci', 'model': 'pcie-switch-upstream-port', 'pre_controller': 'pcie-root-port'} + downstream_port1 = {'type': 'pci', 'model': 'pcie-switch-downstream-port', 'target': {'chassis': '20', 'port': 0x0}, 'pre_controller': 'pcie-switch-upstream-port'} + downstream_port2 = {'type': 'pci', 'model': 'pcie-switch-downstream-port', 'target': {'chassis': '21', 'port': 0x0}, 'pre_controller': 'pcie-switch-upstream-port'} + iface_dict = {'type_name': 'network', 'model': 'virtio', 'driver': {'driver_attr': {'name': 'vhost', 'iommu': 'on'}}, 'source': {'network': 'default'}} + disk_dict = {'target': {'dev': 'vdb', 'bus': 'virtio'}, 'device': 'disk', 'driver': ${disk_driver}} + variants: + - from_pcie_root_port: + root_port = {'type': 'pci', 'model': 'pcie-root-port', 'pre_controller': 'pcie-root'} + controller_dicts = [${root_port}, ${upstream_port}, ${upstream_port}, ${downstream_port1}, ${downstream_port2}] + - from_expander_bus: + downstream_port = {'type': 'pci', 'model': 'pcie-switch-downstream-port', 'pre_controller': 'pcie-switch-upstream-port'} + root_port = {'type': 'pci', 'model': 'pcie-root-port', 'pre_controller': 'pcie-expander-bus'} + controller_dicts = [{'type': 'pci', 'model': 'pcie-expander-bus', 'target': {'busNr': '250'}, 'pre_controller': 'pcie-root'}, ${root_port}, ${upstream_port}, ${upstream_port}, ${downstream_port}, ${downstream_port}] diff --git a/libvirt/tests/cfg/sriov/vIOMMU/intel_iommu_aw_bits.cfg b/libvirt/tests/cfg/sriov/vIOMMU/intel_iommu_aw_bits.cfg new file mode 100644 index 00000000000..8f342d9b74d --- /dev/null +++ b/libvirt/tests/cfg/sriov/vIOMMU/intel_iommu_aw_bits.cfg @@ -0,0 +1,16 @@ +- vIOMMU.intel_iommu.aw_bits: + type = intel_iommu_aw_bits + start_vm = "yes" + enable_guest_iommu = "yes" + only q35 + + variants aw_bits_value: + - 48: + - 39: + - 36: + status_error = yes + err_msg = "Supported | supported values for aw-bits are" + - 3423: + status_error = yes + err_msg = "Parameter 'aw-bits' expects uint8_t" + iommu_dict = {'model': 'intel', 'driver': {'intremap': 'on', 'caching_mode': 'on', 'iotlb': 'on', 'aw_bits': ${aw_bits_value}}} diff --git a/libvirt/tests/cfg/sriov/vIOMMU/intel_iommu_virtio_device_with_ats.cfg b/libvirt/tests/cfg/sriov/vIOMMU/intel_iommu_virtio_device_with_ats.cfg new file mode 100644 index 00000000000..6b68368af0d --- /dev/null +++ b/libvirt/tests/cfg/sriov/vIOMMU/intel_iommu_virtio_device_with_ats.cfg @@ -0,0 +1,32 @@ +- vIOMMU.intel_iommu.virtio_device_with_ats: + type = iommu_device_settings + start_vm = "yes" + enable_guest_iommu = "yes" + iommu_dict = {'model': 'intel', 'driver': {'intremap': 'on', 'iotlb': 'on'}} + ping_dest = '8.8.8.8' + disk_driver = {'name': 'qemu', 'type': 'qcow2', 'iommu': 'on', 'ats': 'on'} + only q35 + + variants: + - virtio_muti_devices: + disk_dict = {'target': {'dev': 'vda', 'bus': 'virtio'}, 'device': 'disk', 'driver': ${disk_driver}} + video_dict = {'primary': 'yes', 'model_heads': '1', 'model_type': 'virtio', 'driver': {'iommu': 'on'}} + test_devices = ["Eth", "block", "gpu"] + variants: + - vhost_on: + interface_driver_name = "vhost" + - vhost_off: + interface_driver_name = "qemu" + interface_driver = {'driver_attr': {'name': '${interface_driver_name}', 'iommu': 'on', 'ats': 'on'}} + iface_dict = {'type_name': 'network', 'model': 'virtio', 'driver': ${interface_driver}, 'source': {'network': 'default'}} + - scsi_controller: + test_devices = ["scsi"] + controller_dicts = [{'type': 'scsi', 'model': 'virtio-scsi','driver': {'iommu': 'on', 'ats': 'on'}}] + disk_driver = {'name': 'qemu', 'type': 'qcow2'} + disk_dict = {'target': {'dev': 'sda', 'bus': 'scsi'}, 'driver': ${disk_driver}} + cleanup_ifaces = no + - pcie_root_port_from_expander_bus: + test_devices = ["Eth", "block"] + root_port = {'type': 'pci', 'model': 'pcie-root-port', 'pre_controller': 'pcie-expander-bus'} + controller_dicts = [{'type': 'pci', 'model': 'pcie-expander-bus', 'target': {'busNr': '252'}, 'pre_controller': 'pcie-root'}, ${root_port}, ${root_port}] + disk_dict = {'target': {'dev': 'vda', 'bus': 'virtio'}, 'device': 'disk', 'driver': ${disk_driver}} diff --git a/libvirt/tests/cfg/sriov/vIOMMU/intel_iommu_with_dma_translation.cfg b/libvirt/tests/cfg/sriov/vIOMMU/intel_iommu_with_dma_translation.cfg new file mode 100644 index 00000000000..15411a02ecf --- /dev/null +++ b/libvirt/tests/cfg/sriov/vIOMMU/intel_iommu_with_dma_translation.cfg @@ -0,0 +1,16 @@ +- vIOMMU.intel_iommu_with_dma_translation: + type = intel_iommu_with_dma_translation + start_vm = "yes" + enable_guest_iommu = "yes" + func_supported_since_libvirt_ver = (10, 7, 0) + only q35 + variants: + - enable_dma_translation: + dma_translation = "on" + - disable_dma_translation: + dma_translation = "off" + - disable_dma_translation_with_more_vcpus: + with_more_vcpus = "yes" + dma_translation = "off" + eim_dict = {'eim': 'on'} + iommu_dict = {'model': 'intel', 'driver': {'intremap': 'on', 'caching_mode': 'on', 'iotlb': 'on', 'dma_translation': '${dma_translation}'}} diff --git a/libvirt/tests/cfg/sriov/vIOMMU/intel_iommu_without_enabling_caching_mode.cfg b/libvirt/tests/cfg/sriov/vIOMMU/intel_iommu_without_enabling_caching_mode.cfg new file mode 100644 index 00000000000..ca97d6ac896 --- /dev/null +++ b/libvirt/tests/cfg/sriov/vIOMMU/intel_iommu_without_enabling_caching_mode.cfg @@ -0,0 +1,16 @@ +- vIOMMU.intel_iommu.without_enabling_caching_mode: + type = intel_iommu_without_enabling_caching_mode + err_msg = "caching-mode=on for [i|I]ntel" + start_vm = "yes" + iommu_dict = {'model': 'intel', 'driver': {'intremap': 'on'}} + only q35 + + variants dev_type: + - hostdev_interface: + iface_dict = {'managed': 'yes', 'type_name': 'hostdev', 'hostdev_address': {'type_name': 'pci', 'attrs': vf_pci_addr}} + - hostdev_device: + hostdev_dict = {'mode': 'subsystem', 'type': 'pci', 'source': {'untyped_address': vf_pci_addr}, 'managed': 'yes'} + variants: + - cold_plug: + attach_option = "--config" + - hot_plug: diff --git a/libvirt/tests/cfg/sriov/vIOMMU/intel_iommu_without_ioapic.cfg b/libvirt/tests/cfg/sriov/vIOMMU/intel_iommu_without_ioapic.cfg new file mode 100644 index 00000000000..77c03b0822d --- /dev/null +++ b/libvirt/tests/cfg/sriov/vIOMMU/intel_iommu_without_ioapic.cfg @@ -0,0 +1,14 @@ +- vIOMMU.intel_iommu.without_ioapic: + type = intel_iommu_without_ioapic + start_vm = "yes" + enable_guest_iommu = "yes" + feature_name = "ioapic" + iommu_dict = {'model': 'intel', 'driver': {'intremap': 'on'}} + only q35 + variants: + - default: + iommu_dict = {'model': 'intel'} + - intremap_on: + func_supported_since_libvirt_ver = (10, 10, 0) + iommu_dict = {'model': 'intel', 'driver': {'intremap': 'on'}} + auto_add_ioapic = "yes" diff --git a/libvirt/tests/cfg/sriov/vIOMMU/sriov_iommu_alias.cfg b/libvirt/tests/cfg/sriov/vIOMMU/iommu_alias.cfg similarity index 92% rename from libvirt/tests/cfg/sriov/vIOMMU/sriov_iommu_alias.cfg rename to libvirt/tests/cfg/sriov/vIOMMU/iommu_alias.cfg index 104abcc8b74..566fe590693 100644 --- a/libvirt/tests/cfg/sriov/vIOMMU/sriov_iommu_alias.cfg +++ b/libvirt/tests/cfg/sriov/vIOMMU/iommu_alias.cfg @@ -1,5 +1,5 @@ -- sriov.vIOMMU.iommu.alias: - type = sriov_iommu_alias +- vIOMMU.iommu.alias: + type = iommu_alias enable_guest_iommu = "yes" func_supported_since_libvirt_ver = (8, 7, 0) start_vm = "no" diff --git a/libvirt/tests/cfg/sriov/vIOMMU/iommu_device_lifecycle.cfg b/libvirt/tests/cfg/sriov/vIOMMU/iommu_device_lifecycle.cfg new file mode 100644 index 00000000000..1950bda758e --- /dev/null +++ b/libvirt/tests/cfg/sriov/vIOMMU/iommu_device_lifecycle.cfg @@ -0,0 +1,43 @@ +- vIOMMU.iommu_device_lifecycle: + type = iommu_device_lifecycle + start_vm = "no" + disk_driver = {'name': 'qemu', 'type': 'qcow2', 'iommu': 'on'} + variants: + - virtio: + only q35, aarch64 + func_supported_since_libvirt_ver = (8, 3, 0) + iommu_dict = {'model': 'virtio'} + - intel: + only q35 + start_vm = "yes" + enable_guest_iommu = "yes" + iommu_dict = {'model': 'intel', 'driver': {'intremap': 'on', 'caching_mode': 'on', 'eim': 'on', 'iotlb': 'on', 'aw_bits': '48'}} + - smmuv3: + only aarch64 + func_supported_since_libvirt_ver = (5, 5, 0) + iommu_dict = {'model': 'smmuv3'} + variants: + - e1000e: + only q35 + iface_model = 'e1000e' + iface_dict = {'type_name': 'network', 'model': '${iface_model}', 'source': {'network': 'default'}} + - virtio_muti_devices: + disk_dict = {'target': {'dev': 'vda', 'bus': 'virtio'}, 'device': 'disk', 'driver': ${disk_driver}} + video_dict = {'primary': 'yes', 'model_heads': '1', 'model_type': 'virtio', 'driver': {'iommu': 'on'}} + test_devices = ["Eth", "block", "gpu"] + variants: + - vhost_on: + interface_driver_name = "vhost" + interface_driver = {'driver_attr': {'name': '${interface_driver_name}', 'iommu': 'on'}} + iface_dict = {'type_name': 'network', 'model': 'virtio', 'driver': ${interface_driver}, 'source': {'network': 'default'}} + - hostdev_iface: + only virtio + no save_restore + need_sriov = "yes" + iface_dict = {'managed': 'yes', 'type_name': 'hostdev', 'hostdev_address': {'type_name': 'pci', 'attrs': vf_pci_addr}} + variants test_scenario: + - save_restore: + - suspend_resume: + - reboot_many_times: + loop_time = 5 + - reset: diff --git a/libvirt/tests/cfg/sriov/vIOMMU/iommu_device_settings.cfg b/libvirt/tests/cfg/sriov/vIOMMU/iommu_device_settings.cfg index 55044b87ed2..6da40ca9f46 100644 --- a/libvirt/tests/cfg/sriov/vIOMMU/iommu_device_settings.cfg +++ b/libvirt/tests/cfg/sriov/vIOMMU/iommu_device_settings.cfg @@ -19,11 +19,11 @@ iommu_dict = {'model': 'smmuv3'} variants: - e1000e: - no smmuv3 + only q35 iface_model = 'e1000e' iface_dict = {'type_name': 'network', 'model': '${iface_model}', 'source': {'network': 'default'}} - rtl8139: - no smmuv3 + only q35 iface_model = 'rtl8139' iface_dict = {'type_name': 'network', 'model': '${iface_model}', 'source': {'network': 'default'}} - virtio_muti_devices: @@ -39,27 +39,47 @@ iface_dict = {'type_name': 'network', 'model': 'virtio', 'driver': ${interface_driver}, 'source': {'network': 'default'}} - hostdev_iface: only virtio + need_sriov = yes ping_dest = '' test_devices = ["Eth"] iface_dict = {'managed': 'yes', 'type_name': 'hostdev', 'hostdev_address': {'type_name': 'pci', 'attrs': vf_pci_addr}} - scsi_controller: test_devices = ["scsi"] controller_dicts = [{'type': 'scsi', 'model': 'virtio-scsi','driver': {'iommu': 'on'}}] - disk_dict = {'target': {'dev': 'sda', 'bus': 'scsi'}} + disk_driver = {'name': 'qemu', 'type': 'qcow2'} + disk_dict = {'target': {'dev': 'sda', 'bus': 'scsi'}, 'driver': ${disk_driver}} cleanup_ifaces = no - pcie_to_pci_bridge_controller: - test_devices = ["Eth", "block"] controller_dicts = [{'type': 'pci', 'model': 'pcie-to-pci-bridge', 'pre_controller': 'pcie-root-port'}] disk_dict = {'target': {'dev': 'vda', 'bus': 'virtio'}, 'device': 'disk', 'driver': ${disk_driver}, 'model': 'virtio-non-transitional'} variants: - virtio_non_transitional: + no smmuv3 iface_dict = {'source': {'network': 'default'}, 'driver': {'driver_attr': {'iommu': 'on'}},'type_name': 'network', 'model': 'virtio-non-transitional'} - hostdev_iface: only virtio + need_sriov = yes ping_dest = '' iface_dict = {'managed': 'yes', 'type_name': 'hostdev', 'hostdev_address': {'type_name': 'pci', 'attrs': vf_pci_addr}} - pcie_root_port_from_expander_bus: test_devices = ["Eth", "block"] root_port = {'type': 'pci', 'model': 'pcie-root-port', 'pre_controller': 'pcie-expander-bus'} - controller_dicts = [{'type': 'pci', 'model': 'pcie-expander-bus', 'pre_controller': 'pcie-root'}, ${root_port}, ${root_port}] + controller_dicts = [{'type': 'pci', 'model': 'pcie-expander-bus', 'target': {'busNr': '252'}, 'pre_controller': 'pcie-root'}, ${root_port}, ${root_port}] + iface_dict = {'source': {'network': 'default'}} disk_dict = {'target': {'dev': 'vda', 'bus': 'virtio'}, 'device': 'disk', 'driver': ${disk_driver}} + - pcie_downstream_port: + test_devices = ["Eth", "block"] + dev_in_same_iommu_group = ["XIO3130", *${test_devices}] + upstream_port = {'type': 'pci', 'model': 'pcie-switch-upstream-port', 'pre_controller': 'pcie-root-port'} + downstream_port1 = {'type': 'pci', 'model': 'pcie-switch-downstream-port', 'target': {'chassis': '20', 'port': 0x0}, 'pre_controller': 'pcie-switch-upstream-port'} + downstream_port2 = {'type': 'pci', 'model': 'pcie-switch-downstream-port', 'target': {'chassis': '21', 'port': 0x0}, 'pre_controller': 'pcie-switch-upstream-port'} + iface_dict = {'type_name': 'network', 'model': 'virtio', 'driver': {'driver_attr': {'name': 'vhost', 'iommu': 'on'}}, 'source': {'network': 'default'}} + disk_dict = {'target': {'dev': 'vdb', 'bus': 'virtio'}, 'device': 'disk', 'driver': ${disk_driver}} + variants: + - from_pcie_root_port: + root_port = {'type': 'pci', 'model': 'pcie-root-port', 'pre_controller': 'pcie-root'} + controller_dicts = [${root_port}, ${upstream_port}, ${upstream_port}, ${downstream_port1}, ${downstream_port2}] + - from_expander_bus: + downstream_port = {'type': 'pci', 'model': 'pcie-switch-downstream-port', 'pre_controller': 'pcie-switch-upstream-port'} + root_port = {'type': 'pci', 'model': 'pcie-root-port', 'pre_controller': 'pcie-expander-bus'} + controller_dicts = [{'type': 'pci', 'model': 'pcie-expander-bus', 'target': {'busNr': '250'}, 'pre_controller': 'pcie-root'}, ${root_port}, ${upstream_port}, ${upstream_port}, ${downstream_port}, ${downstream_port}] diff --git a/libvirt/tests/cfg/sriov/vIOMMU/iommu_repeated_reset.cfg b/libvirt/tests/cfg/sriov/vIOMMU/iommu_repeated_reset.cfg new file mode 100644 index 00000000000..35af9fd26f2 --- /dev/null +++ b/libvirt/tests/cfg/sriov/vIOMMU/iommu_repeated_reset.cfg @@ -0,0 +1,28 @@ +- vIOMMU.iommu_repeated_reset: + type = iommu_repeated_reset + ping_dest = '8.8.8.8' + max_wait_ms = 3000 + max_repeat = 10 + str_in_log = False + log_messages = "virtio: zero sized buffers are not allowed" + variants: + - virtio: + only q35, aarch64 + func_supported_since_libvirt_ver = (8, 3, 0) + iommu_dict = {'model': 'virtio'} + - intel: + only q35 + start_vm = "yes" + enable_guest_iommu = "yes" + iommu_dict = {'model': 'intel', 'driver': {'intremap': 'on', 'caching_mode': 'on', 'eim': 'on', 'iotlb': 'on', 'aw_bits': '48'}} + - smmuv3: + only aarch64 + func_supported_since_libvirt_ver = (5, 5, 0) + iommu_dict = {'model': 'smmuv3'} + variants: + - scsi_controller: + controller_dicts = [{'type': 'scsi', 'model': 'virtio-scsi','driver': {'iommu': 'on'}}] + disk_driver = {'name': 'qemu', 'type': 'qcow2'} + disk_dict = {'target': {'dev': 'sda', 'bus': 'scsi'}, 'driver': ${disk_driver}} + cleanup_ifaces = no + start_vm = "yes" diff --git a/libvirt/tests/cfg/sriov/vIOMMU/migration_iommu_device.cfg b/libvirt/tests/cfg/sriov/vIOMMU/migration_iommu_device.cfg index d0994e5931b..97ac59f6189 100644 --- a/libvirt/tests/cfg/sriov/vIOMMU/migration_iommu_device.cfg +++ b/libvirt/tests/cfg/sriov/vIOMMU/migration_iommu_device.cfg @@ -24,6 +24,7 @@ virsh_migrate_desturi = "qemu+ssh://${migrate_dest_host}/system" virsh_migrate_connect_uri = "qemu:///system" check_network_accessibility_after_mig = "yes" + check_cont_ping = "yes" disk_driver = {'name': 'qemu', 'type': 'qcow2', 'iommu': 'on'} variants: - virtio: diff --git a/libvirt/tests/cfg/sriov/vIOMMU/viommu_netperf.cfg b/libvirt/tests/cfg/sriov/vIOMMU/viommu_netperf.cfg new file mode 100644 index 00000000000..950667f8ea3 --- /dev/null +++ b/libvirt/tests/cfg/sriov/vIOMMU/viommu_netperf.cfg @@ -0,0 +1,49 @@ +- vIOMMU.netperf: + type = viommu_netperf + vms = avocado-vt-vm1 + net_name = network_conn + ip_attrs = {"netmask": "255.255.255.0", "address": "192.168.144.1", "dhcp_ranges": {"attrs": {"end": "192.168.144.254", "start": "192.168.144.2"}}} + iface_attrs = {"source": {"network": "${net_name}"}, "type_name": "network", "model": "virtio"} + network_attrs = {"name": "${net_name}", "forward": {"mode": "nat"}, "ips": [${ip_attrs}]} + start_vm = "no" + variants: + - virtio: + only q35, aarch64 + func_supported_since_libvirt_ver = (8, 3, 0) + iommu_dict = {'model': 'virtio'} + - intel: + only q35 + start_vm = "yes" + enable_guest_iommu = "yes" + iommu_dict = {'model': 'intel', 'driver': {'intremap': 'on', 'caching_mode': 'on', 'eim': 'on', 'iotlb': 'on', 'aw_bits': '48'}} + - smmuv3: + only aarch64 + func_supported_since_libvirt_ver = (5, 5, 0) + iommu_dict = {'model': 'smmuv3'} + variants: + - e1000e: + only q35 + iface_model = 'e1000e' + iface_dict = {'type_name': 'network', 'model': '${iface_model}', 'source': {'network': 'default'}} + - virtio_interface: + interface_driver_name = "vhost" + interface_driver = {'driver_attr': {'name': '${interface_driver_name}', 'iommu': 'on'}} + iface_dict = {'type_name': 'network', 'model': 'virtio', 'driver': ${interface_driver}, 'source': {'network': 'default'}} + variants: + - guest2guest: + vms = avocado-vt-vm1 vm2 + netperf_client = avocado-vt-vm1 + netperf_server = vm2 + - host2guest: + netperf_client = ${local_ip} + netperf_server = ${main_vm} + - guest2host: + netperf_client = ${main_vm} + netperf_server = ${local_ip} + UDP_STREAM: + extra_cmd_opts = "-- -R 1" + variants: + - TCP_STREAM: + test_protocol = TCP_STREAM + - UDP_STREAM: + test_protocol = UDP_STREAM diff --git a/libvirt/tests/cfg/sriov/vIOMMU/viommu_transfer_file.cfg b/libvirt/tests/cfg/sriov/vIOMMU/viommu_transfer_file.cfg new file mode 100644 index 00000000000..681ac9aaf5a --- /dev/null +++ b/libvirt/tests/cfg/sriov/vIOMMU/viommu_transfer_file.cfg @@ -0,0 +1,27 @@ +- vIOMMU.transfer_file: + type = viommu_transfer_file + start_vm = "no" + disk_driver = {'name': 'qemu', 'type': 'qcow2', 'iommu': 'on'} + variants: + - virtio: + only q35, aarch64 + func_supported_since_libvirt_ver = (8, 3, 0) + iommu_dict = {'model': 'virtio'} + - intel: + only q35 + start_vm = "yes" + enable_guest_iommu = "yes" + iommu_dict = {'model': 'intel', 'driver': {'intremap': 'on', 'caching_mode': 'on', 'eim': 'on', 'iotlb': 'on', 'aw_bits': '48'}} + - smmuv3: + only aarch64 + func_supported_since_libvirt_ver = (5, 5, 0) + iommu_dict = {'model': 'smmuv3'} + variants: + - e1000e: + only q35 + iface_model = 'e1000e' + iface_dict = {'type_name': 'network', 'model': '${iface_model}', 'source': {'network': 'default'}} + - virtio_interface: + interface_driver_name = "vhost" + interface_driver = {'driver_attr': {'name': '${interface_driver_name}', 'iommu': 'on'}} + iface_dict = {'type_name': 'network', 'model': 'virtio', 'driver': ${interface_driver}, 'source': {'network': 'default'}} diff --git a/libvirt/tests/cfg/sriov/vIOMMU/viommu_unload_driver.cfg b/libvirt/tests/cfg/sriov/vIOMMU/viommu_unload_driver.cfg new file mode 100644 index 00000000000..59aa9c11aea --- /dev/null +++ b/libvirt/tests/cfg/sriov/vIOMMU/viommu_unload_driver.cfg @@ -0,0 +1,27 @@ +- vIOMMU.unload_driver: + type = viommu_unload_driver + start_vm = "no" + + variants: + - virtio: + only q35, aarch64 + func_supported_since_libvirt_ver = (8, 3, 0) + iommu_dict = {'model': 'virtio'} + - intel: + only q35 + start_vm = "yes" + enable_guest_iommu = "yes" + iommu_dict = {'model': 'intel', 'driver': {'intremap': 'on', 'caching_mode': 'on', 'eim': 'on', 'iotlb': 'on', 'aw_bits': '48'}} + - smmuv3: + only aarch64 + func_supported_since_libvirt_ver = (5, 5, 0) + iommu_dict = {'model': 'smmuv3'} + variants: + - virtio_interface: + variants: + - vhost_on: + interface_driver_name = "vhost" + - vhost_off: + interface_driver_name = "qemu" + interface_driver = {'driver_attr': {'name': '${interface_driver_name}', 'iommu': 'on'}} + iface_dict = {'type_name': 'network', 'model': 'virtio', 'driver': ${interface_driver}, 'source': {'network': 'default'}} diff --git a/libvirt/tests/cfg/sriov/vIOMMU/sriov_virtio_iommu_with_addtional_attributes.cfg b/libvirt/tests/cfg/sriov/vIOMMU/virtio_iommu_with_addtional_attributes.cfg similarity index 82% rename from libvirt/tests/cfg/sriov/vIOMMU/sriov_virtio_iommu_with_addtional_attributes.cfg rename to libvirt/tests/cfg/sriov/vIOMMU/virtio_iommu_with_addtional_attributes.cfg index 352904ef7a0..651b609ecbd 100644 --- a/libvirt/tests/cfg/sriov/vIOMMU/sriov_virtio_iommu_with_addtional_attributes.cfg +++ b/libvirt/tests/cfg/sriov/vIOMMU/virtio_iommu_with_addtional_attributes.cfg @@ -1,10 +1,10 @@ -- sriov.vIOMMU.virtio_iommu.addtional_attributes: - type = sriov_virtio_iommu_with_addtional_attributes +- vIOMMU.virtio_iommu.addtional_attributes: + type = virtio_iommu_with_addtional_attributes start_vm = "no" enable_guest_iommu = "yes" err_msg = "iommu model 'virtio' doesn't support additional attributes" func_supported_since_libvirt_ver = (8, 7, 0) - only x86_64 + only x86_64, aarch64 variants: - caching_mode: iommu_dict = {'driver': {'caching_mode': 'on'}, 'model': 'virtio'} diff --git a/libvirt/tests/cfg/sriov/vm_lifecycle/sriov_vm_lifecycle_exclusive_check_offline_domain.cfg b/libvirt/tests/cfg/sriov/vm_lifecycle/sriov_vm_lifecycle_exclusive_check_offline_domain.cfg index 74bce0ccad3..9fd7f4763f5 100644 --- a/libvirt/tests/cfg/sriov/vm_lifecycle/sriov_vm_lifecycle_exclusive_check_offline_domain.cfg +++ b/libvirt/tests/cfg/sriov/vm_lifecycle/sriov_vm_lifecycle_exclusive_check_offline_domain.cfg @@ -1,7 +1,7 @@ - sriov.vm_lifecycle.exclusive_check.offline_domain: type = sriov_vm_lifecycle_exclusive_check_offline_domain start_vm = "no" - only x86_64 + only x86_64, aarch64 variants dev_type: - hostdev_interface: iface_dict = {'managed': 'yes', 'type_name': 'hostdev', 'hostdev_address': {'type_name': 'pci', 'attrs': vf_pci_addr}} @@ -12,7 +12,7 @@ err_msg = "Hostdev already exists" - hostdev_device: hostdev_dict2 = {'mode': 'subsystem', 'type': 'pci', 'source': {'untyped_address': pf_pci_addr}, 'managed': 'yes'} - err_msg = "interface of PCI device" + err_msg = "interface of PCI device" - hostdev_device: hostdev_dict = {'mode': 'subsystem', 'type': 'pci', 'source': {'untyped_address': vf_pci_addr}, 'managed': 'yes'} variants dev_type2: diff --git a/libvirt/tests/cfg/sriov/vm_lifecycle/sriov_vm_lifecycle_exclusive_check_running_domain.cfg b/libvirt/tests/cfg/sriov/vm_lifecycle/sriov_vm_lifecycle_exclusive_check_running_domain.cfg index bdb5251bf20..20be3cde79a 100644 --- a/libvirt/tests/cfg/sriov/vm_lifecycle/sriov_vm_lifecycle_exclusive_check_running_domain.cfg +++ b/libvirt/tests/cfg/sriov/vm_lifecycle/sriov_vm_lifecycle_exclusive_check_running_domain.cfg @@ -2,7 +2,7 @@ type = sriov_vm_lifecycle_exclusive_check_running_domain vms = "ENTER.YOUR.VM1 ENTER.YOUR.VM2" start_vm = "no" - only x86_64 + only x86_64, aarch64 dev_type = "hostdev_interface" iface_dict = {'managed': 'yes', 'type_name': 'hostdev', 'hostdev_address': {'type_name': 'pci', 'attrs': vf_pci_addr}} err_msg = "in use by driver" @@ -11,7 +11,7 @@ - start_2nd_vm: dev_type2 = hostdev_interface iface_dict2 = ${iface_dict} - - assigned_VF_to_host: + - assigned_VF_to_host: - hotplug: dev_type2 = "hostdev_device" hostdev_dict2 = {'mode': 'subsystem', 'type': 'pci', 'source': {'untyped_address': vf_pci_addr}, 'managed': 'yes'} diff --git a/libvirt/tests/cfg/sriov/vm_lifecycle/sriov_vm_lifecycle_iommu_at_dt_hostdev.cfg b/libvirt/tests/cfg/sriov/vm_lifecycle/sriov_vm_lifecycle_iommu_at_dt_hostdev.cfg index 72d23a24d90..4484fe92795 100644 --- a/libvirt/tests/cfg/sriov/vm_lifecycle/sriov_vm_lifecycle_iommu_at_dt_hostdev.cfg +++ b/libvirt/tests/cfg/sriov/vm_lifecycle/sriov_vm_lifecycle_iommu_at_dt_hostdev.cfg @@ -10,9 +10,10 @@ - hostdev_interface: variants test_scenario: - managed_yes: - iface_dict = {'managed': 'yes', 'type_name': 'hostdev', 'hostdev_address': {'type_name': 'pci', 'attrs': vf_pci_addr}} + iface_dict = {'managed': 'yes', 'type_name': 'hostdev', 'hostdev_address': {'type_name': 'pci', 'attrs': vf_pci_addr}} - failover: - expr_iface_no = 3 + no aarch64 + expr_iface_no = 3 br_dict = {'source': {'bridge': 'br0'}, 'teaming': {'type': 'persistent'}, 'alias': {'name': 'ua-3f13c36e-186b-4c6b-ba54-0ec483613931'}, 'mac_address': mac_addr, 'model': 'virtio', 'type_name': 'bridge'} iface_dict = {'teaming': {'type': 'transient', 'persistent': 'ua-3f13c36e-186b-4c6b-ba54-0ec483613931'}, 'mac_address': mac_addr, 'type_name': 'hostdev', 'hostdev_address': {'type_name': 'pci', 'attrs': vf_pci_addr}} - hostdev_device: diff --git a/libvirt/tests/cfg/sriov/vm_lifecycle/sriov_vm_lifecycle_managedsave.cfg b/libvirt/tests/cfg/sriov/vm_lifecycle/sriov_vm_lifecycle_managedsave.cfg index b89f0f07d80..5703bbd38f7 100644 --- a/libvirt/tests/cfg/sriov/vm_lifecycle/sriov_vm_lifecycle_managedsave.cfg +++ b/libvirt/tests/cfg/sriov/vm_lifecycle/sriov_vm_lifecycle_managedsave.cfg @@ -3,7 +3,7 @@ start_vm = "no" status_error = "yes" err_msg = "cannot migrate.*domain.*(VFIO.*migration|with.*hostdev)" - only x86_64 + only x86_64, aarch64 variants dev_type: - hostdev_interface: variants dev_source: diff --git a/libvirt/tests/cfg/sriov/vm_lifecycle/sriov_vm_lifecycle_reboot.cfg b/libvirt/tests/cfg/sriov/vm_lifecycle/sriov_vm_lifecycle_reboot.cfg index 320a461cd21..2af6ece1e18 100644 --- a/libvirt/tests/cfg/sriov/vm_lifecycle/sriov_vm_lifecycle_reboot.cfg +++ b/libvirt/tests/cfg/sriov/vm_lifecycle/sriov_vm_lifecycle_reboot.cfg @@ -2,7 +2,7 @@ type = sriov_vm_lifecycle_reboot start_vm = "no" - only x86_64 + only x86_64, aarch64 variants: - with_iommu: only vf_address..managed_yes, failover @@ -10,6 +10,10 @@ start_vm = "yes" enable_guest_iommu = "yes" iommu_dict = {'driver': {'intremap': 'on', 'caching_mode': 'on'}, 'model': 'intel'} + aarch64: + start_vm = "no" + enable_guest_iommu = "no" + iommu_dict = {'model': 'virtio'} - without_iommu: no failover variants dev_type: @@ -21,6 +25,8 @@ iface_dict = {'managed': 'yes', 'type_name': 'hostdev', 'hostdev_address': {'type_name': 'pci', 'attrs': vf_pci_addr}, 'driver': {'driver_attr': {'name': 'vfio'}}, 'alias': {'name': 'ua-89cbe690-6c6c-4f2f-adac-5826fe52ea74'}, 'mac_address': mac_addr} iface_dict2 = {'managed': 'yes', 'type_name': 'hostdev', 'hostdev_address': {'type_name': 'pci', 'attrs': vf_pci_addr2}, 'driver': {'driver_attr': {'name': 'vfio'}}} check_ping_time = "yes" + aarch64: + check_ping_time = "no" - managed_no: iface_dict = {'managed': 'no', 'type_name': 'hostdev', 'hostdev_address': {'type_name': 'pci', 'attrs': vf_pci_addr}, 'alias': {'name': 'ua-89cbe690-6c6c-4f2f-adac-5826fe52ea74'}} - without_managed: @@ -28,6 +34,7 @@ - vlan: iface_dict = {'type_name': 'hostdev', 'vlan': {'tags': [{'id': '42'}]}, 'hostdev_address': {'type_name': 'pci', 'attrs': vf_pci_addr}, 'alias': {'name': 'ua-89cbe690-6c6c-4f2f-adac-5826fe52ea74'}, 'managed': 'yes', 'driver': {'driver_attr': {'name': 'vfio'}}, 'mac_address': mac_addr} - failover: + no aarch64 br_dict = {'source': {'bridge': 'br0'}, 'teaming': {'type': 'persistent'}, 'alias': {'name': 'ua-3f13c36e-186b-4c6b-ba54-0ec483613931'}, 'mac_address': mac_addr, 'model': 'virtio', 'type_name': 'bridge'} iface_dict = {'teaming': {'type': 'transient', 'persistent': 'ua-3f13c36e-186b-4c6b-ba54-0ec483613931'}, 'mac_address': mac_addr, 'type_name': 'hostdev', 'hostdev_address': {'type_name': 'pci', 'attrs': vf_pci_addr}} - hostdev_device: diff --git a/libvirt/tests/cfg/sriov/vm_lifecycle/sriov_vm_lifecycle_start_destroy.cfg b/libvirt/tests/cfg/sriov/vm_lifecycle/sriov_vm_lifecycle_start_destroy.cfg index a91fa70d35e..f02482e7787 100644 --- a/libvirt/tests/cfg/sriov/vm_lifecycle/sriov_vm_lifecycle_start_destroy.cfg +++ b/libvirt/tests/cfg/sriov/vm_lifecycle/sriov_vm_lifecycle_start_destroy.cfg @@ -2,7 +2,7 @@ type = sriov_vm_lifecycle_start_destroy start_vm = "no" - only x86_64 + only x86_64, aarch64 variants dev_type: - hostdev_interface: variants dev_source: diff --git a/libvirt/tests/cfg/sriov/vm_lifecycle/sriov_vm_lifecycle_start_negative.cfg b/libvirt/tests/cfg/sriov/vm_lifecycle/sriov_vm_lifecycle_start_negative.cfg index bd10d7bffb8..0c7ba9c9c9c 100644 --- a/libvirt/tests/cfg/sriov/vm_lifecycle/sriov_vm_lifecycle_start_negative.cfg +++ b/libvirt/tests/cfg/sriov/vm_lifecycle/sriov_vm_lifecycle_start_negative.cfg @@ -2,7 +2,7 @@ type = sriov_vm_lifecycle_start_negative start_vm = "no" status_error = "yes" - only x86_64 + only x86_64, aarch64 variants dev_type: - hostdev_interface: variants test_scenario: @@ -27,12 +27,18 @@ err_msg = "is supported only for hostdev" define_err = "yes" - iommu_without_caching: + no aarch64 iommu_dict = {'driver': {'intremap': 'on'}, 'model': 'intel'} iface_dict = {'managed': 'yes', 'type_name': 'hostdev', 'hostdev_address': {'type_name': 'pci', 'attrs': vf_pci_addr}} err_msg = "iommu to enable" + - invalid_driver_model: + driver_model = "test" + iface_dict = {'managed': 'yes', 'type_name': 'hostdev', 'hostdev_address': {'type_name': 'pci', 'attrs': vf_pci_addr}, 'driver': {'driver_attr': {'name': 'vfio', 'model': '${driver_model}'}}} + err_msg = "Failed to load PCI driver module ${driver_model}" - hostdev_device: variants test_scenario: - iommu_without_caching: + no aarch64 iommu_dict = {'driver': {'intremap': 'on'}, 'model': 'intel'} hostdev_dict = {'mode': 'subsystem', 'type': 'pci', 'source': {'untyped_address': vf_pci_addr}, 'managed': 'yes'} err_msg = "iommu to enable" diff --git a/libvirt/tests/cfg/sriov/vm_lifecycle/sriov_vm_lifecycle_suspend_resume.cfg b/libvirt/tests/cfg/sriov/vm_lifecycle/sriov_vm_lifecycle_suspend_resume.cfg index 1bd1bbea104..11fcdeb84f7 100644 --- a/libvirt/tests/cfg/sriov/vm_lifecycle/sriov_vm_lifecycle_suspend_resume.cfg +++ b/libvirt/tests/cfg/sriov/vm_lifecycle/sriov_vm_lifecycle_suspend_resume.cfg @@ -2,7 +2,7 @@ type = sriov_vm_lifecycle_suspend_resume start_vm = "no" - only x86_64 + only x86_64, aarch64 variants: - with_iommu: only vf_address..managed_yes, failover @@ -10,6 +10,10 @@ start_vm = "yes" enable_guest_iommu = "yes" iommu_dict = {'driver': {'intremap': 'on', 'caching_mode': 'on'}, 'model': 'intel'} + aarch64: + start_vm = "no" + enable_guest_iommu = "no" + iommu_dict = {'model': 'virtio'} - without_iommu: no failover variants dev_type: @@ -26,6 +30,7 @@ - vlan: iface_dict = {'type_name': 'hostdev', 'vlan': {'tags': [{'id': '42'}]}, 'hostdev_address': {'type_name': 'pci', 'attrs': vf_pci_addr}, 'alias': {'name': 'ua-89cbe690-6c6c-4f2f-adac-5826fe52ea74'}, 'managed': 'yes', 'driver': {'driver_attr': {'name': 'vfio'}}, 'mac_address': mac_addr} - failover: + no aarch64 br_dict = {'source': {'bridge': 'br0'}, 'teaming': {'type': 'persistent'}, 'alias': {'name': 'ua-3f13c36e-186b-4c6b-ba54-0ec483613931'}, 'mac_address': mac_addr, 'model': 'virtio', 'type_name': 'bridge'} iface_dict = {'teaming': {'type': 'transient', 'persistent': 'ua-3f13c36e-186b-4c6b-ba54-0ec483613931'}, 'mac_address': mac_addr, 'type_name': 'hostdev', 'hostdev_address': {'type_name': 'pci', 'attrs': vf_pci_addr}} - hostdev_device: diff --git a/libvirt/tests/cfg/sriov/vm_lifecycle/sriov_vm_lifecycle_unmanaged.cfg b/libvirt/tests/cfg/sriov/vm_lifecycle/sriov_vm_lifecycle_unmanaged.cfg index 7a587c350d2..62433ffb1c3 100644 --- a/libvirt/tests/cfg/sriov/vm_lifecycle/sriov_vm_lifecycle_unmanaged.cfg +++ b/libvirt/tests/cfg/sriov/vm_lifecycle/sriov_vm_lifecycle_unmanaged.cfg @@ -3,7 +3,7 @@ status_error = "yes" err_msg = "Unmanaged PCI device.*must be manually detached from the host" - only x86_64 + only x86_64, aarch64 variants dev_type: - hostdev_interface: variants dev_source: diff --git a/libvirt/tests/cfg/storage/virsh_pool.cfg b/libvirt/tests/cfg/storage/virsh_pool.cfg index 8a51c3109b7..f7a85cad26e 100644 --- a/libvirt/tests/cfg/storage/virsh_pool.cfg +++ b/libvirt/tests/cfg/storage/virsh_pool.cfg @@ -15,14 +15,14 @@ func_supported_since_libvirt_ver = (9, 5, 0) parallel_executable_path = '../../deps/cve_2023_3750.sh' pool_type = 'rbd' - required_commands = "['parallel', 'rbd']" + required_commands = "['rbd']" auth_key = "EXAMPLE_AUTH_KEY" - auth_user = 'EXAMPLE_AUTH_USER' - client_name = 'EXAMPLE_CLIENT_NAME' - ceph_host_ip = 'EXAMPLE_MON_HOST_AUTHX' + auth_user = "EXAMPLE_AUTH_USER" + client_name = "EXAMPLE_CLIENT_NAME" + ceph_host_ip = "EXAMPLE_MON_HOST_AUTHX" mon_host = "${ceph_host_ip}" - pool_source_name = 'EXAMPLE_POOL_NAME' - pool_name = 'libvirt-rbd-pool' + pool_source_name = "EXAMPLE_POOL_NAME" + pool_name = "libvirt-rbd-pool" image_path = "${pool_source_name}/%s_rbd.img" rbd_image_size = '5M' pool_source_attrs = "'source': {'host_name': '${ceph_host_ip}', 'auth_type': 'ceph', 'auth_username': 'admin', 'vg_name': '${pool_source_name}', 'secret_uuid': '%s'}" diff --git a/libvirt/tests/cfg/virsh_cmd/pool/virsh_pool_autostart.cfg b/libvirt/tests/cfg/storage/virsh_pool_autostart.cfg similarity index 88% rename from libvirt/tests/cfg/virsh_cmd/pool/virsh_pool_autostart.cfg rename to libvirt/tests/cfg/storage/virsh_pool_autostart.cfg index 8f3466e9e80..05b40489260 100644 --- a/libvirt/tests/cfg/virsh_cmd/pool/virsh_pool_autostart.cfg +++ b/libvirt/tests/cfg/storage/virsh_pool_autostart.cfg @@ -1,7 +1,5 @@ - virsh.pool_autostart: type = virsh_pool_autostart - vms = '' - main_vm = '' pool_name = "virsh_pool_test" pool_type = "dir" start_vm = "no" @@ -54,6 +52,9 @@ source_format = "lvm2" - source_format_auto: source_format = "auto" + - with_empty_vg: + func_supported_since_libvirt_ver = (9, 9, 0) + with_empty_vg = "yes" - pool_type_netfs: pool_type = "netfs" pool_target = "/nfs-mount" @@ -71,6 +72,11 @@ ip_protocal = "ipv4" - ipv6_target: ip_protocal = "ipv6" + - destroy_pool_used_by_guest: + destroy_pool_used_by_guest = "yes" + new_dev = 'sdc' + source_attr = "'source':{'attrs': {'pool': '%s', 'volume':'%s'}}" + disk_dict = {"type_name":"volume",'device':'disk',${source_attr},"target":{"dev": "${new_dev}", "bus": "virtio"}, "driver": {"name": "qemu", "type":"raw"}} - pool_type_scsi: pool_type = "scsi" pool_target = "/dev/disk/by-path" diff --git a/libvirt/tests/cfg/svirt/dac/dac_seclabel_per_device.cfg b/libvirt/tests/cfg/svirt/dac/dac_seclabel_per_device.cfg index 3319f870d80..15896e4851e 100644 --- a/libvirt/tests/cfg/svirt/dac/dac_seclabel_per_device.cfg +++ b/libvirt/tests/cfg/svirt/dac/dac_seclabel_per_device.cfg @@ -7,6 +7,7 @@ - cold_plug: - hot_plug: serial: + no s390-virtio func_supported_since_libvirt_ver = (8, 7, 0) variants test_device: - disk: @@ -31,6 +32,7 @@ variants: - without_label: status_error = "yes" + err_msg = "XML error: Cannot specify relabel if label is missing. model=dac" - with_label: variants: - s_qemu: diff --git a/libvirt/tests/cfg/svirt/selinux/selinux_seclabel_per_device.cfg b/libvirt/tests/cfg/svirt/selinux/selinux_seclabel_per_device.cfg index 7497aaa766b..b04262880b4 100644 --- a/libvirt/tests/cfg/svirt/selinux/selinux_seclabel_per_device.cfg +++ b/libvirt/tests/cfg/svirt/selinux/selinux_seclabel_per_device.cfg @@ -7,6 +7,7 @@ - cold_plug: - hot_plug: serial: + no s390-virtio func_supported_since_libvirt_ver = (8, 7, 0) variants test_device: - disk: diff --git a/libvirt/tests/cfg/svirt/umask_value/svirt_umask_files_accessed_by_qemu.cfg b/libvirt/tests/cfg/svirt/umask_value/svirt_umask_files_accessed_by_qemu.cfg index fed7c586519..f38ae0a6afc 100644 --- a/libvirt/tests/cfg/svirt/umask_value/svirt_umask_files_accessed_by_qemu.cfg +++ b/libvirt/tests/cfg/svirt/umask_value/svirt_umask_files_accessed_by_qemu.cfg @@ -3,8 +3,5 @@ start_vm = "no" umask_value = '027' mem_backing_attrs = {'hugepages': {}} - target_hugepages = 1024 - aarch64: - target_hugepages = 4 s390-virtio: kvm_module_parameters = "hpage=1" diff --git a/libvirt/tests/cfg/libvirt_usb_hotplug_controller.cfg b/libvirt/tests/cfg/usb/libvirt_usb_hotplug_controller.cfg similarity index 100% rename from libvirt/tests/cfg/libvirt_usb_hotplug_controller.cfg rename to libvirt/tests/cfg/usb/libvirt_usb_hotplug_controller.cfg diff --git a/libvirt/tests/cfg/libvirt_usb_hotplug_device.cfg b/libvirt/tests/cfg/usb/libvirt_usb_hotplug_device.cfg similarity index 100% rename from libvirt/tests/cfg/libvirt_usb_hotplug_device.cfg rename to libvirt/tests/cfg/usb/libvirt_usb_hotplug_device.cfg diff --git a/libvirt/tests/cfg/usb_device.cfg b/libvirt/tests/cfg/usb/usb_device.cfg similarity index 95% rename from libvirt/tests/cfg/usb_device.cfg rename to libvirt/tests/cfg/usb/usb_device.cfg index 4928e88485e..a9f11b03844 100644 --- a/libvirt/tests/cfg/usb_device.cfg +++ b/libvirt/tests/cfg/usb/usb_device.cfg @@ -68,7 +68,9 @@ - redirdev: only companion only pcie-to-pci-bridge,pci-root - pkgs_host = "usbutils,usbredir-server" + pkgs_host = "usbutils" +# pkgs_host_rhel9 = ",usbredir-server" +# pkgs_host_rhel10 = ",usbredir-tools" device_name = "redirdev" variants: - spicevmc: diff --git a/libvirt/tests/cfg/passthrough/usb/usb_passthrough.cfg b/libvirt/tests/cfg/usb/usb_passthrough.cfg similarity index 100% rename from libvirt/tests/cfg/passthrough/usb/usb_passthrough.cfg rename to libvirt/tests/cfg/usb/usb_passthrough.cfg diff --git a/libvirt/tests/cfg/virsh_cmd/domain/virsh_console.cfg b/libvirt/tests/cfg/virsh_cmd/domain/virsh_console.cfg index 6b91c0af296..b1a8fdc9434 100644 --- a/libvirt/tests/cfg/virsh_cmd/domain/virsh_console.cfg +++ b/libvirt/tests/cfg/virsh_cmd/domain/virsh_console.cfg @@ -11,6 +11,8 @@ console_password_not_root = "" update_console = "yes" console_device = "ttyS0" + aarch64: + console_device = "ttyAMA0" console_speed = "115200" variants: - normal_test: diff --git a/libvirt/tests/cfg/virsh_cmd/domain/virsh_cpu_compare.cfg b/libvirt/tests/cfg/virsh_cmd/domain/virsh_cpu_compare.cfg index bb4f3943fb6..ac2d3c68188 100644 --- a/libvirt/tests/cfg/virsh_cmd/domain/virsh_cpu_compare.cfg +++ b/libvirt/tests/cfg/virsh_cmd/domain/virsh_cpu_compare.cfg @@ -7,6 +7,7 @@ cpu_compare_feature_num = -1 cpu_compare_file_name = "cpu.xml" cpu_compare_modify_invalid = "no" + verify_guest_dmesg = no variants: - default_feature: - delete_feature: diff --git a/libvirt/tests/cfg/virsh_cmd/domain/virsh_cpu_stats.cfg b/libvirt/tests/cfg/virsh_cmd/domain/virsh_cpu_stats.cfg index e1df3c19e4e..28e0027e8bd 100644 --- a/libvirt/tests/cfg/virsh_cmd/domain/virsh_cpu_stats.cfg +++ b/libvirt/tests/cfg/virsh_cmd/domain/virsh_cpu_stats.cfg @@ -4,6 +4,7 @@ cpu_stats_vm_ref = "name" cpu_stats_options = "" start_vm = "yes" + verify_guest_dmesg = no variants: - positive_test: status_error = "no" diff --git a/libvirt/tests/cfg/virsh_cmd/domain/virsh_cpu_xml.cfg b/libvirt/tests/cfg/virsh_cmd/domain/virsh_cpu_xml.cfg index af94762f199..72c3f9ec953 100644 --- a/libvirt/tests/cfg/virsh_cmd/domain/virsh_cpu_xml.cfg +++ b/libvirt/tests/cfg/virsh_cmd/domain/virsh_cpu_xml.cfg @@ -1,5 +1,6 @@ - virsh.cpu_xml: type = virsh_cpu_xml + verify_guest_dmesg = no variants: - positive: variants: diff --git a/libvirt/tests/cfg/virsh_cmd/domain/virsh_detach_device_alias.cfg b/libvirt/tests/cfg/virsh_cmd/domain/virsh_detach_device_alias.cfg index a868a855170..bf3b6f1f813 100644 --- a/libvirt/tests/cfg/virsh_cmd/domain/virsh_detach_device_alias.cfg +++ b/libvirt/tests/cfg/virsh_cmd/domain/virsh_detach_device_alias.cfg @@ -13,8 +13,6 @@ - pci: detach_hostdev_type = "pci" index = 35 - aarch64: - pci_filter = "Host bridge" detach_hostdev_managed = "yes" controller_dict = {'type': 'pci', 'model': 'pcie-to-pci-bridge','index':'${index}'} no s390-virtio @@ -31,8 +29,8 @@ detach_redirdev_type = "spicevmc" - tcp: detach_redirdev_type = "tcp" - port = '4000' - redir_params = "{'source':'{"mode":"connect","host":"localhost","service":"${port}", "tls":"no"}'}" + port_num = '4000' + redir_params = "{'source':'{"mode":"connect","host":"localhost","service":"${port_num}", "tls":"no"}'}" - channel: variants: - spicevmc: diff --git a/libvirt/tests/cfg/virsh_cmd/domain/virsh_domfsinfo.cfg b/libvirt/tests/cfg/virsh_cmd/domain/virsh_domfsinfo.cfg index b68a7724494..c469f5ae3a0 100644 --- a/libvirt/tests/cfg/virsh_cmd/domain/virsh_domfsinfo.cfg +++ b/libvirt/tests/cfg/virsh_cmd/domain/virsh_domfsinfo.cfg @@ -11,7 +11,7 @@ - no_freezed_fs: - nfs: nfs_mount = "yes" - mount_dir = "/test" + mount_dir = "/var/test" - quiet_mode: quiet_mode = "yes" - hotplug_unplug: @@ -37,4 +37,4 @@ check_point_msg = "error: operation forbidden: read only access prevents virDomainGetFSInfo" - fs_freezed: domfsfreeze = "yes" - check_point_msg = "The command guest-get-fsinfo has been disabled for this instance;Command guest-get-fsinfo has been disabled: the agent is in frozen state" + check_point_msg = "The command guest-get-fsinfo has been disabled for this instance;Command guest-get-fsinfo has been disabled: the agent is in frozen state;Command guest-get-fsinfo has been disabled: the command is not allowed" diff --git a/libvirt/tests/cfg/virsh_cmd/domain/virsh_domiflist.cfg b/libvirt/tests/cfg/virsh_cmd/domain/virsh_domiflist.cfg index 37b2cfed6cf..178c12a2ec0 100644 --- a/libvirt/tests/cfg/virsh_cmd/domain/virsh_domiflist.cfg +++ b/libvirt/tests/cfg/virsh_cmd/domain/virsh_domiflist.cfg @@ -29,8 +29,10 @@ - virtio_iface: iface_model = "virtio" - e1000_iface: + only x86_64 iface_model = "e1000" - rtl8139_iface: + only x86_64 iface_model = "rtl8139" - iface_options: domiflist_domname_options = "name" diff --git a/libvirt/tests/cfg/virsh_cmd/domain/virsh_domiftune.cfg b/libvirt/tests/cfg/virsh_cmd/domain/virsh_domiftune.cfg index ee51b8f7ed9..af9fcc2bf40 100644 --- a/libvirt/tests/cfg/virsh_cmd/domain/virsh_domiftune.cfg +++ b/libvirt/tests/cfg/virsh_cmd/domain/virsh_domiftune.cfg @@ -42,7 +42,7 @@ - inside_boundary: inbound = 1024,1024,1024 - maximum_boundary: - inbound = 4294967,4294967,4294967 + inbound = 4194303,4194303,4194303 - with_floor: only none pre_vmstate = "shutoff" @@ -66,7 +66,7 @@ - inside_boundary: outbound = '65535,65535,65535' - maximum_boundary: - outbound = '4294967,4294967,4294967' + outbound = '4194303,4194303,4194303' variants: - options: variants: diff --git a/libvirt/tests/cfg/virsh_cmd/domain/virsh_domtime.cfg b/libvirt/tests/cfg/virsh_cmd/domain/virsh_domtime.cfg index e96298283e6..ca2e337bf9a 100644 --- a/libvirt/tests/cfg/virsh_cmd/domain/virsh_domtime.cfg +++ b/libvirt/tests/cfg/virsh_cmd/domain/virsh_domtime.cfg @@ -3,6 +3,13 @@ start_vm = no take_regular_screendumps = "no" vm_stop_duration = 10 + s390-virtio: + positive: + only get_time,with_pretty,suspend_vm,managedsave_vm + negative: + only shutdown_vm,get_time_readonly,no_agent_channel,no_agent + restore_time = no + get_local_hw = no variants: - positive: variants: diff --git a/libvirt/tests/cfg/virsh_cmd/domain/virsh_guestinfo.cfg b/libvirt/tests/cfg/virsh_cmd/domain/virsh_guestinfo.cfg index 123d89e3f2d..89d35ec66bf 100644 --- a/libvirt/tests/cfg/virsh_cmd/domain/virsh_guestinfo.cfg +++ b/libvirt/tests/cfg/virsh_cmd/domain/virsh_guestinfo.cfg @@ -1,8 +1,10 @@ - virsh.guestinfo: type = virsh_guestinfo start_vm = yes + func_supported_since_libvirt_ver = (6, 0, 0) variants: - positive: + start_vm = no start_ga = "yes" prepare_channel = "yes" variants: @@ -22,9 +24,16 @@ option = "--disk" disk_target_name = "vdb" disk_name = "vdb.img" + disk_target_bus = "virtio" serial_num = "12345678" - interface_info: option = "--interface" + - load_info: + func_supported_since_libvirt_ver = (10, 10, 0) + option = "--load" + stress_in_vm = "yes" + remove_exist_qa = "yes" + load_info_field = ["load.1m", "load.5m", "load.15m"] - negative: status_error = "yes" variants: diff --git a/libvirt/tests/cfg/virsh_cmd/domain/virsh_guestvcpus.cfg b/libvirt/tests/cfg/virsh_cmd/domain/virsh_guestvcpus.cfg index 80494b2f72e..9072b8996b1 100644 --- a/libvirt/tests/cfg/virsh_cmd/domain/virsh_guestvcpus.cfg +++ b/libvirt/tests/cfg/virsh_cmd/domain/virsh_guestvcpus.cfg @@ -8,6 +8,7 @@ take_regular_screendumps="no" vcpus_num = "20" vcpus_placement = "static" + max_test_combine = "" option = "" combine = "" error_msg = [] @@ -26,6 +27,9 @@ option = "--enable" - combine: combine = "yes" + - max_test: + status_error = "no" + max_test_combine = "yes" - error_test: status_error = "yes" variants: diff --git a/libvirt/tests/cfg/virsh_cmd/domain/virsh_hypervisor_cpu_compare.cfg b/libvirt/tests/cfg/virsh_cmd/domain/virsh_hypervisor_cpu_compare.cfg index 4f1984b8884..48e2ffa5ede 100644 --- a/libvirt/tests/cfg/virsh_cmd/domain/virsh_hypervisor_cpu_compare.cfg +++ b/libvirt/tests/cfg/virsh_cmd/domain/virsh_hypervisor_cpu_compare.cfg @@ -70,8 +70,7 @@ - capa_xml: no s390-virtio, aarch64 compare_file_type = "capa_xml" - status_error = "yes" - msg_pattern = "incompatible" + status_error = "no" - cpu_xml: extract_mode = "yes" variants: @@ -81,8 +80,7 @@ - f_capa_xml: no s390-virtio, aarch64 compare_file_type = "capa_xml" - status_error = "yes" - msg_pattern = "incompatible" + status_error = "no" - f_domcapa_xml: compare_file_type = "domcapa_xml" msg_pattern = "identical" diff --git a/libvirt/tests/cfg/virsh_cmd/domain/virsh_iothreadadd.cfg b/libvirt/tests/cfg/virsh_cmd/domain/virsh_iothreadadd.cfg index 70fccddddcd..582b6d0629c 100644 --- a/libvirt/tests/cfg/virsh_cmd/domain/virsh_iothreadadd.cfg +++ b/libvirt/tests/cfg/virsh_cmd/domain/virsh_iothreadadd.cfg @@ -10,6 +10,7 @@ iothreadpins = "2:1 1:0-1" iothreads = "2" iothread_id = "6" + start_vm = 'no' variants: - normal_test: status_error = "no" diff --git a/libvirt/tests/cfg/virsh_cmd/domain/virsh_iothreaddel.cfg b/libvirt/tests/cfg/virsh_cmd/domain/virsh_iothreaddel.cfg index 9219d4b8f03..9dbe54e2f3f 100644 --- a/libvirt/tests/cfg/virsh_cmd/domain/virsh_iothreaddel.cfg +++ b/libvirt/tests/cfg/virsh_cmd/domain/virsh_iothreaddel.cfg @@ -10,6 +10,7 @@ iothreads = "2" iothreadpins = "2:1 1:0-1" iothread_id = "2" + start_vm = 'no' variants: - normal_test: status_error = "no" diff --git a/libvirt/tests/cfg/virsh_cmd/domain/virsh_iothreadinfo.cfg b/libvirt/tests/cfg/virsh_cmd/domain/virsh_iothreadinfo.cfg index 5eb1dafd25c..dc7ecb449fc 100644 --- a/libvirt/tests/cfg/virsh_cmd/domain/virsh_iothreadinfo.cfg +++ b/libvirt/tests/cfg/virsh_cmd/domain/virsh_iothreadinfo.cfg @@ -9,6 +9,7 @@ # The format of iothreadpins is IOTHEADID:CPUSET iothreads = "2" iothreadpins = "2:1 1:0-1" + start_vm = 'no' variants: - normal_test: status_error = "no" diff --git a/libvirt/tests/cfg/virsh_cmd/domain/virsh_iothreadpin.cfg b/libvirt/tests/cfg/virsh_cmd/domain/virsh_iothreadpin.cfg index 66396d8f780..f05f60dcf3b 100644 --- a/libvirt/tests/cfg/virsh_cmd/domain/virsh_iothreadpin.cfg +++ b/libvirt/tests/cfg/virsh_cmd/domain/virsh_iothreadpin.cfg @@ -9,6 +9,7 @@ iothreads = "2" iothreadpins = "2:1 1:0-1" iothread_id = "2" + start_vm = 'no' variants: - normal_test: cpuset = "1" diff --git a/libvirt/tests/cfg/virsh_cmd/domain/virsh_managedsave.cfg b/libvirt/tests/cfg/virsh_cmd/domain/virsh_managedsave.cfg index af4c5b71855..8a05992ed08 100644 --- a/libvirt/tests/cfg/virsh_cmd/domain/virsh_managedsave.cfg +++ b/libvirt/tests/cfg/virsh_cmd/domain/virsh_managedsave.cfg @@ -43,12 +43,17 @@ - cpu_mode: managedsave_cpumode = "yes" cpu_mode = "host-model" + aarch64: + cpu_mode = "host-passthrough" cpu_match = "exact" cpu_fallback = "forbid" cpu_topology_sockets = "2" cpu_topology_cores = "4" cpu_topology_threads = "2" vcpu_nums = "16" + s390-virtio: + cpu_topology_threads = "1" + vcpu_nums = "8" - undefine: managedsave_undefine = "yes" - bypass_cache: @@ -75,8 +80,6 @@ - rm_test: remove_test = 'yes' variants: - - not_saved_with_file: - case = 'not_saved_with_file' - not_saved_without_file: case = 'not_saved_without_file' - saved_without_file: diff --git a/libvirt/tests/cfg/virsh_cmd/domain/virsh_managedsave_restore.cfg b/libvirt/tests/cfg/virsh_cmd/domain/virsh_managedsave_restore.cfg new file mode 100644 index 00000000000..817249794b6 --- /dev/null +++ b/libvirt/tests/cfg/virsh_cmd/domain/virsh_managedsave_restore.cfg @@ -0,0 +1,19 @@ +- virsh.managedsave_restore: + type = virsh_managedsave_restore + start_vm = yes + variants: + - managedsaved: + vm_managedsaved = yes + - not_managedsaved: + only no_file + vm_managedsaved = no + variants: + - no_file: + file_state = nonexist + - corrupt_file: + file_state = corrupt + expected_log = "Ignoring incomplete managed state" + - occupied_file: + file_state = occupied + need_vm2 = yes + expected_cmd_err = "Requested operation is not valid" diff --git a/libvirt/tests/cfg/virsh_cmd/domain/virsh_managedsave_special_name.cfg b/libvirt/tests/cfg/virsh_cmd/domain/virsh_managedsave_special_name.cfg new file mode 100644 index 00000000000..19aae3ca0e8 --- /dev/null +++ b/libvirt/tests/cfg/virsh_cmd/domain/virsh_managedsave_special_name.cfg @@ -0,0 +1,11 @@ +- virsh.managedsave_special_name: + type = "virsh_managedsave_special_name" + start_vm = "no" + variants: + - non_acsii: + vmname = kīмсhīkīмсhīkīмсhī-∨м + name_display = 'k\xff\xff\xff\xff\xff\xffh\xff\xffk\xff\xff\xff\xff\xff\xffh\xff\xffk\xff\xff\xff\xff\xff\xffh\xff\xff-\xff\xff\xff\xff\xff' + - long: + vmname = 12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012 + name_display = ${vmname} + diff --git a/libvirt/tests/cfg/virsh_cmd/domain/virsh_managedsave_undefine.cfg b/libvirt/tests/cfg/virsh_cmd/domain/virsh_managedsave_undefine.cfg new file mode 100644 index 00000000000..872210d7b51 --- /dev/null +++ b/libvirt/tests/cfg/virsh_cmd/domain/virsh_managedsave_undefine.cfg @@ -0,0 +1,3 @@ +- virsh.managedsave_undefine: + type = "virsh_managedsave_undefine" + start_vm = "yes" diff --git a/libvirt/tests/cfg/virsh_cmd/domain/virsh_memtune.cfg b/libvirt/tests/cfg/virsh_cmd/domain/virsh_memtune.cfg index 079e35d2014..df4739d6828 100644 --- a/libvirt/tests/cfg/virsh_cmd/domain/virsh_memtune.cfg +++ b/libvirt/tests/cfg/virsh_cmd/domain/virsh_memtune.cfg @@ -1,5 +1,6 @@ - virsh.memtune: install setup image_copy unattended_install.cdrom type = virsh_memtune + start_vm = no # Values are in KiB variants: - positive_test: @@ -22,6 +23,10 @@ mt_hard_limit = 1111111 mt_soft_limit = 222222 mt_swap_hard_limit = 3333333 + aarch64: + mt_hard_limit = 4194304 + mt_soft_limit = 8388608 + mt_swap_hard_limit = 12582912 - step_increment: mt_step_mem = "yes" mt_base_mem = 1048576 diff --git a/libvirt/tests/cfg/virsh_cmd/domain/virsh_reboot.cfg b/libvirt/tests/cfg/virsh_cmd/domain/virsh_reboot.cfg index 15449abafb5..58ada50b7da 100644 --- a/libvirt/tests/cfg/virsh_cmd/domain/virsh_reboot.cfg +++ b/libvirt/tests/cfg/virsh_cmd/domain/virsh_reboot.cfg @@ -15,7 +15,7 @@ - no_mode: - acpi_mode: reboot_mode = "acpi" - no ppc64,ppc64le + no ppc64,ppc64le,s390-virtio - agent_mode: no lxc reboot_mode = "agent" diff --git a/libvirt/tests/cfg/virsh_cmd/domain/virsh_restore.cfg b/libvirt/tests/cfg/virsh_cmd/domain/virsh_restore.cfg index 477de656549..9622c2c8be8 100644 --- a/libvirt/tests/cfg/virsh_cmd/domain/virsh_restore.cfg +++ b/libvirt/tests/cfg/virsh_cmd/domain/virsh_restore.cfg @@ -22,6 +22,9 @@ restore_extra_param = "--running" - xml_option: restore_extra_param = "--xml" + os_update_dict = '{"boots": ["cdrom"]}' + s390-virtio: + os_update_dict = '{"bootmenu_enable": "yes"}' - xml_option_dac: only non_acl restore_extra_param = "--xml" diff --git a/libvirt/tests/cfg/virsh_cmd/domain/virsh_save_image_define.cfg b/libvirt/tests/cfg/virsh_cmd/domain/virsh_save_image_define.cfg index 305d5fc6bdf..b37ede77b15 100644 --- a/libvirt/tests/cfg/virsh_cmd/domain/virsh_save_image_define.cfg +++ b/libvirt/tests/cfg/virsh_cmd/domain/virsh_save_image_define.cfg @@ -2,6 +2,11 @@ type = virsh_save_image_define vm_save = "vm.save" kill_vm_on_error = "no" + xml_before = "" + xml_after = "" + s390-virtio: + xml_before = "" + xml_after = "" variants: - running: restore_state = "running" diff --git a/libvirt/tests/cfg/virsh_cmd/domain/virsh_save_image_edit.cfg b/libvirt/tests/cfg/virsh_cmd/domain/virsh_save_image_edit.cfg index 90ed44f1ad9..984b512d85c 100644 --- a/libvirt/tests/cfg/virsh_cmd/domain/virsh_save_image_edit.cfg +++ b/libvirt/tests/cfg/virsh_cmd/domain/virsh_save_image_edit.cfg @@ -3,6 +3,11 @@ vm_save = "vm.save" kill_vm_on_error = "no" take_regular_screendumps = "no" + xml_before = "" + xml_after = "" + s390-virtio: + xml_before = "" + xml_after = "" variants: - no_option: restore_state = "running" diff --git a/libvirt/tests/cfg/virsh_cmd/domain/virsh_set_user_password.cfg b/libvirt/tests/cfg/virsh_cmd/domain/virsh_set_user_password.cfg index 7aa4ff3d5c4..5c89f76669b 100644 --- a/libvirt/tests/cfg/virsh_cmd/domain/virsh_set_user_password.cfg +++ b/libvirt/tests/cfg/virsh_cmd/domain/virsh_set_user_password.cfg @@ -36,4 +36,4 @@ err_msg = "error: failed to get domain 'not_existed_domain'" - not_existed_user: set_user_name = "not_existed_user" - err_msg = "error: internal error: unable to execute QEMU agent command 'guest-set-user-password': child process has failed to set user password" + err_msg = "error: (internal error|guest agent command failed): unable to execute QEMU agent command 'guest-set-user-password': child process has failed to set user password" diff --git a/libvirt/tests/cfg/virsh_cmd/domain/virsh_sosreport.cfg b/libvirt/tests/cfg/virsh_cmd/domain/virsh_sosreport.cfg new file mode 100644 index 00000000000..5b4bc441f1a --- /dev/null +++ b/libvirt/tests/cfg/virsh_cmd/domain/virsh_sosreport.cfg @@ -0,0 +1,10 @@ +- io-github-autotest-libvirt.virsh.sosreport: + virt_test_type = libvirt + provider = io-github-autotest-libvirt + type = virsh_sosreport + take_regular_screendumps = "no" + variants: + - generate_sos_report: + generate_sos_report = "yes" + - access_pool_stats: + access_pool_stats = "yes" diff --git a/libvirt/tests/cfg/virsh_cmd/domain/virsh_start.cfg b/libvirt/tests/cfg/virsh_cmd/domain/virsh_start.cfg index 4b4e2efcc38..68bf04daf1d 100644 --- a/libvirt/tests/cfg/virsh_cmd/domain/virsh_start.cfg +++ b/libvirt/tests/cfg/virsh_cmd/domain/virsh_start.cfg @@ -38,6 +38,10 @@ vs_opt = "--force-boot" - audit_log_search: audit_log_search_string = "AVC" + libvirtd_error_message = "warning : virCgroupMoveTask.*no vm cgroup in controller" + message_log_file = "/var/log/messages" + tmp_auvirt_event_log = "/var/lib/libvirt/images/auvirt.log" + auvirt_error_msg = "%s.*failed" - status_error_yes: status_error = "yes" variants: diff --git a/libvirt/tests/cfg/virsh_cmd/domain/virsh_vcpuinfo.cfg b/libvirt/tests/cfg/virsh_cmd/domain/virsh_vcpuinfo.cfg index 3fcae002557..96eaaf01026 100644 --- a/libvirt/tests/cfg/virsh_cmd/domain/virsh_vcpuinfo.cfg +++ b/libvirt/tests/cfg/virsh_cmd/domain/virsh_vcpuinfo.cfg @@ -8,6 +8,7 @@ kill_vm = "yes" # Test is not Guest OS dependent kill_vm_gracefully = "no" + verify_guest_dmesg = no variants: - normal_test: status_error = "no" diff --git a/libvirt/tests/cfg/virsh_cmd/host/virsh_cpu_models.cfg b/libvirt/tests/cfg/virsh_cmd/host/virsh_cpu_models.cfg index db5ad3843d5..c73cb9dd57a 100644 --- a/libvirt/tests/cfg/virsh_cmd/host/virsh_cpu_models.cfg +++ b/libvirt/tests/cfg/virsh_cmd/host/virsh_cpu_models.cfg @@ -10,7 +10,16 @@ variants: - auto_get_arch: - specific_arch: + only local_host + check_qemu_cpu_supported_cmd = "/usr/libexec/qemu-kvm -cpu help | awk '/Available CPUs/,/Recognized CPUID flags/' | grep '^ ' | awk '{print $1}'" + skip_list = ['base', 'host', 'max'] cpu_arch = "x86_64" + s390-virtio: + cpu_arch = "s390" + msg = "all CPU models are accepted" + aarch64: + cpu_arch = "aarch64" + msg = "all CPU models are accepted" variants: - local_host: - remote_host: diff --git a/libvirt/tests/cfg/virsh_cmd/host/virsh_freepages.cfg b/libvirt/tests/cfg/virsh_cmd/host/virsh_freepages.cfg index 9225f070bec..11539c77ae6 100644 --- a/libvirt/tests/cfg/virsh_cmd/host/virsh_freepages.cfg +++ b/libvirt/tests/cfg/virsh_cmd/host/virsh_freepages.cfg @@ -6,6 +6,7 @@ variants: - positive_test: status_error = "no" + hugepage_allocation_dict = {'64':256, '2048':64, '32768':8, '524288':4, '1048576':2, '16777216':1} variants: - option_all: freepages_option = "--all" @@ -17,20 +18,60 @@ freepages_pagesize = "EACH" - pagesize_2M: freepages_pagesize = "2M" + pagesize_kb = '2048' - pagesize_2048: freepages_pagesize = "2048" + pagesize_kb = '2048' - pagesize_2048K: freepages_pagesize = "2048K" + pagesize_kb = '2048' - pagesize_2048kib: freepages_pagesize = "2048kib" + pagesize_kb = '2048' - pagesize_1G: freepages_pagesize = "1G" + pagesize_kb = '1048576' - pagesize_1048576: freepages_pagesize = "1048576" + pagesize_kb = '1048576' - pagesize_1048576K: freepages_pagesize = "1048576K" + pagesize_kb = '1048576' - pagesize_1048576KIB: freepages_pagesize = "1048576KIB" + pagesize_kb = '1048576' + - pagesize_524288: + only aarch64 + freepages_pagesize = "524288" + pagesize_kb = '524288' + - pagesize_512M: + only aarch64 + freepages_pagesize = "512M" + pagesize_kb = '524288' + - pagesize_64: + only aarch64 + freepages_pagesize = "64" + pagesize_kb = '64' + - pagesize_64K: + only aarch64 + freepages_pagesize = "64K" + pagesize_kb = '64' + - pagesize_32768: + only aarch64 + freepages_pagesize = "32768" + pagesize_kb = '32768' + - pagesize_32M: + only aarch64 + freepages_pagesize = "32M" + pagesize_kb = '32768' + - pagesize_16G: + only aarch64 + freepages_pagesize = "16G" + pagesize_kb = '16777216' + - pagesize_16777216: + only aarch64 + freepages_pagesize = "16777216" + pagesize_kb = '16777216' - negative_test: status_error = "yes" variants: @@ -47,3 +88,4 @@ - invalid_page_size: freepages_cellno = "0" freepages_pagesize = "-1" + diff --git a/libvirt/tests/cfg/virsh_cmd/host/virsh_hypervisor_cpu_models.cfg b/libvirt/tests/cfg/virsh_cmd/host/virsh_hypervisor_cpu_models.cfg new file mode 100644 index 00000000000..45a1d711f12 --- /dev/null +++ b/libvirt/tests/cfg/virsh_cmd/host/virsh_hypervisor_cpu_models.cfg @@ -0,0 +1,30 @@ +- virsh.hypervisor_cpu_models: + type = virsh_hypervisor_cpu_models + func_supported_since_libvirt_ver = (11, 2, 0) + options = "" + start_vm = no + variants: + - positive_test: + status_error = "no" + variants: + - default: + - all: + options = "--all" + - valid_parameter_values: + s390-virtio: + options = "--all --arch s390x --machine s390-ccw-virtio --emulator /usr/libexec/qemu-kvm --virttype kvm" + x86_64: + options = "--all --arch x86_64 --machine q35 --emulator /usr/libexec/qemu-kvm --virttype kvm" + aarch64: + options = "--all --arch aarch64 --machine virt --emulator /usr/libexec/qemu-kvm --virttype kvm" + - negative_test: + status_error = "yes" + variants: + - invalid_arch: + options = "--arch invalid" + - invalid_virttype: + options = "--virttype invalid" + - invalid_machine: + options = "--machine invalid" + - invalid_emulator: + options = "--virttype invalid" diff --git a/libvirt/tests/cfg/virsh_cmd/host/virsh_nodeinfo.cfg b/libvirt/tests/cfg/virsh_cmd/host/virsh_nodeinfo.cfg index 025034b28d7..fa07d7c02aa 100644 --- a/libvirt/tests/cfg/virsh_cmd/host/virsh_nodeinfo.cfg +++ b/libvirt/tests/cfg/virsh_cmd/host/virsh_nodeinfo.cfg @@ -4,6 +4,9 @@ start_vm = no virsh_node_options = "" status_error = "no" + check_frequency = yes + aarch64: + check_frequency = no variants test_case: - no_option: libvirtd = "on" diff --git a/libvirt/tests/cfg/virsh_cmd/monitor/virsh_domstate.cfg b/libvirt/tests/cfg/virsh_cmd/monitor/virsh_domstate.cfg index 7a4a78a4ffc..5a46a57a8a8 100644 --- a/libvirt/tests/cfg/virsh_cmd/monitor/virsh_domstate.cfg +++ b/libvirt/tests/cfg/virsh_cmd/monitor/virsh_domstate.cfg @@ -42,8 +42,12 @@ variants: - oncrash_destroy: domstate_vm_oncrash = "destroy" + aarch64: + func_supported_since_libvirt_ver = (9, 1, 0) - oncrash_restart: domstate_vm_oncrash = "restart" + aarch64: + func_supported_since_libvirt_ver = (9, 1, 0) - oncrash_preserve: domstate_vm_oncrash = "preserve" variants: @@ -55,10 +59,14 @@ memory_value = "2097152" memory_unit = "KiB" domstate_vm_oncrash = "coredump-destroy" + aarch64: + func_supported_since_libvirt_ver = (9, 1, 0) - oncrash_coredump_restart: memory_value = "2097152" memory_unit = "KiB" domstate_vm_oncrash = "coredump-restart" + aarch64: + func_supported_since_libvirt_ver = (9, 1, 0) - oncrash_rename_restart: domstate_vm_oncrash = "rename-restart" variants: diff --git a/libvirt/tests/cfg/virsh_cmd/network/virsh_net_update.cfg b/libvirt/tests/cfg/virsh_cmd/network/virsh_net_update.cfg index 63318918b06..236b876f0b1 100644 --- a/libvirt/tests/cfg/virsh_cmd/network/virsh_net_update.cfg +++ b/libvirt/tests/cfg/virsh_cmd/network/virsh_net_update.cfg @@ -322,6 +322,7 @@ network_section = "dns-host" variants: - modify: + no dns_host,dns_txt update_command = "modify" error_type = "modify" - dns_disable: diff --git a/libvirt/tests/cfg/virsh_cmd/nodedev/virsh_nodedev_dumpxml_chain.cfg b/libvirt/tests/cfg/virsh_cmd/nodedev/virsh_nodedev_dumpxml_chain.cfg index 1fa84e9e9bb..3403d36106a 100644 --- a/libvirt/tests/cfg/virsh_cmd/nodedev/virsh_nodedev_dumpxml_chain.cfg +++ b/libvirt/tests/cfg/virsh_cmd/nodedev/virsh_nodedev_dumpxml_chain.cfg @@ -1,8 +1,9 @@ -- virsh.nodedev_dumpxml_chain: +- virsh.nodedev_dumpxml.chain: type = virsh_nodedev_dumpxml_chain vms = "" main_vm = "" start_vm = "no" + device_ids = 0.0.1234,0.0.4567 variants: - device_type_dasd: only s390-virtio diff --git a/libvirt/tests/cfg/virsh_cmd/nodedev/virsh_nodedev_list.cfg b/libvirt/tests/cfg/virsh_cmd/nodedev/virsh_nodedev_list.cfg index 318ebb8c2f8..7e0d0cf166a 100644 --- a/libvirt/tests/cfg/virsh_cmd/nodedev/virsh_nodedev_list.cfg +++ b/libvirt/tests/cfg/virsh_cmd/nodedev/virsh_nodedev_list.cfg @@ -17,6 +17,7 @@ comparison_mode = exact s390-virtio: comparison_mode = similar + remove_scm_device = "yes" - multi_cap_option: cap_option = multi - long_cap_option: diff --git a/libvirt/tests/cfg/virsh_cmd/snapshot/virsh_snapshot_create_as.cfg b/libvirt/tests/cfg/virsh_cmd/snapshot/virsh_snapshot_create_as.cfg index aa9597c6215..102c992f879 100644 --- a/libvirt/tests/cfg/virsh_cmd/snapshot/virsh_snapshot_create_as.cfg +++ b/libvirt/tests/cfg/virsh_cmd/snapshot/virsh_snapshot_create_as.cfg @@ -35,9 +35,6 @@ domain_state = "paused" - running_domain: domain_state = "running" - - autodestroy_domain: - create_autodestroy = "yes" - snap_createas_opts = "--disk-only" - quiesce_without_unix_channel: unix_channel = "no" snap_createas_opts = "--quiesce --disk-only" @@ -162,6 +159,10 @@ snap_createas_opts = "--print-xml --name tt --description hello --disk-only" diskspec_opts1 = "vda,snapshot=internal,driver=raw,file=test1.img" diskspec_opts2 = "vdb,snapshot=no" + - autodestroy_domain: + status_error = "yes" + create_autodestroy = "yes" + snap_createas_opts = "--disk-only" variants: - file_disk: variants: diff --git a/libvirt/tests/cfg/virsh_cmd/virsh_qemu_cmdline_core.cfg b/libvirt/tests/cfg/virsh_cmd/virsh_qemu_cmdline_core.cfg new file mode 100644 index 00000000000..fcd5e3019b1 --- /dev/null +++ b/libvirt/tests/cfg/virsh_cmd/virsh_qemu_cmdline_core.cfg @@ -0,0 +1,6 @@ +- io-github-autotest-libvirt.virsh.qemu_cmdline_core: + virt_test_type = libvirt + provider = io-github-autotest-libvirt + type = virsh_qemu_cmdline_core + variants: + - qemu_cmdline_more_cpus: diff --git a/libvirt/tests/cfg/virt_cmd/virt_xml_validate.cfg b/libvirt/tests/cfg/virt_cmd/virt_xml_validate.cfg index 45a5228c81b..491960ddc99 100644 --- a/libvirt/tests/cfg/virt_cmd/virt_xml_validate.cfg +++ b/libvirt/tests/cfg/virt_cmd/virt_xml_validate.cfg @@ -28,3 +28,6 @@ secret_volume = "/var/lib/libvirt/images/virt_xml_validate.secret" - interface: schema = "interface" + - domcapabilities: + func_supported_since_libvirt_ver = (10, 10, 0) + schema = "domcapabilities" diff --git a/libvirt/tests/cfg/virtio/virtio_page_per_vq.cfg b/libvirt/tests/cfg/virtio/virtio_page_per_vq.cfg index a06382e9159..eee6c38c750 100644 --- a/libvirt/tests/cfg/virtio/virtio_page_per_vq.cfg +++ b/libvirt/tests/cfg/virtio/virtio_page_per_vq.cfg @@ -1,7 +1,7 @@ - virtio_attributes.virtio_page_per_vq: type = virtio_page_per_vq start_vm = no - driver_dict = {'driver': {'page_per_vq': 'on'}} + driver_dict = {'driver': {'page_per_vq': 'on', 'packed': 'on'}} ping_outside = 'www.google.com' func_supported_since_libvirt_ver = (8, 5, 0) no s390-virtio @@ -15,7 +15,7 @@ disk_image = '/var/lib/avocado/data/avocado-vt/images/jeos-27-x86_64.qcow2' aarch64: disk_image = '/var/lib/avocado/data/avocado-vt/images/jeos-27-aarch64.qcow2' - driver_dict = {'driver': {'name': 'qemu', 'type': 'qcow2', 'page_per_vq': 'on'}} + driver_dict = {'driver': {'name': 'qemu', 'type': 'qcow2', 'page_per_vq': 'on', 'packed': 'on'}} device_dict = {'device': 'disk', 'type_name': 'file', **${driver_dict}, 'source': {'attrs': {'file': '${disk_image}'}}, 'target': {'dev': 'vdb', 'bus': 'virtio'}} - controller: variants: @@ -27,7 +27,7 @@ controller_type = "virtio-serial" device_dict = {**${driver_dict}, 'type': 'virtio-serial', 'index': '0', 'type_name': 'virtio-serial'} - interface: - driver_dict = {'driver': {'driver_attr': {'page_per_vq': 'on'}}} + driver_dict = {'driver': {'driver_attr': {'page_per_vq': 'on', 'packed': 'on'}}} device_dict = {'type_name': 'network', 'model': 'virtio', 'source': {'network': 'default'}, **${driver_dict}, 'mac_address': '52:54:00:26:08:7b'} - rng: device_dict = {'backend': {'backend_dev': '/dev/urandom', 'backend_model': 'random'}, **${driver_dict}, 'rng_model': 'virtio'} @@ -41,10 +41,10 @@ - mouse: - tablet: - passthrough: - device_dict = {**${device_dict}, 'source_evdev': '/dev/input/event1'} + device_dict = {**${device_dict}, 'source_evdev': '%s'} - video: only default_start device_dict = {'model_type': 'virtio', **${driver_dict}, 'model_heads': '1'} - filesystem: - driver_dict = {'driver': {'type': 'virtiofs', 'page_per_vq': 'on'}} - device_dict = {'source': {'dir': '/tmp'}, **${driver_dict}, 'type_name': 'mount', 'accessmode': 'passthrough', 'target': {'dir': 'mount_tag'}, 'binary': {'xattr': 'on', 'path': '/usr/libexec/virtiofsd', 'cache_mode': 'none'}} + driver_dict = {'driver': {'type': 'virtiofs', 'page_per_vq': 'on', 'packed': 'on'}} + device_dict = {'source': {'dir': '/tmp'}, **${driver_dict}, 'type_name': 'mount', 'accessmode': 'passthrough', 'target': {'dir': 'mount_tag'}, 'binary': {'xattr': 'on', 'path': '/usr/libexec/virtiofsd', 'cache_mode': 'always'}} diff --git a/libvirt/tests/cfg/virtio_transitional/virtio_transitional_blk.cfg b/libvirt/tests/cfg/virtio_transitional/virtio_transitional_blk.cfg index 610be54b504..962d46dc4ce 100644 --- a/libvirt/tests/cfg/virtio_transitional/virtio_transitional_blk.cfg +++ b/libvirt/tests/cfg/virtio_transitional/virtio_transitional_blk.cfg @@ -1,6 +1,7 @@ - virtio_transitional_blk: type = virtio_transitional_blk start_vm = no + no s390-virtio Windows: get_device_cmd = "wmic diskdrive get index, size" get_device_pattern = "^\d+" @@ -10,11 +11,9 @@ virtio_model = "virtio" controller_model = "virtio-scsi" - virtio_transitional: - no s390-virtio virtio_model = "virtio-transitional" controller_model = ${virtio_model} - virtio_non_transitional: - no s390-virtio virtio_model = "virtio-non-transitional" variants: - boot_test: @@ -45,7 +44,6 @@ at_disk_bus = scsi variants: - @default: - only q35 only boot_test no virtio_transitional - rhel6_guest: diff --git a/libvirt/tests/cfg/virtio_transitional/virtio_transitional_mem_balloon.cfg b/libvirt/tests/cfg/virtio_transitional/virtio_transitional_mem_balloon.cfg index 8897edf68b4..1d4fd8f2ad9 100644 --- a/libvirt/tests/cfg/virtio_transitional/virtio_transitional_mem_balloon.cfg +++ b/libvirt/tests/cfg/virtio_transitional/virtio_transitional_mem_balloon.cfg @@ -1,7 +1,10 @@ - virtio_transitional_mem_balloon: type = virtio_transitional_mem_balloon - only q35 start_vm = no + vm_memory = 8388608 + detect_cmd = 'lspci |grep balloon' + s390-virtio: + detect_cmd = 'lscss |grep "3832/05"' variants: - virtio: virtio_model = "virtio" @@ -13,7 +16,9 @@ virtio_model = "virtio-non-transitional" variants: - @default: + no virtio_transitional - rhel6_guest: + only q35 os_variant = rhel6 image_path = images/rhel6-x86_64-latest.qcow2 guest_src_url = "http://download.libvirt.redhat.com/libvirt-CI-resources/RHEL-6.10-x86_64-latest.qcow2" diff --git a/libvirt/tests/cfg/virtio_transitional/virtio_transitional_nic.cfg b/libvirt/tests/cfg/virtio_transitional/virtio_transitional_nic.cfg index 23ccd230968..9e69346f6c5 100644 --- a/libvirt/tests/cfg/virtio_transitional/virtio_transitional_nic.cfg +++ b/libvirt/tests/cfg/virtio_transitional/virtio_transitional_nic.cfg @@ -18,6 +18,9 @@ variants: - virtio: virtio_model = "virtio" + s390-virtio: + check_pci_bridge = no + bridge_controller_needed = no - virtio_transitional: no s390-virtio virtio_model = "virtio-transitional" @@ -26,10 +29,10 @@ virtio_model = "virtio-non-transitional" variants: - @default: - only q35 only boot_test no virtio_transitional - rhel6_guest: + only q35 os_variant = rhel6 only virtio_transitional no Windows diff --git a/libvirt/tests/cfg/virtio_transitional/virtio_transitional_rng.cfg b/libvirt/tests/cfg/virtio_transitional/virtio_transitional_rng.cfg index 9795928c29d..489eca77984 100644 --- a/libvirt/tests/cfg/virtio_transitional/virtio_transitional_rng.cfg +++ b/libvirt/tests/cfg/virtio_transitional/virtio_transitional_rng.cfg @@ -2,6 +2,9 @@ type = virtio_transitional_rng start_vm = no check_cmd = 'hexdump /dev/hwrng|head -2' + s390-virtio: + bridge_controller_needed = no + variants: - virtio: virtio_model = "virtio" @@ -18,7 +21,6 @@ hotplug = yes variants: - @default: - only q35 only boot_test no virtio_transitional disk_model = ${virtio_model} diff --git a/libvirt/tests/cfg/virtio_transitional/virtio_transitional_vsock.cfg b/libvirt/tests/cfg/virtio_transitional/virtio_transitional_vsock.cfg index c647734bd4a..c925cb0672d 100644 --- a/libvirt/tests/cfg/virtio_transitional/virtio_transitional_vsock.cfg +++ b/libvirt/tests/cfg/virtio_transitional/virtio_transitional_vsock.cfg @@ -4,14 +4,13 @@ start_vm = no addr_pattern = '\d\d:\d\d\.\d' device_pattern = 'Communication controller: Red Hat.* Device | Communication controller: Red Hat.* socket' + no s390-virtio variants: - virtio: virtio_model = "virtio" - virtio_transitional: - no s390-virtio virtio_model = "virtio-transitional" - virtio_non_transitional: - no s390-virtio virtio_model = "virtio-non-transitional" variants: - boot_test: @@ -20,7 +19,6 @@ hotplug = yes variants: - @default: - only q35 only boot_test no virtio_transitional - rhel6_guest: diff --git a/libvirt/tests/cfg/virtiofs/virtiofs.cfg b/libvirt/tests/cfg/virtiofs/virtiofs.cfg new file mode 100644 index 00000000000..1668004baff --- /dev/null +++ b/libvirt/tests/cfg/virtiofs/virtiofs.cfg @@ -0,0 +1,210 @@ +- virtiofs: + type = virtiofs + take_regular_screendumps = "no" + vms = "avocado-vt-vm1" + start_vm = no + cache_mode = "auto" + virtiofsd_path = "/usr/libexec/virtiofsd" + queue_size = "512" + driver_type = "virtiofs" + source_dir_prefix = "/dir" + target_prefix = "mount_tag" + vcpus_per_cell = 2 + extra_hugepages = 128 + pseries: + vcpus_per_cell = 5 + aarch64: + extra_hugepages = 0 + s390-virtio: + with_numa = no + variants: + - positive_test: + variants: + - multiple_devices: + variants @launched: + - internal: + - external: + launch_mode = "externally" + variants @devices: + - one_device: + fs_num = 1 + - two_devices: + only one_guest + fs_num = 2 + - retry_two_devices: + only one_guest + only nop.file_backed..internal + omit_dir_at_first = "yes" + variants @guests: + - one_guest: + - two_guests: + vms = "avocado-vt-vm1 avocado-vt-vm2" + variants @memory_backing: + - file_backed: + with_hugepages = no + - memfd_backed: + with_hugepages = no + with_memfd = "yes" + - hugepages_backed: + with_hugepages = "yes" + s390-virtio: + kvm_module_parameters = "hpage=1" + variants @attachment: + - nop: + - coldplug_unplug: + only file_backed + only one_guest.one_device + coldplug = "yes" + - hotplug_unplug: + hotplug_unplug = "yes" + variants @reference: + - with_alias: + only default_parameters + only file_backed.one_guest.one_device + detach_device_alias = "yes" + - no_alias: + detach_device_alias = "no" + variants @parameter_set: + - default_parameters: + xattr = "" + cache_mode = "none" + thread_pool_size = + queue_size = + sandbox_mode = "none" + - non_default_parameters_1: + only hotplug_unplug + xattr = "on" + cache_mode = "auto" + thread_pool_size = + queue_size = + sandbox_mode = "namespace" + - non_default_parameters_2: + only hotplug_unplug + xattr = "on" + cache_mode = "always" + thread_pool_size = 16 + openfiles = "yes" + queue_size = 512 + sandbox_mode = "chroot" + - single_device: + fs_num = 1 + with_hugepages = no + variants @launched: + - internal: + xattr = "" + cache_mode = "none" + thread_pool_size = + queue_size = + sandbox_mode = "none" + - external: + launch_mode = "externally" + queue_size = + variants: + - lifecycle: + variants: + - managedsave: + no external + lifecycle_scenario = "managedsave" + bug_url = https://issues.redhat.com/browse/RHEL-50542 + - restart_service: + func_supported_since_libvirt_ver = (9, 2, 0) + lifecycle_scenario = "restart_service" + setup_mem = True + source_dir = "/var/tmp/mount_tag0" + dev_type = "filesystem" + vm_attrs = {'mb': {"source_type":"file", 'access_mode': 'shared'}} + fs_dict = {'accessmode':'passthrough', 'driver': {'type': 'virtiofs', 'queue':'512'}, 'source':{'dir': '${source_dir}'}, "target": {'dir': 'mount_tag0'}, 'binary': {'path': '/usr/libexec/virtiofsd', 'xattr': 'on','cache_mode':'always'}} + - reboot: + lifecycle_scenario = "reboot" + - shutdown_start: + no external + lifecycle_scenario = "shutdown_start" + - edit_start: + no external + lifecycle_scenario = "edit_start" + - destroy_start: + no external + lifecycle_scenario = "destroy_start" + stress_script = "#!/usr/bin/python3;import os;while True:; os.open("%s/moo", os.O_CREAT | os.O_RDWR); os.unlink("%s/moo");" + bug_url = "https://bugzilla.redhat.com/show_bug.cgi?id=1940276" + - suspend_resume: + lifecycle_scenario = "suspend_resume" + - qemu_config: + only internal + variants: + - virtiofsd_debug_log: + - stdio_handler: + variants: + - file: + stdio_handler = "file" + - logd: + stdio_handler = "logd" + - socket_file_check: + socket_file_checking = "yes" + - parameters: + variants: + - xattr: + only internal + variants: + - xattr_not_set: + xattr = "" + - xattr_on: + xattr = "on" + - xattr_off: + xattr = "off" + - cache_mode: + only internal + variants: + - cache_mode_none: + cache_mode = "none" + - cache_mode_always: + cache_mode = "always" + - cache_mode_auto: + cache_mode = "auto" + - thread_pool: + only internal + variants: + - thread_pool_notset: + - thread_pool_0: + thread_pool_size = 0 + openfiles = "no" + - thread_pool_16: + thread_pool_size = 0 + openfiles = "yes" + - sandbox_mode: + only internal + variants: + - sandox_mode_none: + sandbox_mode = "none" + - sandox_mode_chroot: + sandbox_mode = "chroot" + - sandox_mode_namespace: + sandbox_mode = "namespace" + - queue_size: + variants: + - queue_size_none: + queue_size = "" + - queue_size_0: + queue_size = "0" + - queue_size_1024: + queue_size = "1024" + - negative_test: + status_error = "yes" + xattr = "" + cache_mode = "none" + thread_pool_size = + queue_size = + sandbox_mode = "none" + fs_num = 1 + variants: + - invalid_queue_size: + variants: + - larger_than_uint16: + queue_size = 1048576 + error_msg_start = "Parameter 'queue-size' expects uint16_t" + - not_powerof_2: + queue_size = 100 + error_msg_start = "queue-size property must be a power of 2" + - larger_than_1024: + queue_size = 2048 + error_msg_start = "queue-size property must be 1024 or smaller" diff --git a/libvirt/tests/cfg/virtiofs/virtiofs_unprivileged.cfg b/libvirt/tests/cfg/virtiofs/virtiofs_unprivileged.cfg new file mode 100644 index 00000000000..aaf21aee7e4 --- /dev/null +++ b/libvirt/tests/cfg/virtiofs/virtiofs_unprivileged.cfg @@ -0,0 +1,35 @@ +- virtiofs.unprivileged: + type = virtiofs_unprivileged + # 10.0.0-6 + func_supported_since_libvirt_ver = (10, 0, 0) + take_regular_screendumps = "no" + start_vm = no + vcpus_per_cell = 2 + extra_hugepages = 128 + test_user = test + test_passwd = test + pseries: + vcpus_per_cell = 5 + aarch64: + extra_hugepages = 0 + s390-virtio: + with_numa = no + variants plugmode: + - hotplug: + - coldplug: + variants: + - one_guest: + unpr_vms = unpr-vm + - two_guests: + unpr_vms = unpr-vm,unpr-vm2 + variants memorybacking: + - with_hugepages: + s390-virtio: + kvm_module_parameters = hpage=1 + - with_memfd: + - with_shm: + variants: + - one_fs: + fs_dicts = [{'accessmode': 'passthrough', 'source': {'dir': '/tmp/dir1'}, "target": {'dir': 'mount_tag1'}, 'binary': {'path':'/usr/libexec/virtiofsd', 'sandbox_mode':'namespace', 'xattr':'on', 'cache_mode':'always'}, 'driver': {'type': 'virtiofs', 'queue':'1024'}}] + - two_fs: + fs_dicts = [{'accessmode': 'passthrough', 'source': {'dir': '/tmp/dir1'}, "target": {'dir': 'mount_tag1'}, 'binary': {'sandbox_mode':'namespace'}, 'driver': {'type': 'virtiofs'}}, {'accessmode': 'passthrough', 'source': {'dir': '/tmp/dir2'}, "target": {'dir': 'mount_tag2'}, 'binary': {'sandbox_mode':'namespace', 'xattr':'on', 'cache_mode':'always'}, 'driver': {'type': 'virtiofs'}}] diff --git a/libvirt/tests/cfg/virtual_device/filesystem_device.cfg b/libvirt/tests/cfg/virtual_device/filesystem_device.cfg deleted file mode 100644 index f4ccfea94d6..00000000000 --- a/libvirt/tests/cfg/virtual_device/filesystem_device.cfg +++ /dev/null @@ -1,150 +0,0 @@ -- virtual_devices.filesystem_device: - type = filesystem_device - take_regular_screendumps = "no" - vms = "avocado-vt-vm1" - start_vm = no - cache_mode = "none" - lock_posix = "off" - flock = "off" - virtiofsd_path = "/usr/libexec/virtiofsd" - queue_size = "512" - driver_type = "virtiofs" - source_dir_prefix = "/dir" - target_prefix = "mount_tag" - vcpus_per_cell = 2 - extra_hugepages = 128 - pseries: - vcpus_per_cell = 5 - aarch64: - extra_hugepages = 0 - s390-virtio: - with_numa = no - variants: - - externally_launched_fs_test: - variants: - - launched_mode: - launched_mode = "externally" - source_socket = "/var/tmp/vm001.socket" - - fs_test: - variants: - - one_guest: - guest_num = 1 - - two_guests: - vms = "avocado-vt-vm1 avocado-vt-vm2" - guest_num = 2 - only nop.fs_test.xattr_on.flock_off.lock_posix_off.cache_mode_none..one_fs, hotplug_unplug..fs_test.xattr_on.flock_off.lock_posix_off.cache_mode_none..one_fs - variants: - - one_fs: - fs_num = 1 - - multiple_fs: - fs_num = 2 - only xattr_on.flock_off.lock_posix_off.cache_mode_none - variants: - - thread_pool_16: - thread_pool_size = 16 - only positive_test..nop..xattr_on.flock_off.lock_posix_off.cache_mode_none, positive_test..detach_device..xattr_on.flock_off.lock_posix_off.cache_mode_none - - thread_pool_noset: - variants: - - cache_mode_none: - cache_mode = "none" - - cache_mode_always: - cache_mode = "always" - - cache_mode_auto: - cache_mode = "auto" - variants: - - lock_posix_off: - lock_posix = "off" - - lock_posix_on: - lock_posix = "on" - variants: - - flock_on: - flock = "on" - - flock_off: - flock = "off" - variants: - - xattr_on: - xattr = "on" - - xattr_off: - xattr = "off" - - xattr_noset: - xattr = "" - variants: - - nop: - - socket_file_checking: - socket_file_checking = "yes" - only xattr_on.flock_off.lock_posix_off.cache_mode_none, externally_launched_fs_test - - lifecycle: - only xattr_on.flock_off.lock_posix_off.cache_mode_none..one_fs - variants: - - suspend_resume: - suspend_resume = "yes" - - edit_start: - edit_start = "yes" - error_msg_start = "qemu-kvm: -foo: invalid option" - - destroy_start: - only file_backed - bug_url = "https://bugzilla.redhat.com/show_bug.cgi?id=1940276" - destroy_start = "yes" - stress_script = "#!/usr/bin/python3;import os;while True:; os.open("%s/moo", os.O_CREAT | os.O_RDWR); os.unlink("%s/moo");" - - restart_service: - only file_backed - func_supported_since_libvirt_ver = (9, 2, 0) - setup_mem = True - source_dir = "/var/tmp/mount_tag0" - dev_type = "filesystem" - vm_attrs = {'mb': {"source_type":"file", 'access_mode': 'shared'}} - fs_dict = {'accessmode':'passthrough', 'driver': {'type': 'virtiofs', 'queue':'512'}, 'source':{'dir': '${source_dir}'}, "target": {'dir': 'mount_tag0'}, 'binary': {'path': '/usr/libexec/virtiofsd', 'xattr': 'on','cache_mode':'none','lock_posix':'off','flock':'off'}} - - coldplug_coldunplug: - only xattr_on.flock_off.lock_posix_off.cache_mode_none..one_fs - coldplug = "yes" - - hotplug_unplug: - hotplug_unplug = "yes" - variants: - - detach_device_alias: - detach_device_alias = "yes" - only xattr_on.flock_off.lock_posix_off.cache_mode_none - variants: - - stdio_handler: - variants: - - file: - stdio_handler = "file" - only one_fs.one_guest - - logd: - stdio_handler = "logd" - - detach_device: - detach_device_alias = "no" - variants: - - positive_test: - status_error = "no" - variants: - - hugepages_backed: - with_hugepages = yes - s390-virtio: - kvm_module_parameters = "hpage=1" - - file_backed: - with_hugepages = no - - memfd_backed: - with_hugepages = no - with_memfd = yes - - negative_test: - only fs_test.xattr_on.flock_off.lock_posix_off.cache_mode_none..one_fs.one_guest - status_error = "yes" - variants: - - invalid_queue_size: - only nop, hotplug_unplug.detach_device - variants: - - larger_than_uint16: - queue_size = 1048576 - error_msg_start = "Parameter 'queue-size' expects uint16_t" - - not_powerof_2: - queue_size = 100 - error_msg_start = "queue-size property must be a power of 2" - - larger_than_1024: - queue_size = 2048 - error_msg_start = "queue-size property must be 1024 or smaller" - - managedsave: - only nop - s390-virtio: - kvm_module_parameters = "hpage=1" - managedsave = "yes" - error_msg_save = "migration with virtiofs device is not supported" diff --git a/libvirt/tests/cfg/virtual_device/input_devices_plug_unplug.cfg b/libvirt/tests/cfg/virtual_device/input_devices_plug_unplug.cfg new file mode 100644 index 00000000000..120d4acd0cf --- /dev/null +++ b/libvirt/tests/cfg/virtual_device/input_devices_plug_unplug.cfg @@ -0,0 +1,16 @@ +- virtual_devices.input_devices_plug_unplug: + type = input_devices_plug_unplug + take_regular_screendumps = no + start_vm = no + + variants multiple_input_types: + - tablet_mouse_keyboard: + device_types = ['tablet', 'mouse', 'keyboard'] + variants: + - bus_usb: + no s390-virtio + bus_type = usb + - bus_virtio: + bus_type = virtio + variants: + - hot: diff --git a/libvirt/tests/cfg/virtual_device/swtpm_cmd.cfg b/libvirt/tests/cfg/virtual_device/swtpm_cmd.cfg new file mode 100644 index 00000000000..4c209148403 --- /dev/null +++ b/libvirt/tests/cfg/virtual_device/swtpm_cmd.cfg @@ -0,0 +1,20 @@ +- virtual_devices.swtpm_cmd: + type = swtpm_cmd + start_vm = no + no s390-virtio + variants case: + - print_caps: + swtpm_setup_cmd = "swtpm_setup --print-capabilities" + swtpm_socket_cmd = "swtpm socket --print-capabilities" + - start_qemu_guest: + tpm_state_dir = "/tmp/mytpm" + swtpm_setup_cmd = "swtpm_setup --tpm2 --tpmstate /tmp/mytpm --create-ek-cert --create-platform-cert --overwrite" + swtpm_socket_cmd = "swtpm socket --daemon --ctrl type=unixio,path=/tmp/guest-swtpm.sock,mode=0600 --tpmstate dir=/tmp/mytpm,mode=0600 --tpm2" + qemu_cmd = "/usr/libexec/qemu-kvm -tpmdev emulator,id=tpm-tpm0,chardev=chrtpm -chardev socket,id=chrtpm,path=/tmp/guest-swtpm.sock -device tpm-crb,tpmdev=tpm-tpm0,id=tpm0" + variants: + - with_terminate: + extra_option = "--terminate" + - no_terminate: + - cocurrent_setup: + co_cmd = "rm -rf /var/lib/swtpm-localca/* ; for ((i = 0; i<500;i++)); do rm -rf /tmp/vtpm${i}; mkdir -p /tmp/vtpm${i}; swtpm_setup --tpm2 --tpmstate /tmp/vtpm${i} --create-ek-cert --create-platform-cert --pcr-banks sha256 2>&1 | grep -i read & done" + unexpected_error = "Need read rights on issuer certificate" diff --git a/libvirt/tests/cfg/virtual_device/tpm_device.cfg b/libvirt/tests/cfg/virtual_device/tpm_device.cfg index dee9a38346f..a5abf51f759 100644 --- a/libvirt/tests/cfg/virtual_device/tpm_device.cfg +++ b/libvirt/tests/cfg/virtual_device/tpm_device.cfg @@ -32,9 +32,22 @@ only encrypted only pcrbank_default test_rsaencypt = 'yes' + - sign_test: + only encrypted + only pcrbank_default + test_sign = 'yes' - version_default: only plain backend_version = 'none' + - debug: + func_supported_since_libvirt_ver = (10, 6, 0) + only encrypted + only pcrbank_default + variants: + - lvl_5: + backend_debug = '5' + - lvl_20: + backend_debug = '20' - persistent_state: persistent_state = 'yes' func_supported_since_libvirt_ver = (7, 0, 0) @@ -133,11 +146,9 @@ no default_model source_attrs = {'type': 'unix', 'mode': 'connect', 'path': '/var/tmp/guest-swtpm.sock'} statedir = "/var/tmp/mytpm" - swtpm_setup_path = '/usr/bin/swtpm_setup' - swtpm_path = '/usr/bin/swtpm' variants: - start_vm: - audit_cmd = ausearch -ts recent -m VIRT_RESOURCE| grep 'tpm-external' + audit_cmd = "cat /var/log/audit/audit.log| grep 'tpm-external'" ausearch_check = 'reason=start.*device="/var/tmp/guest-swtpm.sock".*res=success' - suspend_resume: vm_operate = 'resume' @@ -187,6 +198,8 @@ - emulator: backend_type='emulator' tpm_model = 'tpm-crb' + aarch64: + tpm_model = 'tpm-tis' pseries: tpm_model = 'tpm-spapr' variants: @@ -194,7 +207,7 @@ variants: - version_1.2: backend_version = '1.2' - xml_errmsg = "Unsupported interface tpm-crb for TPM 1.2|TPM version '1.2' is not supported" + xml_errmsg = "Unsupported interface.*tpm-crb.*for TPM 1.2|TPM .*1.2.* is not supported" pseries: xml_errmsg = 'TPM 1.2 is not supported with the SPAPR device mode' - version_2: @@ -203,6 +216,11 @@ - version_textdefault: backend_version = 'default' xml_errmsg = "Invalid value for attribute 'version' in element 'backend': 'default'" + - invalid_debug: + func_supported_since_libvirt_ver = (10, 6, 0) + backend_debug = '-1' + backend_version = '2.0' + xml_errmsg = "Invalid.*'debug' in element 'backend'.*Expected non-negative integer value" - encrypt_secret: backend_version = '2.0' variants: diff --git a/libvirt/tests/cfg/virtual_device/video_devices.cfg b/libvirt/tests/cfg/virtual_device/video_devices.cfg index 077d0bc24a4..7a1138a2fb1 100644 --- a/libvirt/tests/cfg/virtual_device/video_devices.cfg +++ b/libvirt/tests/cfg/virtual_device/video_devices.cfg @@ -5,6 +5,12 @@ - positive_test: status_error = "no" variants: + - resolution_test: + no qxl + resolution_test = "yes" + resolution_x = 507 + resolution_y = 510 + qemu_line = "xres.*:${resolution_x}.*yres.*:${resolution_y}" - model_test: model_test = "yes" variants: @@ -98,6 +104,7 @@ no mem_test variants: - qxl: + no aarch64 secondary_video_model = qxl - virtio: secondary_video_model = virtio @@ -105,20 +112,21 @@ - primary_video: variants: - qxl: - no s390-virtio + no s390-virtio, aarch64 primary_video_model = qxl - vga: - no s390-virtio + no s390-virtio, aarch64 primary_video_model = vga - cirrus: - no s390-virtio + no s390-virtio, aarch64 + no resolution_test primary_video_model = cirrus no mem_test - virtio: primary_video_model = virtio no mem_test - bochs: - no s390-virtio + no s390-virtio, aarch64 primary_video_model = bochs only no_secondary_video..model_test.default no_secondary_video..vram..bochs_default_size - negative_test: diff --git a/libvirt/tests/cfg/virtual_device/vsock.cfg b/libvirt/tests/cfg/virtual_device/vsock.cfg index a2f01b4ba90..25acdac1b90 100644 --- a/libvirt/tests/cfg/virtual_device/vsock.cfg +++ b/libvirt/tests/cfg/virtual_device/vsock.cfg @@ -31,6 +31,12 @@ - edit_start: start_vm = "no" edit_xml = "yes" + - ssh_proxy: + func_supported_since_libvirt_ver = (10, 4, 0) + start_vm = "no" + guest_user = "guest_user" + guest_user_passwd = "123456" + systemd_version_cmd = "rpm -q systemd | awk -F'-' '{print $2}'" - negative_test: status_error = no variants: diff --git a/libvirt/tests/cfg/virtual_disks/startup_policy.cfg b/libvirt/tests/cfg/virtual_disks/startup_policy.cfg index 54fc056296e..09bf8e9857e 100644 --- a/libvirt/tests/cfg/virtual_disks/startup_policy.cfg +++ b/libvirt/tests/cfg/virtual_disks/startup_policy.cfg @@ -73,6 +73,7 @@ - disk: device_type = "disk" image_size = "100M" + snapshot_options = "--memspec snapshot=external,file=/tmp/mem.%s --diskspec %s,file=/tmp/test.%s --diskspec vda,snapshot=no" only file dir_pool variants: - virtio_bus: @@ -89,13 +90,16 @@ update_policy_list = "optional requisite" start_error = "yes" restore_error = "yes" + revert_error = "yes" - optional: policy = "optional" update_policy_list = "mandatory requisite" start_error = "no" - restore_error = "no" + restore_error = "yes" + revert_error = "yes" - requisite: policy = "requisite" update_policy_list = "mandatory optional" start_error = "yes" restore_error = "no" + revert_error = "no" diff --git a/libvirt/tests/cfg/virtual_disks/vhostvdpa_block_backend_type/blockcopy_vhostvdpa_backend_disk.cfg b/libvirt/tests/cfg/virtual_disks/vhostvdpa_block_backend_type/blockcopy_vhostvdpa_backend_disk.cfg new file mode 100644 index 00000000000..737b7444ffe --- /dev/null +++ b/libvirt/tests/cfg/virtual_disks/vhostvdpa_block_backend_type/blockcopy_vhostvdpa_backend_disk.cfg @@ -0,0 +1,14 @@ +- virtual_disks.vhostvdpa.blockcopy: + type = blockcopy_vhostvdpa_backend_disk + start_vm = no + only x86_64 + + func_supported_since_libvirt_ver = (9, 10, 0) + simulator = "yes" + disk_target = "vdb" + disk_vdpa_attrs = {"source": {"attrs": {"dev": "/dev/vhost-vdpa-0"}}, "type_name": "vhostvdpa"} + disk_driver = {"driver": {"name": "qemu", "type": "raw", "cache": "none", "io": "threads", "copy_on_read": "on", "discard": "unmap", "detect_zeroes": "on"}} + disk_attrs = {"device": "disk", "target": {"dev": "${disk_target}", "bus": "virtio"}, **${disk_vdpa_attrs}, **${disk_driver}} + bc_disk_vdpa_attrs = {"source": {"attrs": {"dev": "/dev/vhost-vdpa-1"}}, "type_name": "vhostvdpa"} + bc_disk_attrs = {"device": "disk", "target": {"dev": "${disk_target}", "bus": "virtio"}, **${bc_disk_vdpa_attrs}, **${disk_driver}} + bc_options = "--xml {} --pivot --transient-job" diff --git a/libvirt/tests/cfg/virtual_disks/vhostvdpa_block_backend_type/define_start_vm_with_multi_vhostvdpa_backend_disks.cfg b/libvirt/tests/cfg/virtual_disks/vhostvdpa_block_backend_type/define_start_vm_with_multi_vhostvdpa_backend_disks.cfg new file mode 100644 index 00000000000..9ae52ba2c33 --- /dev/null +++ b/libvirt/tests/cfg/virtual_disks/vhostvdpa_block_backend_type/define_start_vm_with_multi_vhostvdpa_backend_disks.cfg @@ -0,0 +1,12 @@ +- virtual_disks.vhostvdpa.define_start_multi_disks: + type = define_start_vm_with_multi_vhostvdpa_backend_disks + start_vm = no + simulator = "yes" + func_supported_since_libvirt_ver = (9, 10, 0) + only x86_64 + + disk_vdpa_attrs = {"source": {"attrs": {"dev": "/dev/vhost-vdpa-0"}}, "type_name": "vhostvdpa"} + disk2_vdpa_attrs = {"source": {"attrs": {"dev": "/dev/vhost-vdpa-1"}}, "type_name": "vhostvdpa"} + disk_driver = {"driver": {"name": "qemu", "type": "raw", "cache": "none", "io": "threads", "copy_on_read": "on", "discard": "unmap", "detect_zeroes": "on"}} + disk_attrs = {"device": "disk", "target": {"dev": "vdb", "bus": "virtio"}, **${disk_vdpa_attrs}, **${disk_driver}} + disk2_attrs = {"device": "disk", "target": {"dev": "vdc", "bus": "virtio"}, **${disk2_vdpa_attrs}, **${disk_driver}} diff --git a/libvirt/tests/cfg/virtual_disks/vhostvdpa_block_backend_type/define_start_vm_with_vhostvdpa_backend_disk.cfg b/libvirt/tests/cfg/virtual_disks/vhostvdpa_block_backend_type/define_start_vm_with_vhostvdpa_backend_disk.cfg new file mode 100644 index 00000000000..fd298ec8798 --- /dev/null +++ b/libvirt/tests/cfg/virtual_disks/vhostvdpa_block_backend_type/define_start_vm_with_vhostvdpa_backend_disk.cfg @@ -0,0 +1,26 @@ +- virtual_disks.vhostvdpa.define_start: + type = define_start_vm_with_vhostvdpa_backend_disk + start_vm = no + simulator = "yes" + driver_type = "raw" + disk_vdpa_attrs = {"source": {"attrs": {"dev": "/dev/vhost-vdpa-0"}}, "type_name": "vhostvdpa"} + func_supported_since_libvirt_ver = (9, 10, 0) + only x86_64 + variants cache_mode: + - none: + - directsync: + - no_specified_value: + define_error = "yes" + variants: + - default: + - without_shared_memory: + only none + without_shared_memory = "yes" + define_error = "yes" + - qcow2_dirver: + only none + driver_type = "qcow2" + start_error = "yes" + + disk_driver = {"driver": {"name": "qemu", "type": "${driver_type}", "cache": "${cache_mode}", "io": "threads", "copy_on_read": "on", "discard": "unmap", "detect_zeroes": "on"}} + disk_attrs = {"device": "disk", "target": {"dev": "vdb", "bus": "virtio"}, **${disk_vdpa_attrs}, **${disk_driver}} diff --git a/libvirt/tests/cfg/virtual_disks/vhostvdpa_block_backend_type/define_start_vms_with_same_vhostvdpa_backend_disk.cfg b/libvirt/tests/cfg/virtual_disks/vhostvdpa_block_backend_type/define_start_vms_with_same_vhostvdpa_backend_disk.cfg new file mode 100644 index 00000000000..a539534bfb6 --- /dev/null +++ b/libvirt/tests/cfg/virtual_disks/vhostvdpa_block_backend_type/define_start_vms_with_same_vhostvdpa_backend_disk.cfg @@ -0,0 +1,12 @@ +- virtual_disks.vhostvdpa.define_start_multi_vms_with_same_disk: + type = define_start_vms_with_same_vhostvdpa_backend_disk + start_vm = no + simulator = "yes" + func_supported_since_libvirt_ver = (9, 10, 0) + only x86_64 + + vms = avocado-vt-vm1 vm2 + disk_vdpa_attrs = {"source": {"attrs": {"dev": "/dev/vhost-vdpa-0"}}, "type_name": "vhostvdpa"} + disk_driver = {"driver": {"name": "qemu", "type": "raw", "cache": "none", "io": "threads", "copy_on_read": "on", "discard": "unmap", "detect_zeroes": "on"}} + disk_attrs = {"device": "disk", "target": {"dev": "vdb", "bus": "virtio"}, **${disk_vdpa_attrs}, **${disk_driver}} + err_msg = "vdpa device.*Device or resource busy" diff --git a/libvirt/tests/cfg/virtual_disks/vhostvdpa_block_backend_type/hotplug_vhostvdpa_backend_disk.cfg b/libvirt/tests/cfg/virtual_disks/vhostvdpa_block_backend_type/hotplug_vhostvdpa_backend_disk.cfg new file mode 100644 index 00000000000..299fe4b2771 --- /dev/null +++ b/libvirt/tests/cfg/virtual_disks/vhostvdpa_block_backend_type/hotplug_vhostvdpa_backend_disk.cfg @@ -0,0 +1,16 @@ +- virtual_disks.vhostvdpa.hotplug: + type = hotplug_vhostvdpa_backend_disk + start_vm = no + simulator = "yes" + disk_vdpa_attrs = {"source": {"attrs": {"dev": "/dev/vhost-vdpa-0"}}, "type_name": "vhostvdpa"} + func_supported_since_libvirt_ver = (9, 10, 0) + only x86_64 + + variants cache_mode: + - none: + - directsync: + - no_specified_value: + status_error = "yes" + + disk_driver = {"driver": {"name": "qemu", "type": "raw", "cache": "${cache_mode}", "io": "threads", "copy_on_read": "on", "discard": "unmap", "detect_zeroes": "on"}} + disk_attrs = {"device": "disk", "target": {"dev": "vdb", "bus": "virtio"}, **${disk_vdpa_attrs}, **${disk_driver}} diff --git a/libvirt/tests/cfg/virtual_disks/vhostvdpa_block_backend_type/nodedev_vhostvdpa_disk.cfg b/libvirt/tests/cfg/virtual_disks/vhostvdpa_block_backend_type/nodedev_vhostvdpa_disk.cfg new file mode 100644 index 00000000000..5a548bbcd6a --- /dev/null +++ b/libvirt/tests/cfg/virtual_disks/vhostvdpa_block_backend_type/nodedev_vhostvdpa_disk.cfg @@ -0,0 +1,6 @@ +- virtual_disks.vhostvdpa.nodedev: + type = nodedev_vhostvdpa_disk + start_vm = no + simulator = "yes" + func_supported_since_libvirt_ver = (9, 10, 0) + only x86_64 diff --git a/libvirt/tests/cfg/virtual_disks/vhostvdpa_block_backend_type/vm_lifecycle_vhostvdpa_backend_disk.cfg b/libvirt/tests/cfg/virtual_disks/vhostvdpa_block_backend_type/vm_lifecycle_vhostvdpa_backend_disk.cfg new file mode 100644 index 00000000000..fea95cd88b0 --- /dev/null +++ b/libvirt/tests/cfg/virtual_disks/vhostvdpa_block_backend_type/vm_lifecycle_vhostvdpa_backend_disk.cfg @@ -0,0 +1,9 @@ +- virtual_disks.vhostvdpa.lifecycle: + type = vm_lifecycle_vhostvdpa_backend_disk + start_vm = no + simulator = "yes" + disk_vdpa_attrs = {"source": {"attrs": {"dev": "/dev/vhost-vdpa-0"}}, "type_name": "vhostvdpa"} + disk_driver = {"driver": {"name": "qemu", "type": "raw", "cache": "none", "io": "threads", "copy_on_read": "on", "discard": "unmap", "detect_zeroes": "on"}} + disk_attrs = {"device": "disk", "target": {"dev": "vdb", "bus": "virtio"}, **${disk_vdpa_attrs}, **${disk_driver}} + func_supported_since_libvirt_ver = (9, 10, 0) + only x86_64 diff --git a/libvirt/tests/cfg/virtual_disks/virtual_disks_blockresize.cfg b/libvirt/tests/cfg/virtual_disks/virtual_disks_blockresize.cfg new file mode 100755 index 00000000000..03e7b99055a --- /dev/null +++ b/libvirt/tests/cfg/virtual_disks/virtual_disks_blockresize.cfg @@ -0,0 +1,61 @@ +- virtual_disks.blockresize: + type = virtual_disks_blockresize + take_regular_screendumps = "no" + start_vm = "no" + target_format = "raw" + type_name = "block" + driver_type = 'raw' + device_type = "disk" + target_dev = "sdb" + status_error = "no" + define_error = "no" + func_supported_since_libvirt_ver = (10, 0, 0) + offset = "512" + size_in_mb = "100" + block_size_in_bytes = "104857600" + disk_slice_attrs = "{'slice_type': 'storage', 'slice_offset': '0', 'slice_size': '512'}" + variants test_scenario: + - capacity: + resize_value = "--capacity" + - specific: + resize_value = "104857600B" + - save_restore: + only coldplug..virtio + resize_value = "--capacity" + vm_save = "/var/lib/libvirt/images/%s.save" + - not_equal_actual_size: + only coldplug..virtio + resize_value = "1024B" + status_error = "yes" + status_error_msg = "Operation not supported: block device backed disk must be resized to its actual size" + - not_zero_offset: + only coldplug..virtio + disk_slice_attrs = "{'slice_type': 'storage', 'slice_offset': '512', 'slice_size': '1024'}" + status_error = "yes" + resize_value = "--capacity" + status_error_msg = "Operation not supported: resize of a disk with storage slice with non-zero .*offset.*" + - non_raw_block_device: + only coldplug..virtio + overlay_source_file_path = "/var/lib/libvirt/images/qcow2" + driver_type = 'qcow2' + target_format = "qcow2" + status_error = "yes" + resize_value = "--capacity" + status_error_msg = "Operation not supported: block resize to full capacity supported only with.*raw.*local block-based disks" + - not_align_with_multiple_1024: + only coldplug..virtio + resize_value = "1025000B" + source_raw_file_path = "/var/lib/libvirt/images/align_large.raw" + type_name = "file" + actual_resize_value = "1025024" + variants target_bus: + - virtio: + - sata: + only coldplug + no s390-virtio,aarch64 + - scsi: + variants: + - coldplug: + virt_device_hotplug = "no" + - hotplug: + virt_device_hotplug = "yes" diff --git a/libvirt/tests/cfg/virtual_disks/virtual_disks_ccw_addr.cfg b/libvirt/tests/cfg/virtual_disks/virtual_disks_ccw_addr.cfg index a885def8c6d..d9205d7a584 100755 --- a/libvirt/tests/cfg/virtual_disks/virtual_disks_ccw_addr.cfg +++ b/libvirt/tests/cfg/virtual_disks/virtual_disks_ccw_addr.cfg @@ -3,7 +3,7 @@ take_regular_screendumps = "no" start_vm = "no" target_bus = "virtio" - no s390-virtio + only s390-virtio variants: - start_vm: variants: @@ -11,9 +11,10 @@ status_error = "yes" define_error = "yes" error_msg = "cannot use CCW address type for device" + only attach_no_exist_disk - positive_test: status_error = "no" - only attach_same_pci_slot + no attach_no_exist_disk variants: - attach_no_exist_disk: only coldplug @@ -37,7 +38,7 @@ addr_attrs = "{'type': 'ccw', 'cssid': '0x0', 'ssid': '0x0', 'devno': '0x0000'}" - attach_rng: backend_device = "rng" - backend_dev = "/dev/hwrng" + backend_dev = "/dev/random" rng_model = "virtio" addr_attrs = "{'type': 'ccw', 'cssid': '0x0', 'ssid': '0x0', 'devno': '0x0000'}" - attach_same_pci_slot: diff --git a/libvirt/tests/cfg/virtual_disks/virtual_disks_cdrom_device.cfg b/libvirt/tests/cfg/virtual_disks/virtual_disks_cdrom_device.cfg index fd7f467d168..0b8ff6d41a5 100755 --- a/libvirt/tests/cfg/virtual_disks/virtual_disks_cdrom_device.cfg +++ b/libvirt/tests/cfg/virtual_disks/virtual_disks_cdrom_device.cfg @@ -122,6 +122,36 @@ backend_device = "scsi_cdrom_hot_eject_backend" tray_state = "locked, tray closed" only hotplug..positive_test + - empty_source_cdrom_backend: + func_supported_since_libvirt_ver = (9, 10, 0) + type_name = "file" + target_format = "raw" + target_dev = "sdd" + backend_device = "empty_source_cdrom_backend" + only hotplug..positive_test + - dropped_changed_events_startuppolicy: + type_name = "file" + target_format = "raw" + virt_disk_device_source_second = "/var/lib/libvirt/images/none.qcow2" + virt_disk_device_source = "/var/lib/libvirt/images/none" + target_dev = "sdc" + startupPolicy="optional" + backend_device = "dropped_changed_events_startuppolicy" + only coldplug..positive_test + - block_cdrom_tainted: + only coldplug..positive_test + target_format = "raw" + type_name = "block" + target_dev = "sdb" + virt_disk_device_source = "/dev/sdb" + backend_device = "block_cdrom_tainted" + - disconnect_audit_cdrom_backend: + type_name = "file" + target_format = "raw" + virt_disk_device_source = "/var/lib/libvirt/images/disconnect.iso" + target_dev = "sdb" + backend_device = "disconnect_audit_cdrom_backend" + only coldplug..positive_test variants: - hotplug: virt_device_hotplug = "yes" diff --git a/libvirt/tests/cfg/virtual_disks/virtual_disks_dasd.cfg b/libvirt/tests/cfg/virtual_disks/virtual_disks_dasd.cfg index b9321ecf1f8..39abe318a25 100644 --- a/libvirt/tests/cfg/virtual_disks/virtual_disks_dasd.cfg +++ b/libvirt/tests/cfg/virtual_disks/virtual_disks_dasd.cfg @@ -1,6 +1,6 @@ - virtual_disks.dasd: type = virtual_disks_dasd only s390-virtio - devid = + devid = dasd variants: - read_native_partition_table: diff --git a/libvirt/tests/cfg/virtual_disks/virtual_disks_datastore.cfg b/libvirt/tests/cfg/virtual_disks/virtual_disks_datastore.cfg new file mode 100644 index 00000000000..a756bd9d013 --- /dev/null +++ b/libvirt/tests/cfg/virtual_disks/virtual_disks_datastore.cfg @@ -0,0 +1,16 @@ +- virtual_disks.datastore: + type = virtual_disks_datastore + start_vm = no + target_disk = "vdb" + disk_type = "file" + func_supported_since_libvirt_ver = (10, 10, 0) + data_file_option = " -o data_file=%s" + disk_dict = {"type_name":"${disk_type}", "target":{"dev": "${target_disk}", "bus": "virtio"}, "driver": {"name": "qemu", "type":"qcow2"}} + variants: + - start_vm: + - hotplug_disk: + with_hotplug = "yes" + variants datastore_type: + - with_file: + - with_block: + with_block = "yes" diff --git a/libvirt/tests/cfg/virtual_disks/virtual_disks_discard_granularity.cfg b/libvirt/tests/cfg/virtual_disks/virtual_disks_discard_granularity.cfg new file mode 100755 index 00000000000..c04eff57b14 --- /dev/null +++ b/libvirt/tests/cfg/virtual_disks/virtual_disks_discard_granularity.cfg @@ -0,0 +1,87 @@ +- virtual_disks.discard_granularity: + type = virtual_disks_discard_granularity + take_regular_screendumps = "no" + start_vm = "no" + target_format = "raw" + type_name = "file" + driver_type = 'raw' + device_type = "disk" + target_dev = "vdb" + status_error = "no" + define_error = "no" + func_supported_since_libvirt_ver = (10, 0, 0) + variants target_bus: + - virtio: + target_dev = "vdb" + discard_granularity = '1024' + discard_granularity_in_unit = '1K' + invalid_discard_granularity = '1000' + - sata: + no aarch64, s390x + only coldplug + target_dev = "sdb" + discard_granularity = '512' + discard_granularity_in_unit = '512B' + invalid_discard_granularity = '1024' + - scsi: + target_dev = "sdb" + discard_granularity = '1024' + discard_granularity_in_unit = '1K' + invalid_discard_granularity = '1000' + - usb: + target_dev = "sdb" + discard_granularity = '512' + discard_granularity_in_unit = '512B' + invalid_discard_granularity = '1000' + variants test_scenario: + - normal_vm_start: + - failure_vm_start: + only coldplug + define_error = "yes" + status_error = "yes" + status_error_msg = "discard_granularity must be a multiple|discard_granularity must be 512" + - boundary_vm_start: + only coldplug..virtio + define_error_msg = "Invalid value for attribute.*discard_granularity.*" + expected_attribute = "no" + variants: + - value_zero: + discard_granularity = '0' + discard_granularity_in_unit = '0K' + - value_minus: + discard_granularity = '-1' + define_error = "yes" + - value_max: + discard_granularity = '4294967296' + define_error = "yes" + - value_max_minus_one: + discard_granularity = '4294967295' + discard_granularity_in_unit = '1K' + expected_attribute = "yes" + - live_update_discard_granularity: + only coldplug..virtio + error_msg = "cannot modify field .*blockio discard_granularity.*" + variants: + - add_discard_granularity: + discard_granularity = '0' + new_discard_granularity = '512' + - modify_discard_granularity: + new_discard_granularity = '2048' + - remove_discard_granularity: + new_discard_granularity = '0' + variants disk_type: + - file: + source_file_path = "/var/lib/libvirt/images/discard_granularity" + - vhostuser: + only coldplug..virtio..failure_vm_tart + type_name = "vhostuser" + vhost_source_file_path = "/var/lib/libvirt/images/discard_granularity_vhost" + socket_file = "/tmp/vhost.sock" + define_error = "yes" + define_error_msg = "blockio is not supported with vhostuser disk" + variants: + - coldplug: + virt_device_hotplug = "no" + - hotplug: + virt_device_hotplug = "yes" + 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..af789687448 --- /dev/null +++ b/libvirt/tests/cfg/virtual_disks/virtual_disks_discard_no_unref.cfg @@ -0,0 +1,47 @@ +- 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}"' + - hotplug_disk: + only enable..with_discard_unmap.file_disk + hotplug = "yes" + check_libvirtd_log = '"driver":"qcow2","discard-no-unref":true' + - 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" + - update_negative: + only enable..with_discard_unmap.file_disk + func_supported_since_libvirt_ver = (10, 5, 0) + status_error = "yes" + expect_error = "cannot modify field 'discard_no_unref' of the disk" + 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/cfg/virtual_disks/virtual_disks_https.cfg b/libvirt/tests/cfg/virtual_disks/virtual_disks_https.cfg new file mode 100644 index 00000000000..d33e39e5a46 --- /dev/null +++ b/libvirt/tests/cfg/virtual_disks/virtual_disks_https.cfg @@ -0,0 +1,25 @@ +- virtual_disks.https: + type = virtual_disks_https + start_vm = "no" + target_disk = "sdb" + disk_format = "raw" + source_host_name = "insect.mm.fcix.net" + source_iso_name = "/fedora/linux/releases/41/Server/x86_64/iso/Fedora-Server-netinst-x86_64-41-1.4.iso" + cookie_name = "vmware_soap_session" + cookie_value = "314455dbd2eaafd7d76b3b7828f0a3e3956450f9" + expected_xpaths = [{'element_attrs': [".//ssl[@verify='yes']"]}, {'element_attrs': [".//readahead[@size='1024']"]}, {'element_attrs': [".//timeout[@seconds='60']"]}] + cookie_in_dumpxml = "${cookie_name}.*${cookie_value}" + driver_dict = "'driver': {'name': 'qemu', 'type': '${disk_format}'}" + source_extra_dict = "'cookies': {'cookie_name': '${cookie_name}', 'cookie': '${cookie_value}'}, 'readahead': '1024', 'timeout': '60', 'ssl': 'yes'" + source_dict = "'source': {'hosts': [{'name': '${source_host_name}'}], 'attrs': {'protocol': 'https', 'name': '${source_iso_name}'}, ${source_extra_dict}}" + disk_dict = {'type_name': 'network', 'readonly': True, 'device': '%s', ${driver_dict}, ${source_dict}, 'target': {'dev': '${target_disk}', 'bus': 'scsi'}} + func_supported_since_libvirt_ver = (10, 10, 0) + variants: + - start_vm: + - detach_attach_disk: + with_hotplug = "yes" + variants: + - network_disk: + network_device = "disk" + - network_cdrom: + network_device = "cdrom" diff --git a/libvirt/tests/cfg/virtual_disks/virtual_disks_io_error.cfg b/libvirt/tests/cfg/virtual_disks/virtual_disks_io_error.cfg new file mode 100644 index 00000000000..c4972bcbb6b --- /dev/null +++ b/libvirt/tests/cfg/virtual_disks/virtual_disks_io_error.cfg @@ -0,0 +1,18 @@ +- virtual_disks.io_error: + type = virtual_disks_io_error + start_vm = "no" + virt_disk_device = "disk" + take_regular_screendumps=no + func_supported_since_libvirt_ver = (10, 10, 0) + variants: + - hypervisor_message: + device_manager_path = "/tmp/img" + prepare_file = "dd if=/dev/zero of=${device_manager_path} count=512 bs=1048576" + device_manager = "errdev1" + disk_dict = {"type_name": "block",'source': {'attrs': {'dev': '/dev/mapper/${device_manager}'}}, "target": {"dev": "vdb", "bus": "virtio"}, "driver": {"name": "qemu", "type": "raw"}} + dd_in_guest = "dd if=/dev/vdb of=/tmp/img bs=1024 count=524288" + dd_msg = "Input/output error" + event_msg = "/dev/mapper/${device_manager}.*report due to message" + guest_log_msg = "IO error device=.*Input/output error" + dominfo_msg = "I/O error:.*path='/dev/mapper/${device_manager}'.*message='Input/output error'" + diff --git a/libvirt/tests/cfg/virtual_disks/virtual_disks_io_tuning.cfg b/libvirt/tests/cfg/virtual_disks/virtual_disks_io_tuning.cfg index 73deead6f3a..e2c65cebbf2 100755 --- a/libvirt/tests/cfg/virtual_disks/virtual_disks_io_tuning.cfg +++ b/libvirt/tests/cfg/virtual_disks/virtual_disks_io_tuning.cfg @@ -7,7 +7,7 @@ func_supported_since_libvirt_ver = (9, 3, 0) variants test_scenario: - normal_start: - driver_attribute = {'name': "qemu", 'type': "qcow2", 'queue_size': '1024', 'io': 'io_uring'} + driver_attribute = {'name': "qemu", 'type': "qcow2", 'io': 'io_uring'} source_file_path = "/var/lib/libvirt/images/io_uring.qcow2" target_device = "sdb" variants plug_mode: diff --git a/libvirt/tests/cfg/virtual_disks/virtual_disks_iothreads_queue.cfg b/libvirt/tests/cfg/virtual_disks/virtual_disks_iothreads_queue.cfg new file mode 100755 index 00000000000..36567f89977 --- /dev/null +++ b/libvirt/tests/cfg/virtual_disks/virtual_disks_iothreads_queue.cfg @@ -0,0 +1,133 @@ +- virtual_disks.iothreads.queue: + type = virtual_disks_iothreads_queue + status_error = "no" + start_vm = "no" + func_supported_since_libvirt_ver = (10, 0, 0) + check_vm_dumpxml = yes + target_dev = "vda" + vm_attrs = {'iothreads': 4} + variants method: + - user_defined: + queue_num = "3" + driver = {'name': 'qemu', 'queues': '${queue_num}'} + driver_iothreads = {'iothread': [{'queue': [{'id': '0'}, {'id': '1'}], 'id': '1'}, {'queue': [{'id': '2'}], 'id': '2'}]} + check_qemu_pattern = '"driver":"virtio-blk-.*","num-queues":3,"iothread-vq-mapping":\[{"iothread":"iothread1","vqs":\[0,1\]},{"iothread":"iothread2","vqs":\[2\]}\]' + - round_robin: + driver = {'name': 'qemu', 'type': 'qcow2'} + driver_iothreads = {'iothread': [{'id': '1'}, {'id': '2'}, {'id': '3'}]} + check_qemu_pattern = '"driver":"virtio-blk-.*","iothread-vq-mapping":\[{"iothread":"iothread1"},{"iothread":"iothread2"},{"iothread":"iothread3"}\]' + variants scenario: + - define_start: + - define_invalid: + status_error = yes + variants: + - both_attribute_subelement: + only coldplug..round_robin + queue_num = "3" + driver = {'name': 'qemu', 'queues': '${queue_num}', 'iothread': '4'} + driver_iothreads = {'iothread': [{'id': '1'}, {'id': '2'}]} + err_msg = "disk driver 'iothread' attribute can't be used together with 'iothreads' subelement" + - part_iothreads_mapped: + only coldplug..user_defined + queue_num = "3" + driver = {'name': 'qemu', 'queues': '${queue_num}'} + driver_iothreads = {'iothread': [{'queue': [{'id': '0'}, {'id': '1'}], 'id': '1'}, {'id': '2'}]} + err_msg = "iothread to queue mapping must be provided for all iothreads or for none" + - no_iothreads_define: + only coldplug..round_robin + vm_attrs = {'iothreads': 0} + queue_num = "2" + driver = {'name': 'qemu', 'queues': '${queue_num}'} + driver_iothreads = {'iothread': [{'id': '1'}, {'id': '2'}]} + err_msg = "iothread '1' not defined in iothreadid" + - dup_mapping_same_iothread: + only coldplug..round_robin + queue_num = "3" + driver = {'name': 'qemu', 'queues': '${queue_num}'} + driver_iothreads = {'iothread': [{'id': '1'}, {'id': '1'}]} + err_msg = "d|Duplicate mapping for iothread '1'" + - dup_queue_assigned: + only coldplug..user_defined + queue_num = "2" + driver = {'name': 'qemu', 'queues': '${queue_num}'} + driver_iothreads = {'iothread': [{'queue': [{'id': '0'}], 'id': '1'}, {'queue': [{'id': '1'}], 'id': '2'}, {'queue': [{'id': '1'}], 'id': '3'}]} + err_msg = "iothread queue '1' is already assigned" + - no_queue_number: + only coldplug..user_defined + driver = {'name': 'qemu', 'type': 'qcow2'} + driver_iothreads = {'iothread': [{'queue': [{'id': '0'}], 'id': '1'}, {'queue': [{'id': '2'}], 'id': '2'}]} + err_msg = "'queue' count must be configured for explicit iothread to queue mapping" + - missing_iothread_mapping: + only coldplug..user_defined + queue_num = "3" + driver = {'name': 'qemu', 'queues': '${queue_num}'} + driver_iothreads = {'iothread': [{'queue': [{'id': '2'}], 'id': '1'}, {'queue': [{'id': '1'}], 'id': '2'}]} + err_msg = "missing iothread mapping for queue '0'" + - queue_id_out_of_range: + only coldplug..user_defined + queue_num = "2" + driver = {'name': 'qemu', 'queues': '${queue_num}'} + driver_iothreads = {'iothread': [{'queue': [{'id': '0'}], 'id': '1'}, {'queue': [{'id': '1'}], 'id': '2'}, {'queue': [{'id': '2'}], 'id': '3'}]} + err_msg = "iothread queue '${queue_num}'.*out of range" + - update_delete_iothread: + only coldplug..round_robin + status_error = yes + driver = {'name': 'qemu', 'type': 'qcow2'} + driver_iothreads = {'iothread': [{'id': '1'}, {'id': '2'}, {'id': '3'}]} + new_driver_iothreads = {'iothread': [{'id': '1'}, {'id': '2'}]} + del_iothread_id = 2 + check_qemu_pattern = + err_msg = "cannot remove IOThread ${del_iothread_id} since it is being used by disk" + - live_update_disk: + func_supported_since_libvirt_ver = (10, 10, 0) + check_qemu_pattern = + status_error = yes + err_msg = "error: Operation not supported: cannot modify .*iothreads.* of the disk" + variants: + - change_none_to_roundrobin: + only coldplug..round_robin + driver = {'name': 'qemu', 'type': 'qcow2'} + driver_iothreads = {} + new_driver_iothreads = {'iothread': [{'id': '1'}, {'id': '2'}]} + - add_iothreadid_to_mapping: + only coldplug..round_robin + driver = {'name': 'qemu', 'type': 'qcow2'} + driver_iothreads = {'iothread': [{'id': '1'}, {'id': '2'}]} + new_driver_iothreads = {'iothread': [{'id': '1'}, {'id': '2'}, {'id': '3'}]} + - del_iothreadid_from_mapping: + only coldplug..round_robin + driver = {'name': 'qemu', 'type': 'qcow2'} + driver_iothreads = {'iothread': [{'id': '1'}, {'id': '2'}, {'id': '3'}]} + new_driver_iothreads = {'iothread': [{'id': '1'}, {'id': '2'}]} + - change_roundrobin_to_userdefined: + only coldplug..round_robin + driver = {'name': 'qemu', 'type': 'qcow2', 'queues': '3'} + driver_iothreads = {'iothread': [{'id': '1'}, {'id': '2'}, {'id': '3'}]} + new_driver_iothreads = {'iothread': [{'queue': [{'id': '0'}], 'id': '1'}, {'queue': [{'id': '1'}], 'id': '2'}, {'queue': [{'id': '2'}], 'id': '3'}]} + - change_iothreadid_vqid_mapping: + only coldplug..user_defined + driver = {'name': 'qemu', 'type': 'qcow2', 'queues': '3'} + driver_iothreads = {'iothread': [{'queue': [{'id': '0'}], 'id': '1'}, {'queue': [{'id': '1'}], 'id': '2'}, {'queue': [{'id': '2'}], 'id': '3'}]} + new_driver_iothreads = {'iothread': [{'queue': [{'id': '0'}], 'id': '1'}, {'queue': [{'id': '2'}], 'id': '2'}, {'queue': [{'id': '1'}], 'id': '3'}]} + - change_nothing: + only coldplug..user_defined + status_error = no + driver = {'name': 'qemu', 'type': 'qcow2', 'queues': '3'} + driver_iothreads = {'iothread': [{'queue': [{'id': '0'}], 'id': '1'}, {'queue': [{'id': '1'}], 'id': '2'}, {'queue': [{'id': '2'}], 'id': '3'}]} + new_driver_iothreads = {'iothread': [{'queue': [{'id': '0'}], 'id': '1'}, {'queue': [{'id': '1'}], 'id': '2'}, {'queue': [{'id': '2'}], 'id': '3'}]} + err_msg = "" + variants plug_type: + - coldplug: + - hotplug: + new_target_dev = "vdb" + new_driver_iothreads = {'iothread': [{'id': '1'}, {'id': '2'}, {'id': '3'}]} + new_image_name = "hotplug_disk.qcow2" + new_target = {'dev': '${new_target_dev}', 'bus': 'virtio'} + new_source = {'attrs': {'file': '%s'}} + new_disk_dict = {'target': ${new_target}, 'device': 'disk', 'driver': {'name': 'qemu', 'type': 'qcow2'}, 'driver_iothreads': ${new_driver_iothreads}, 'source': ${new_source}} + check_libvirtd_log = '"driver":"virtio-blk-.*","iothread-vq-mapping":\[{"iothread":"iothread1"},{"iothread":"iothread2"},{"iothread":"iothread3"}\]' + log_level = "1" + variants disk_bus: + - virtio: + target = {'dev': '${target_dev}', 'bus': 'virtio'} + disk_dict = {'target': ${target}, 'device': 'disk', 'driver': ${driver}, 'driver_iothreads': ${driver_iothreads}} diff --git a/libvirt/tests/cfg/virtual_disks/virtual_disks_multiattributes.cfg b/libvirt/tests/cfg/virtual_disks/virtual_disks_multiattributes.cfg new file mode 100644 index 00000000000..f6710214ca0 --- /dev/null +++ b/libvirt/tests/cfg/virtual_disks/virtual_disks_multiattributes.cfg @@ -0,0 +1,18 @@ +- virtual_disks.multiattributes: + type = virtual_disks_multiattributes + start_vm = no + disk_target_dev = "vda" + dom_iothreads = "1" + driver_attributes = {'name': 'qemu', 'type': 'raw', 'cache': 'none', 'error_policy': 'stop',} + no s390-virtio + variants: + - start_guest: + variants: + - file_disk: + disk_type = "file" + another_disk_dev = "vdb" + disk1_dict = {'type_name': '${disk_type}', 'model': 'virtio-non-transitional', 'driver': {**${driver_attributes}, 'discard': 'unmap'}, 'device': 'disk', 'target': {'dev': '${disk_target_dev}', 'bus': 'virtio'}} + disk2_dict = {'type_name': '${disk_type}', 'model': 'virtio-non-transitional', 'driver': {**${driver_attributes}, 'discard': 'unmap'}, 'device': 'disk', 'target': {'dev': '${another_disk_dev}', 'bus': 'virtio'}} + - block_disk: + disk_type = "block" + disk_dict = {'type_name': '${disk_type}', 'model': 'virtio-non-transitional', 'driver': {**${driver_attributes}, 'io': 'native'}, 'device': 'disk', 'boot': '1', 'target': {'dev': '${disk_target_dev}', 'bus': 'virtio'}} diff --git a/libvirt/tests/cfg/virtual_disks/virtual_disks_multidisks.cfg b/libvirt/tests/cfg/virtual_disks/virtual_disks_multidisks.cfg index 07eeb4cf4b9..369987a7628 100644 --- a/libvirt/tests/cfg/virtual_disks/virtual_disks_multidisks.cfg +++ b/libvirt/tests/cfg/virtual_disks/virtual_disks_multidisks.cfg @@ -249,6 +249,7 @@ driver_option = "name=qemu,type=raw,iothread=4" variants: - ide_bus: + no s390-virtio virt_disk_device_target = "hdb" virt_disk_device_bus = "ide" - dom_iothreads: @@ -379,6 +380,7 @@ virt_disk_device_target = "hda" virt_disk_device_bus = "ide" - disk_bus_fdc: + no s390-virtio virt_disk_device = "floppy" virt_disk_device_target = "fda" virt_disk_device_bus = "fdc" @@ -581,6 +583,7 @@ virt_disk_at_dt_disk = "yes" disks_attach_option = "--mode readonly --sourcetype file;" - disk_readonly_nfs_floppy: + no s390-virtio only coldplug virt_disk_device_test_readonly = "yes" virt_disk_device = "floppy" @@ -700,6 +703,7 @@ virt_disk_device_bus = "scsi" virt_disk_device_target = "sda" - disk_floppy_update_boot_order: + no s390-virtio only coldplug floppy_path = '/var/lib/libvirt/images/fd2.img' disk_floppy_update_boot_order = "yes" @@ -716,6 +720,7 @@ only coldplug no q35 no aarch64 + no s390-virtio virt_disk_with_source = "yes" virt_disk_device = "disk" virt_disk_device_source = "ide1" @@ -1010,6 +1015,7 @@ only coldplug no q35 no aarch64 + no s390-virtio status_error = "yes" disk_virtio_multi_ide_controller = "yes" virt_disk_device = "disk" @@ -1078,6 +1084,13 @@ - disk_attach_with_minimal_xml: only coldplug test_minimal_xml = "yes" + memory_size = "1048576" + curr_mem_size = "1048576" + aarch64: + cpu_model_xml = "" + aarch64_machine_type = "virt" + memory_size = "4194304" + curr_mem_size = "4194304" disks_attach_option = "--live" virt_disk_device = "disk" virt_disk_device_source = "disk_minimal" diff --git a/libvirt/tests/cfg/virtual_disks/virtual_disks_ssh.cfg b/libvirt/tests/cfg/virtual_disks/virtual_disks_ssh.cfg new file mode 100644 index 00000000000..f9f1d7d46cb --- /dev/null +++ b/libvirt/tests/cfg/virtual_disks/virtual_disks_ssh.cfg @@ -0,0 +1,22 @@ +- virtual_disks.ssh: + type = virtual_disks_ssh + start_vm = "no" + target_disk = "vdb" + disk_dict = {'type_name': 'network', 'device': 'disk', 'driver': {'name': 'qemu', 'type': 'qcow2'}, "target":{"dev": "${target_disk}", "bus": "virtio"}} + func_supported_since_libvirt_ver = (10, 10, 0) + variants: + - start_vm: + - hotplug_disk: + with_hotplug = "yes" + variants: + - with_ssh_key: + disk_type = "ssh_with_key" + expected_xpaths = [{'element_attrs': [".//knownHosts[@path='%s']"]}, {'element_attrs': [".//identity[@keyfile='%s']"]}] + - with_secret_password: + with_secret_passwd = "yes" + disk_type = "ssh_with_passwd" + key_word = "redhat" + iscsi_user = "root" + secret_pwd = "`printf %s ${key_word} | base64`" + sec_dict = {"secret_ephemeral": "no", "secret_private": "no", "description": "secret_desc_for_ssh_disk", "usage": "iscsi", "target": "libvirtiscsi"} + expected_xpaths = [{'element_attrs': [".//knownHosts[@path='%s']"]}, {'element_attrs': [".//secret[@type='iscsi']"]}] diff --git a/libvirt/tests/cfg/virtual_network/attach_detach_device/attach_iface_with_boot_order.cfg b/libvirt/tests/cfg/virtual_network/attach_detach_device/attach_iface_with_boot_order.cfg new file mode 100644 index 00000000000..1b59a6ca9b9 --- /dev/null +++ b/libvirt/tests/cfg/virtual_network/attach_detach_device/attach_iface_with_boot_order.cfg @@ -0,0 +1,22 @@ +- virtual_network.attach_detach_device.boot_order: + type = attach_iface_with_boot_order + start_vm = no + timeout = 240 + status_error = yes + variants scenario: + - vm_with_os_boot: + no s390-virtio + os_attrs = {'boots': ['hd']} + boot_order = 2 + err_msg = per-device boot elements cannot be used together with os/boot elements + - dup_boot_order: + boot_order = 1 + disk_attrs = {'boot': '${boot_order}'} + err_msg = unsupported configuration: boot order ${boot_order} is already used by another device + - neg_value: + boot_order = -1 + err_msg = Expected non-negative integer value|Expected integer value + - str_value: + boot_order = ss + err_msg = Expected non-negative integer value|Expected integer value + iface_attrs = {'source': {'network': 'default'}, 'model': 'virtio', 'type_name': 'network', 'boot': '${boot_order}'} diff --git a/libvirt/tests/cfg/virtual_network/attach_detach_device/attach_user_type_iface.cfg b/libvirt/tests/cfg/virtual_network/attach_detach_device/attach_user_type_iface.cfg new file mode 100644 index 00000000000..ffa08de2292 --- /dev/null +++ b/libvirt/tests/cfg/virtual_network/attach_detach_device/attach_user_type_iface.cfg @@ -0,0 +1,17 @@ +- virtual_network.attach_device.user_type_iface: + type = attach_user_type_iface + start_vm = no + outside_ip = 'www.redhat.com' + vm_ping_outside = pass + variants user_type: + - root_user: + test_user = root + virsh_uri = 'qemu:///system' + - non_root_user: + test_user = USER.EXAMPLE + test_passwd = PASSWORD.EXAMPLE + unpr_vm_name = UNPRIVILEGED_VM.EXAMPLE + virsh_uri = 'qemu+ssh://${test_user}@localhost/session' + iface_attrs = {'type_name': 'user', 'mac_address': '00:11:22:33:44:55', 'model': 'virtio', 'ips': [{'family': 'ipv4', 'address': '172.17.2.0', 'prefix': '24'}, {'family': 'ipv6', 'address': '2001:db8:ac10:fd01::', 'prefix': '64'}]} + expect_ipv4 = 172.17.2.15 + expect_ipv6 = 2001:db8:ac10:fd01: diff --git a/libvirt/tests/cfg/virtual_network/connectivity/connectivity_check_ethernet_interface.cfg b/libvirt/tests/cfg/virtual_network/connectivity/connectivity_check_ethernet_interface.cfg index 16c123fc2cd..ad09767cfe3 100644 --- a/libvirt/tests/cfg/virtual_network/connectivity/connectivity_check_ethernet_interface.cfg +++ b/libvirt/tests/cfg/virtual_network/connectivity/connectivity_check_ethernet_interface.cfg @@ -4,11 +4,11 @@ timeout = 240 outside_ip = 'www.redhat.com' host_iface = + extra_attrs = {} variants user_type: - non_root_user: test_user = USER.EXAMPLE test_passwd = PASSWORD.EXAMPLE - user_id = unpr_vm_name = UNPRIVILEGED_VM.EXAMPLE variants: - positive_test: @@ -24,15 +24,31 @@ tap_mtu = 1400 iface_mtu = 1200 mtu_attrs = {'mtu': {'size': ${iface_mtu}}} + - smaller_mtu_multi_ifaces: + only two_ifaces + tap_mtu = 1400 + iface_mtu = 1200 + iface_mtu_2 = 1150 + mtu_attrs = {'mtu': {'size': ${iface_mtu}}} variants tap_type: - tap: vm_ping_outside = pass vm_ping_host_public = pass + variants iface_amount: + - one_iface: + - two_ifaces: + only smaller_mtu_multi_ifaces + extra_attrs = {'rom': {'enabled': 'no'}} + iface_attrs_2 = {'type_name': 'ethernet', 'target': {'dev': tap_name_2, 'managed': 'no'}, 'model': 'virtio', 'mtu': {'size': '${iface_mtu_2}'}, 'driver': {'driver_attr': {'name': 'vhost'}}, 'rom': {'enabled': 'no'}} + s390-virtio, aarch64: + extra_attrs = + iface_attrs_2 = {'type_name': 'ethernet', 'target': {'dev': tap_name_2, 'managed': 'no'}, 'model': 'virtio', 'mtu': {'size': '${iface_mtu_2}'}, 'driver': {'driver_attr': {'name': 'vhost'}}} - macvtap: vm_ping_outside = pass vm_ping_host_public = fail - iface_attrs = {'target': {'dev': tap_name, 'managed': 'no'}, 'model': 'virtio', 'type_name': 'ethernet', **${mtu_attrs}, 'acpi': {'index': '1'}} - vm_iface = eno1 + iface_attrs = {'target': {'dev': tap_name, 'managed': 'no'}, 'model': 'virtio', 'type_name': 'ethernet', **${mtu_attrs}, **${extra_attrs}} + s390-virtio, aarch64: + iface_attrs = {'target': {'dev': tap_name, 'managed': 'no'}, 'model': 'virtio', 'type_name': 'ethernet', **${mtu_attrs}} - negative_test: status_error = yes variants: @@ -41,11 +57,17 @@ err_msg = target dev must be supplied when managed='no' - target_dev_not_exist: iface_attrs = {'model': 'virtio', 'type_name': 'ethernet', 'target': {'dev': 'test', 'managed': 'no'}} - err_msg = target managed='no' but specified dev doesn't exist + err_msg = "target managed='no' but specified dev doesn't exist" - managed_yes: func_supported_since_libvirt_ver = (9,0,0) tap_type = tap iface_attrs = {'model': 'virtio', 'type_name': 'ethernet', 'target': {'dev': tap_name, 'managed': 'yes'}} err_msg = The .* interface already exists + - no_multi_queue_flag: + func_supported_since_libvirt_ver = (10,8,0) + tap_type = tap + tap_flag = + iface_attrs = {'model': 'virtio', 'type_name': 'ethernet', 'target': {'dev': tap_name, 'managed': 'no'}, 'driver': {'driver_attr': {'queues': '2'}}} + err_msg = Unable to create multiple fds for tap device .*\(maybe existing device was created without multi_queue flag\) variants: - managed_no: diff --git a/libvirt/tests/cfg/virtual_network/connectivity/connectivity_check_user_interface.cfg b/libvirt/tests/cfg/virtual_network/connectivity/connectivity_check_user_interface.cfg index 5bc896d4477..c92c492c2f9 100644 --- a/libvirt/tests/cfg/virtual_network/connectivity/connectivity_check_user_interface.cfg +++ b/libvirt/tests/cfg/virtual_network/connectivity/connectivity_check_user_interface.cfg @@ -41,6 +41,10 @@ ipv4_addr = 100.100.100.15 ipv4_default_gw = 100.100.100.2 nameserver = 100.100.100.3 + - with_backend: + iface_attrs = {'model': 'virtio', 'type_name': 'user'} + backend = {'type': 'default'} + func_supported_since_libvirt_ver = (10, 8, 0) - negative_test: expect_error = yes variants: diff --git a/libvirt/tests/cfg/virtual_network/connectivity/netperf_nat_interface.cfg b/libvirt/tests/cfg/virtual_network/connectivity/netperf_nat_interface.cfg new file mode 100644 index 00000000000..8b5890da0df --- /dev/null +++ b/libvirt/tests/cfg/virtual_network/connectivity/netperf_nat_interface.cfg @@ -0,0 +1,27 @@ +- virtual_network.netperf.nat_interface: + type = netperf_nat_interface + vms = avocado-vt-vm1 + start_vm = no + net_name = network_conn + ip_attrs = {"netmask": "255.255.255.0", "address": "192.168.144.1", "dhcp_ranges": {"attrs": {"end": "192.168.144.254", "start": "192.168.144.2"}}} + iface_attrs = {"source": {"network": "${net_name}"}, "type_name": "network", "model": "virtio"} + network_attrs = {"name": "${net_name}", "forward": {"mode": "nat"}, "ips": [${ip_attrs}]} + + variants: + - guest2guest: + vms = avocado-vt-vm1 vm2 + netperf_client = avocado-vt-vm1 + netperf_server = vm2 + - host2guest: + netperf_client = ${local_ip} + netperf_server = ${main_vm} + - guest2host: + netperf_client = ${main_vm} + netperf_server = ${local_ip} + UDP_STREAM: + extra_cmd_opts = "-- -R 1" + variants: + - TCP_STREAM: + test_protocol = TCP_STREAM + - UDP_STREAM: + test_protocol = UDP_STREAM diff --git a/libvirt/tests/cfg/virtual_network/domifaddr.cfg b/libvirt/tests/cfg/virtual_network/domifaddr.cfg new file mode 100644 index 00000000000..74df3dd1ac1 --- /dev/null +++ b/libvirt/tests/cfg/virtual_network/domifaddr.cfg @@ -0,0 +1,13 @@ +- virtual_network.domifaddr: + type = domifaddr + start_vm = no + libvirtd_debug_file = /var/log/libvirt/libvird.log + libvirtd_debug_level = 1 + libvirtd_debug_filters = 1:qemu 1:libvirt 4:object 4:json 4:event 1:util + variants: + - default: + net_name = default + net_ipv6_attrs = {'address': '2001:db8:ca2:2::1', 'family': 'ipv6', 'prefix': '64', 'dhcp_ranges': {'attrs': {'start': '2001:db8:ca2:2:1::10', 'end': '2001:db8:ca2:2:1::ff'}}} + iface_a_attrs = {'type_name': 'bridge', 'source': {'bridge': br_name}, 'model': 'virtio'} + iface_b_attrs = {'type_name': 'network', 'source': {'network': net_name}, 'model': 'virtio'} + err_msg = Failed to open file '/var/lib/libvirt/dnsmasq/.*status': No such file or directory diff --git a/libvirt/tests/cfg/virtual_network/driver/check_vhost_cpu_affinity_with_emulatorpin.cfg b/libvirt/tests/cfg/virtual_network/driver/check_vhost_cpu_affinity_with_emulatorpin.cfg new file mode 100644 index 00000000000..5287ac45b03 --- /dev/null +++ b/libvirt/tests/cfg/virtual_network/driver/check_vhost_cpu_affinity_with_emulatorpin.cfg @@ -0,0 +1,7 @@ +- virtual_network.check_vhost_cpu_affinity_with_emulatorpin: + type = check_vhost_cpu_affinity_with_emulatorpin + start_vm = no + timeout = 240 + vcpu_set = 0 + vm_attrs = {'vcpu': 1, 'cputune': {'vcpupins': [{'vcpu': '0', 'cpuset': '${vcpu_set}'}], 'emulatorpin': epin_set}} + iface_attrs = {'model': 'virtio'} diff --git a/libvirt/tests/cfg/virtual_network/driver/rx_tx_queue_size.cfg b/libvirt/tests/cfg/virtual_network/driver/rx_tx_queue_size.cfg new file mode 100644 index 00000000000..c2b5e17be15 --- /dev/null +++ b/libvirt/tests/cfg/virtual_network/driver/rx_tx_queue_size.cfg @@ -0,0 +1,34 @@ +- virtual_network.driver.rx_tx_queue_size: + type = rx_tx_queue_size + start_vm = no + timeout = 240 + outside_ip = 'www.redhat.com' + vm_ping_outside = pass + variants: + - positive: + variants: + - rx_256_tx_256: + rx_tx_attrs = {'rx_queue_size': '256', 'tx_queue_size': '256'} + - rx_512_tx_256: + rx_tx_attrs = {'rx_queue_size': '512', 'tx_queue_size': '256'} + - rx_1024_tx_unset: + rx_tx_attrs = {'rx_queue_size': '1024'} + actual_tx = 256 + - negative: + status_error = yes + variants: + - rx_128_tx_unset: + rx_tx_attrs = {'rx_queue_size': '128'} + - rx_2048_tx_unset: + rx_tx_attrs = {'rx_queue_size': '2048'} + - rx_511_tx_unset: + fail_operation = define + rx_tx_attrs = {'rx_queue_size': '511'} + - rx_unset_tx_128: + rx_tx_attrs = {'tx_queue_size': '128'} + - rx_unset_tx_2048: + rx_tx_attrs = {'tx_queue_size': '2048'} + - rx_unset_tx_512: + rx_tx_attrs = {'tx_queue_size': '512'} + + iface_attrs = {'source': {'network': 'default'}, 'type_name': 'network', 'model': 'virtio', 'driver': {'driver_attr': {'name': 'vhost', 'queues': '5', **${rx_tx_attrs}}}} diff --git a/libvirt/tests/cfg/virtual_network/elements_and_attributes/element_mac_specific_addr.cfg b/libvirt/tests/cfg/virtual_network/elements_and_attributes/element_mac_specific_addr.cfg new file mode 100644 index 00000000000..40f1eb3708d --- /dev/null +++ b/libvirt/tests/cfg/virtual_network/elements_and_attributes/element_mac_specific_addr.cfg @@ -0,0 +1,39 @@ +- virtual_network.elements_and_attributes.mac.specific_addr: + type = element_mac_specific_addr + start_vm = no + timeout = 240 + outside_ip = 'www.redhat.com' + vm_ping_outside = pass + variants scenario: + - pre_set: + - hotplug: + variants: + - default: + mac = {} + expect_xml_mac = 52:54:00.* + expect_tap_mac = fe: + - starts_with_0xfe: + set_mac = 'fe:54:00:70:58:07' + mac = {'mac_address': '${set_mac}'} + expect_xml_mac = ${set_mac} + expect_tap_mac = fa: + - all_zeros: + func_supported_since_libvirt_ver = (9, 9, 0) + mac = {'mac_address': '00:00:00:00:00:00'} + expect_xml_mac = 52:54:00.* + expect_tap_mac = fe: + - multicast_addr: + mac = {'mac_address': '01:54:00:bc:f3:ec'} + status_error = yes + err_msg = expected unicast mac address, found multicast + - null_addr: + mac = {'mac_address': 'null'} + status_error = yes + err_msg = unable to parse mac address + - null_addr: + mac = {'mac_address': 'zero'} + status_error = yes + err_msg = unable to parse mac address + + iface_attrs = {**${mac}, 'model': 'virtio', 'type_name': 'network', 'source': {'network': 'default'}} + diff --git a/libvirt/tests/cfg/virtual_network/elements_and_attributes/element_model.cfg b/libvirt/tests/cfg/virtual_network/elements_and_attributes/element_model.cfg index 634314d458e..5b720226c24 100644 --- a/libvirt/tests/cfg/virtual_network/elements_and_attributes/element_model.cfg +++ b/libvirt/tests/cfg/virtual_network/elements_and_attributes/element_model.cfg @@ -18,9 +18,15 @@ - virtio: iface_driver = virtio_net pci_model = pcie-root-port + s390-virtio: + check_pci_model = no - e1000e: iface_driver = e1000e pci_model = pcie-root-port + - igb: + func_supported_since_libvirt_ver = (9, 3, 0) + iface_driver = igb + pci_model = pcie-root-port - rtl8139: iface_driver = 8139cp pci_model = pcie-to-pci-bridge @@ -30,5 +36,6 @@ - test: status_error = yes err_msg = is not a valid device model name - iface_attrs = {'source': {'network': 'default'}, 'model': '${model_type}', 'type_name': 'network', 'acpi': {'index': '1'}} - vm_iface = eno1 + s390-virtio: + check_pci_model = no + iface_attrs = {'source': {'network': 'default'}, 'model': '${model_type}', 'type_name': 'network'} diff --git a/libvirt/tests/cfg/virtual_network/hotplug/attach_detach_device/rollback_vdpafd_on_hotplug_failure.cfg b/libvirt/tests/cfg/virtual_network/hotplug/attach_detach_device/rollback_vdpafd_on_hotplug_failure.cfg new file mode 100644 index 00000000000..fd5797b058e --- /dev/null +++ b/libvirt/tests/cfg/virtual_network/hotplug/attach_detach_device/rollback_vdpafd_on_hotplug_failure.cfg @@ -0,0 +1,9 @@ +- virtual_network.hotplug.rollback.vdpa_interface: + type = rollback_vdpafd_on_hotplug_failure + start_vm = no + test_target = mellanox + vdpa_dev = "vdpa0" + iface_dict = {'source': {'dev': '/dev/vhost-vdpa-0'}, 'acpi': {'index': '1'}} + iface_dict2 = {'source': {'dev': '/dev/vhost-vdpa-1'}, 'acpi': {'index': '1'}} + func_supported_since_libvirt_ver = (10, 8, 0) + only x86_64 diff --git a/libvirt/tests/cfg/virtual_network/hotplug/attach_detach_interface/attach_interface_with_model.cfg b/libvirt/tests/cfg/virtual_network/hotplug/attach_detach_interface/attach_interface_with_model.cfg new file mode 100644 index 00000000000..7535c6dc3c0 --- /dev/null +++ b/libvirt/tests/cfg/virtual_network/hotplug/attach_detach_interface/attach_interface_with_model.cfg @@ -0,0 +1,27 @@ +- virtual_network.hotplug.attach_interface.model: + type = attach_interface_with_model + start_vm = no + timeout = 240 + outside_ip = 'www.redhat.com' + host_iface = + vm_ping_outside = pass + variants model_type: + - virtio: + iface_driver = virtio_net + pci_model = pcie-root-port + s390-virtio: + check_pci_model = no + bridge_controller_needed = no + - e1000e: + only x86_64 + iface_driver = e1000e + pci_model = pcie-root-port + - igb: + only x86_64 + func_supported_since_libvirt_ver = (9, 3, 0) + iface_driver = igb + pci_model = pcie-root-port + - rtl8139: + only x86_64 + iface_driver = 8139cp + pci_model = pcie-to-pci-bridge diff --git a/libvirt/tests/cfg/virtual_network/iface_attach_detach.cfg b/libvirt/tests/cfg/virtual_network/iface_attach_detach.cfg index 77f1bab5001..54d16028bdc 100644 --- a/libvirt/tests/cfg/virtual_network/iface_attach_detach.cfg +++ b/libvirt/tests/cfg/virtual_network/iface_attach_detach.cfg @@ -12,6 +12,7 @@ virsh_options = ' --config' variants scenario: - with_os_boot: + no s390-virtio error_msg = 'per-device boot elements cannot be used together with os/boot elements' - with_boot_disk: error_msg = 'boot order 1 is already used by another device' diff --git a/libvirt/tests/cfg/virtual_network/iface_bridge.cfg b/libvirt/tests/cfg/virtual_network/iface_bridge.cfg index 803a9ad166a..d2e413a0d78 100644 --- a/libvirt/tests/cfg/virtual_network/iface_bridge.cfg +++ b/libvirt/tests/cfg/virtual_network/iface_bridge.cfg @@ -4,6 +4,7 @@ vms = avocado-vt-vm1 vm2 bridge_name = "test_br0" netdst_nic1 = ${bridge_name} + host_iface = # Replace remote_ip by a actual IP address remote_ip = "www.google.com" ping_count = 3 diff --git a/libvirt/tests/cfg/virtual_network/iface_network.cfg b/libvirt/tests/cfg/virtual_network/iface_network.cfg index 3b3f7efa6ff..4c338770c9e 100644 --- a/libvirt/tests/cfg/virtual_network/iface_network.cfg +++ b/libvirt/tests/cfg/virtual_network/iface_network.cfg @@ -196,6 +196,7 @@ no_mac = "yes" - negative_without_ip: define_error = "yes" + only_test_define = "yes" no_ip = "yes" - negative_with_dev: define_error = "yes" @@ -328,7 +329,7 @@ portgroup_bandwidth_inbound = "{'average':'1000','peak':'5000','burst':'5120'} {'average':'500','peak':'2000','burst':'2560'}" portgroup_bandwidth_outbound = "{'average':'1000','peak':'5000','burst':'5120'} {'average':'128','peak':'256','burst':'256'}" iface_model = "rtl8139" - aarch64: + aarch64, s390-virtio: iface_model = "virtio" variants: - default_portgroup: diff --git a/libvirt/tests/cfg/virtual_network/iface_stat.cfg b/libvirt/tests/cfg/virtual_network/iface_stat.cfg index 9694b64722c..ec031c55329 100644 --- a/libvirt/tests/cfg/virtual_network/iface_stat.cfg +++ b/libvirt/tests/cfg/virtual_network/iface_stat.cfg @@ -22,3 +22,5 @@ - macvtap: func_supported_since_libvirt_ver = (9, 2, 0) iface_attrs = {'acpi': {'index': '5'}, 'target': {'dev': tap_name, 'managed': 'no'}, 'model': 'virtio', 'type_name': 'ethernet'} + s390-virtio: + iface_attrs = {'target': {'dev': tap_name, 'managed': 'no'}, 'model': 'virtio', 'type_name': 'ethernet'} diff --git a/libvirt/tests/cfg/virtual_network/iface_unprivileged.cfg b/libvirt/tests/cfg/virtual_network/iface_unprivileged.cfg index 0905a4cf7be..c8b93a8a87e 100644 --- a/libvirt/tests/cfg/virtual_network/iface_unprivileged.cfg +++ b/libvirt/tests/cfg/virtual_network/iface_unprivileged.cfg @@ -1,14 +1,12 @@ - virtual_network.iface_unprivileged: type = iface_unprivileged start_vm = no - up_user = 'test_upu' - user_vm_name = 'non_root_vm' - bridge_name = "test_br0" - # Replace remote_ip by a actual IP address - remote_ip = "www.google.com" - ping_count = 3 - ping_timeout = 10 - iface_name = + outside_ip = "www.redhat.com" + vm_ping_outside = pass + host_iface = + test_user = test + test_passwd = test + unpr_vm_name = unpr-vm variants: - precreated: case = 'precreated' diff --git a/libvirt/tests/cfg/virtual_network/iface_update.cfg b/libvirt/tests/cfg/virtual_network/iface_update.cfg index 33644f42f56..d864f40a9e1 100644 --- a/libvirt/tests/cfg/virtual_network/iface_update.cfg +++ b/libvirt/tests/cfg/virtual_network/iface_update.cfg @@ -75,23 +75,6 @@ - update_coalesce: iface_coalesce = {'max': 64} new_iface_coalesce = {'max': 32} - - update_portgroup: - bo_0 = {'average': '128', 'burst': '256', 'peak': '256'} - bi_0 = {'average': '1000', 'burst': '5120', 'peak': '5000'} - portgroup_0 = {'bandwidth_outbound': ${bo_0}, 'name': 'sales', 'bandwidth_inbound': ${bi_0}, 'default': 'yes'} - bo_1 = {'average': '256', 'burst': '512', 'peak': '128'} - bi_1 = {'average': '500', 'burst': '1024', 'peak': '1000'} - portgroup_1 = {'bandwidth_outbound': ${bi_1}, 'name': 'engineering', 'bandwidth_inbound': ${bo_1}} - net_attr_portgroups = [${portgroup_0}, ${portgroup_1}] - net_attr_nat_port = {'start': '1024', 'end': '65535'} - net_attr_bridge = {'name': 'virbr1', 'stp': 'on', 'delay': '0'} - net_attr_ips = [{'dhcp_ranges': {'attrs': {'end': '192.168.100.254', 'start': '192.168.100.100'}}, 'address': '192.168.100.1'}] - net_attr_forward = {'mode': 'nat'} - net_attr_mac = "'52:54:00:cf:11:a0'" - net_attr_uuid = "'a2ab8047-591e-4f95-80f6-ad47b518b9e0'" - iface_source = "{'network': 'default'}" - del_bandwidth = "yes" - new_iface_source = "{'network':'default', 'portgroup': 'engineering'}" - update_boot_order: cold_update = 'yes' disk_boot = '1' @@ -142,7 +125,7 @@ new_iface_rom = "{'enabled':'no'}" del_address = "yes" del_rom = "yes" - expect_err_msg = "Operation not supported: cannot modify network device rom enabled setting" + expect_err_msg = "Operation not supported:.*rom" - del_rom_enable: no s390-virtio iface_rom = "{'enabled':'yes'}" @@ -178,9 +161,9 @@ new_iface_outbound = "{'average':'128','peak':'256','burst':'256'}" expect_err_msg = "could not convert bandwidth average value|Expected non-negative integer value" - huge_val: - new_iface_inbound = "{'average':'10000000000000000','peak':'5000','burst':'1024'}" + new_iface_inbound = "{'average':'100000000000000000','peak':'5000','burst':'1024'}" new_iface_outbound = "{'average':'128','peak':'256','burst':'256'}" - expect_err_msg = 'Illegal "quantum"' + expect_err_msg = "too big for 'average' parameter, maximum is '18014398509481984'" - missing: new_iface_inbound = "{'peak':'5000','burst':'1024'}" new_iface_outbound = "{'peak':'256','burst':'256'}" @@ -200,6 +183,7 @@ - update_boot_order: variants: - with_os_boot: + no s390-virtio new_iface_boot = '1' expect_err_msg = 'per-device boot elements cannot be used together with os/boot elements' - boot_order_occupied: @@ -222,3 +206,21 @@ - vm_on: - vm_off: cold_update = 'yes' + - update_portgroup: + bo_0 = {'average': '128', 'burst': '256', 'peak': '256'} + bi_0 = {'average': '1000', 'burst': '5120', 'peak': '5000'} + portgroup_0 = {'bandwidth_outbound': ${bo_0}, 'name': 'sales', 'bandwidth_inbound': ${bi_0}, 'default': 'yes'} + bo_1 = {'average': '256', 'burst': '512', 'peak': '128'} + bi_1 = {'average': '500', 'burst': '1024', 'peak': '1000'} + portgroup_1 = {'bandwidth_outbound': ${bi_1}, 'name': 'engineering', 'bandwidth_inbound': ${bo_1}} + net_attr_portgroups = [${portgroup_0}, ${portgroup_1}] + net_attr_nat_port = {'start': '1024', 'end': '65535'} + net_attr_bridge = {'name': 'virbr1', 'stp': 'on', 'delay': '0'} + net_attr_ips = [{'dhcp_ranges': {'attrs': {'end': '192.168.100.254', 'start': '192.168.100.100'}}, 'address': '192.168.100.1'}] + net_attr_forward = {'mode': 'nat'} + net_attr_mac = "'52:54:00:cf:11:a0'" + net_attr_uuid = "'a2ab8047-591e-4f95-80f6-ad47b518b9e0'" + iface_source = "{'network': 'default'}" + del_bandwidth = "yes" + new_iface_source = "{'network':'default', 'portgroup': 'engineering'}" + expect_err_msg = 'cannot modify network device portgroup attribute' diff --git a/libvirt/tests/cfg/virtual_network/lifecycle/lifecycle_vdpa_interface.cfg b/libvirt/tests/cfg/virtual_network/lifecycle/lifecycle_vdpa_interface.cfg index 15ab0814e32..b2031b2ac3f 100644 --- a/libvirt/tests/cfg/virtual_network/lifecycle/lifecycle_vdpa_interface.cfg +++ b/libvirt/tests/cfg/virtual_network/lifecycle/lifecycle_vdpa_interface.cfg @@ -5,6 +5,7 @@ only x86_64 func_supported_since_libvirt_ver = (7, 3, 0) func_supported_since_qemu_kvm_ver = (6, 0, 0) + save_supported_ver = (8, 5, 0) iface_dict = {"source": {'dev':'/dev/vhost-vdpa-0'}} variants test_target: - simulator: diff --git a/libvirt/tests/cfg/virtual_network/lifecycle/restart_service.cfg b/libvirt/tests/cfg/virtual_network/lifecycle/restart_service.cfg new file mode 100644 index 00000000000..ff90b7fdff3 --- /dev/null +++ b/libvirt/tests/cfg/virtual_network/lifecycle/restart_service.cfg @@ -0,0 +1,5 @@ +- virtual_network.lifecycle.restart_service: + type = restart_service + start_vm = no + net_attrs = {'name': net_name, 'forward': {'mode': 'nat'}, 'ips': [{'dhcp_ranges': {'attrs': {'start': '192.168.23.2', 'end': '192.168.23.254'}}, 'netmask': '255.255.255.0', 'address': '192.168.23.1'}]} + diff --git a/libvirt/tests/cfg/virtual_network/link_state/link_state_model_type.cfg b/libvirt/tests/cfg/virtual_network/link_state/link_state_model_type.cfg new file mode 100644 index 00000000000..4b3aefe0057 --- /dev/null +++ b/libvirt/tests/cfg/virtual_network/link_state/link_state_model_type.cfg @@ -0,0 +1,48 @@ +- virtual_network.link_state.model: + type = link_state_model_type + start_vm = no + timeout = 240 + outside_ip = "www.redhat.com" + vm_ping_outside = pass + host_iface = + variants: + - initial_up: + initial_link_state = "up" + - initial_down: + initial_link_state = "down" + - without_state: + variants model_type: + - virtio: + - e1000e: + only x86_64 + - igb: + only x86_64 + func_supported_since_libvirt_ver = (9, 3, 0) + - rtl8139: + only x86_64 + variants interface_type: + - network: + iface_base_attrs = {"type_name": "network", "source": {"network": "default"}} + - direct: + only virtio + iface_base_attrs = {"type_name": "direct", "source": {"dev": host_iface, "mode": "bridge"}} + - user: + only virtio + variants: + - root: + iface_base_attrs = {"type_name": "user"} + - passt: + iface_base_attrs = {"backend": {"type": "passt"}, "source": {"dev": host_iface}, "type_name": "user"} + variants: + - root: + test_user = "root" + - unprivileged_user: + test_user = USER.EXAMPLE + test_passwd = PASSWORD.EXAMPLE + unpr_vm_name = UNPRIVILEGED_VM.EXAMPLE + - ethernet: + only virtio + create_tap = "yes" + iface_base_attrs = {"type_name": "ethernet", "target": {"dev": tap_name, "managed": "no"}} + + iface_attrs = {"model": "${model_type}", **${iface_base_attrs}} diff --git a/libvirt/tests/cfg/virtual_network/locked_memory_vdpa/hotplug_mem_to_vm_with_multiple_vdpa_interfaces.cfg b/libvirt/tests/cfg/virtual_network/locked_memory_vdpa/hotplug_mem_to_vm_with_multiple_vdpa_interfaces.cfg index 4553e1341c3..e6e306af5b7 100644 --- a/libvirt/tests/cfg/virtual_network/locked_memory_vdpa/hotplug_mem_to_vm_with_multiple_vdpa_interfaces.cfg +++ b/libvirt/tests/cfg/virtual_network/locked_memory_vdpa/hotplug_mem_to_vm_with_multiple_vdpa_interfaces.cfg @@ -1,4 +1,4 @@ -- virtual_network.locked_memory.vdpa_interfaceiface.multiple_interfaces.hotplug_mem: +- virtual_network.locked_memory.vdpa_interface.multiple_interfaces.hotplug_mem: type = hotplug_mem_to_vm_with_multiple_vdpa_interfaces start_vm = no only x86_64 diff --git a/libvirt/tests/cfg/virtual_network/locked_memory_vdpa/hotplug_mem_to_vm_with_vdpa.cfg b/libvirt/tests/cfg/virtual_network/locked_memory_vdpa/hotplug_mem_to_vm_with_vdpa.cfg new file mode 100644 index 00000000000..0a6809c426c --- /dev/null +++ b/libvirt/tests/cfg/virtual_network/locked_memory_vdpa/hotplug_mem_to_vm_with_vdpa.cfg @@ -0,0 +1,30 @@ +- virtual_network.locked_memory.vdpa_interface.hotplug_mem: + type = hotplug_mem_to_vm_with_vdpa + start_vm = no + + current_mem = 2 + current_mem_unit = 'GiB' + cpu_setting = {'numa_cell': [{'id': '0', 'cpus': '0-3', 'memory': '1', 'unit': 'GiB'}, {'id': '1', 'cpus': '4-7', 'memory': '1', 'unit': 'GiB'}]} + max_mem_rt = 6291456 + max_mem_rt_unit = 'K' + max_mem_rt_slots = 32 + vcpu = 8 + func_supported_since_libvirt_ver = (7, 3, 0) + func_supported_since_qemu_kvm_ver = (6, 0, 0) + iface_dict = {"source": {'dev':'/dev/vhost-vdpa-0'}} + only x86_64 + + variants test_target: + - simulator: + - mellanox: + variants test_scenario: + - at_memory_to_vm_with_iface: + vm_attrs = {'max_mem_rt': ${max_mem_rt}, 'max_mem_rt_slots': ${max_mem_rt_slots}, 'max_mem_rt_unit': '${max_mem_rt_unit}', 'current_mem': ${current_mem}, 'current_mem_unit': '${current_mem_unit}','vcpu': ${vcpu}, 'cpu': ${cpu_setting}} + mem_dict = {'mem_model': 'dimm', 'target': {'size': 1, 'size_unit': 'G', 'node': 0}} + - at_memory_to_vm_with_iface_and_locked_mem: + vm_attrs = {'max_mem_rt': ${max_mem_rt}, 'max_mem_rt_slots': ${max_mem_rt_slots}, 'max_mem_rt_unit': '${max_mem_rt_unit}', 'current_mem': ${current_mem}, 'current_mem_unit': '${current_mem_unit}','vcpu': ${vcpu},'memtune':{'hard_limit': 10485760, 'hard_limit_unit': 'KiB'}, 'mb': {'locked': True}, 'cpu': ${cpu_setting}} + mem_dict = {'mem_model': 'dimm', 'target': {'size': 1, 'size_unit': 'G', 'node': 0}} + - at_iface_and_memory: + vm_attrs = {'max_mem_rt': ${max_mem_rt}, 'max_mem_rt_slots': ${max_mem_rt_slots}, 'max_mem_rt_unit': '${max_mem_rt_unit}', 'current_mem': ${current_mem}, 'current_mem_unit': '${current_mem_unit}','vcpu': ${vcpu}, 'cpu': ${cpu_setting}} + mem_dict1 = {'mem_model': 'dimm', 'target': {'size': 256, 'size_unit': 'M', 'node': 0}} + mem_dict2 = {'mem_model': 'dimm', 'target': {'size': 256, 'size_unit': 'M', 'node': 1}} diff --git a/libvirt/tests/cfg/virtual_network/locked_memory_vdpa/mem_lock_limit_multiple_vdpa_interfaces.cfg b/libvirt/tests/cfg/virtual_network/locked_memory_vdpa/mem_lock_limit_multiple_vdpa_interfaces.cfg new file mode 100644 index 00000000000..844ccde56b5 --- /dev/null +++ b/libvirt/tests/cfg/virtual_network/locked_memory_vdpa/mem_lock_limit_multiple_vdpa_interfaces.cfg @@ -0,0 +1,10 @@ +- virtual_network.locked_memory.vdpa_interface.multiple_interfaces: + type = mem_lock_limit_multiple_vdpa_interfaces + start_vm = no + only x86_64 + + func_supported_since_libvirt_ver = (8, 7, 0) + vm_attrs = {'max_mem_rt': 6291456, 'max_mem_rt_slots': 32, 'max_mem_rt_unit': 'K', 'current_mem':3, 'current_mem_unit': 'GiB','vcpu': 8, 'cpu': {'numa_cell': [{'id': '0', 'cpus': '0-3', 'memory': '1', 'unit': 'GiB'}, {'id': '1', 'cpus': '4-7', 'memory': '1', 'unit': 'GiB'}]}} + iface_dict1 = {"source": {'dev':'/dev/vhost-vdpa-0'}} + iface_dict2 = {"source": {'dev':'/dev/vhost-vdpa-1'}} + iface_dict3 = {"source": {'dev':'/dev/vhost-vdpa-2'}} diff --git a/libvirt/tests/cfg/virtual_network/mtu.cfg b/libvirt/tests/cfg/virtual_network/mtu.cfg index bb6635cca7c..c55f088100d 100644 --- a/libvirt/tests/cfg/virtual_network/mtu.cfg +++ b/libvirt/tests/cfg/virtual_network/mtu.cfg @@ -43,7 +43,7 @@ - tap: create_tap = yes tap_mtu_size = 2000 - tap_cmd = 'ip tuntap add mode tap name {tap_name};ip link set dev {tap_name} mtu ${tap_mtu_size}' + tap_cmd = 'ip tuntap add mode tap name {tap_name} multi_queue;ip link set dev {tap_name} mtu ${tap_mtu_size}' variants: - managed_no: iface_target = {'dev': '%s', 'managed': 'no'} diff --git a/libvirt/tests/cfg/virtual_network/network/elements_and_attributes/network_static_route.cfg b/libvirt/tests/cfg/virtual_network/network/elements_and_attributes/network_static_route.cfg new file mode 100644 index 00000000000..4e47a588a16 --- /dev/null +++ b/libvirt/tests/cfg/virtual_network/network/elements_and_attributes/network_static_route.cfg @@ -0,0 +1,12 @@ +- virtual_network.network.static_route: + type = network_static_route + start_vm = "no" + variants: + - start_test: + net_name = "network_def" + net_attrs = {'name': net_name, 'forward': {'mode': 'nat'}, 'ips': [{'dhcp_ranges': {'attrs': {'start': '192.168.120.2', 'end': '192.168.120.254'}}, 'address': '192.168.120.1', 'netmask': '255.255.255.0'}, {'family': 'ipv6', 'address': '2001:db8:ca2:2::1', 'prefix': '64'}], 'routes': [{'address':'192.168.222.0','prefix':'24','gateway':'192.168.120.2'}, {'family':'ipv6','address':'2001:db8:ca2:3::','prefix':'64','gateway':'2001:db8:ca2:2::2'},{'family':'ipv6','address':'2001:db9:4:1::','prefix':'64','gateway':'2001:db8:ca2:2::3','metric':'2'}]} + ipv4_associated_route = '192.168.120.0/24' + ipv4_defined_route = '192.168.222.0/24' + ipv6_associated_route = '2001:db8:ca2:2::/64' + ipv6_defined_routes = "['2001:db8:ca2:3::/64', '2001:db9:4:1::/64']" + diff --git a/libvirt/tests/cfg/virtual_network/network/net_update_dns.cfg b/libvirt/tests/cfg/virtual_network/network/net_update_dns.cfg new file mode 100644 index 00000000000..b33c0aa12b1 --- /dev/null +++ b/libvirt/tests/cfg/virtual_network/network/net_update_dns.cfg @@ -0,0 +1,37 @@ +- virtual_network.network.net_update_dns: + type = net_update_dns + start_vm = no + timeout = 240 + host_iface = + dns_host = {'host': {'host_ip': '192.168.10.2', 'hostnames': [{'hostname': 'myhost'}, {'hostname': 'myhostalias'}]}} + dns_txt = {'txt': {'name': 'example', 'value': 'example value'}} + dns_srv = {'srv': {'service': 'name', 'protocol': 'tcp', 'domain': 'test-domain-name', 'target': 'englab.nay.redhat.com', 'port': '1024', 'priority': '10', 'weight': '10'}} + dns_attrs = {**${dns_host}, **${dns_txt}, **${dns_srv}} + func_supported_since_libvirt_ver = (10, 6, 0) + variants dns_ele: + - dns-txt: + variants: + - default: + update_xml = '''''''' + update_attrs = {'name': 'example', 'value': 'new value'} + conf_val = txt-record=example,new value + - incomplete: + status_error = yes + err_msg = Failed to update network + variants: + - no_value: + update_xml = '''''''' + - no_name: + update_xml = '''''''' + - dns-host: + variants: + - default: + update_attrs = {'host_ip': '192.168.10.2', 'hostnames': [{'hostname': 'myserver'}, {'hostname': 'my_new_server'}, {'hostname': 'my_new_dhcp_server'}]} + conf_val = '192.168.10.2\s+myserver\s+my_new_server\s+my_new_dhcp_server' + - not_match: + status_error = yes + err_msg = Failed to update network + update_attrs = {'host_ip': '192.168.10.5', 'hostnames': ['myhost', 'myhostalias']} + post_check = check_pid_not_change + variants operation: + - modify: diff --git a/libvirt/tests/cfg/virtual_network/network/virsh_cmds/virsh_net_desc.cfg b/libvirt/tests/cfg/virtual_network/network/virsh_cmds/virsh_net_desc.cfg new file mode 100644 index 00000000000..d55a4c72daf --- /dev/null +++ b/libvirt/tests/cfg/virtual_network/network/virsh_cmds/virsh_net_desc.cfg @@ -0,0 +1,47 @@ +- virtual_network.network.net_desc: + type = virsh_net_desc + net_name = "default" + func_supported_since_libvirt_ver = (9, 8, 0) + variants update_method: + - cmdline: + - edit_space: + variants update_item: + - title: + net_title = "network title" + execute_cmd =" --title '${net_title}'" + expected_xml = '${net_title}' + expected_str = ${net_title} + net_title_update = "network title update" + execute_update_cmd =" --title '${net_title_update}'" + expected_update_xml = '${net_title_update}' + expected_update_str = ${net_title_update} + remove_opt = " --title '' " + removed_msg = "No title for network: default" + get_cmd = ' --title' + - description: + net_desc = "network description" + execute_cmd = "${net_desc}" + expected_xml = '${net_desc}' + expected_str = ${net_desc} + net_desc_update = "network description update" + execute_update_cmd =" ${net_desc_update}" + expected_update_xml = '${net_desc_update}' + expected_update_str = ${net_desc_update} + remove_opt = "''" + removed_msg = "No description for network: default" + get_cmd = ' ' + variants network_states: + - active_net: + - inactive_net: + variants: + - live: + opt = ' --live' + inactive_net: + error_msg = "error: Requested operation is not valid: network is not running" + - config: + opt = ' --config' + - current: + opt = ' --current' + - opt_none: + no inactive_net + opt = ' ' diff --git a/libvirt/tests/cfg/virtual_network/network/virsh_cmds/virsh_net_metadata.cfg b/libvirt/tests/cfg/virtual_network/network/virsh_cmds/virsh_net_metadata.cfg new file mode 100644 index 00000000000..ff2fea43c80 --- /dev/null +++ b/libvirt/tests/cfg/virtual_network/network/virsh_cmds/virsh_net_metadata.cfg @@ -0,0 +1,44 @@ +- virtual_network.network.net_metadata: + type = virsh_net_metadata + net_name = "default" + metadata_uri = "http://app.org/" + prefix = "test" + ele_name = "head" + metadata_extra = " --key ${prefix} --set '<${ele_name}/>' " + expected_xml = "<${ele_name}/>" + expected_metadata_xml = '\n.*<${prefix}:${ele_name} xmlns:${prefix}="${metadata_uri}"/>\n.*' + prefix_update = "abc" + ele_update = "body" + metadata_extra_update = " --key ${prefix_update} --set '<${ele_update}/>' " + expected_update_xml = "<${ele_update}/>" + expected_update_metadata_xml = '\n.*<${prefix_update}:${ele_update} xmlns:${prefix_update}="${metadata_uri}"/>\n.*' + exist = "yes" + remove_opt = " --remove" + removed_msg = "error: metadata not found: Requested metadata element is not present" + func_supported_since_libvirt_ver = (9, 8, 0) + variants update_method: + - cmdline: + - edit_space: + variants network_states: + - active_net: + - inactive_net: + variants: + - live: + opt = ' --live' + inactive_net: + error_msg = "error: Requested operation is not valid: network is not running" + - config: + opt = ' --config' + - current: + opt = ' --current' + - opt_none: + opt = ' ' + variants: + - active_dumpxml: + dumpxml_opt = " " + config.active_net: + exist = "no" + - inactive_dumpxml: + dumpxml_opt = " --inactive" + live, current.active_net, opt_none.active_net: + exist = "no" diff --git a/libvirt/tests/cfg/virtual_network/network_misc.cfg b/libvirt/tests/cfg/virtual_network/network_misc.cfg index 26bd0ed029b..8aef75b2ba7 100644 --- a/libvirt/tests/cfg/virtual_network/network_misc.cfg +++ b/libvirt/tests/cfg/virtual_network/network_misc.cfg @@ -4,7 +4,21 @@ variants test_group: - zone: variants case: + - libvirt_managed: + br_attrs = {'stp': 'on', 'delay': '0'} + variants forward_mode: + - nat: + default_zone = libvirt + - route: + default_zone = libvirt-routed + - isolated: + default_zone = libvirt + - open: + default_zone = no zone + net_attrs = {'forward': {'mode': '${forward_mode}'}, 'name': net_name, 'ips': [{'address': '192.168.152.1', 'netmask': '255.255.255.0', 'dhcp_ranges': {'attrs': {'start': '192.168.152.2', 'end': '192.168.152.254'}}}]} + expect_str = ['${default_zone} (active)', 'target: ACCEPT', 'interfaces: .*%s' % br, 'services: dhcp dhcpv6 dns ssh tftp', 'protocols: icmp ipv6-icmp', 'rule priority="32767" reject'] - public: + net_attrs = {'forward': {'mode': 'nat'}, 'name': net_name, 'bridge': {'zone': 'public'}, 'ips': [{'address': '192.168.152.1', 'netmask': '255.255.255.0', 'dhcp_ranges': {'attrs': {'start': '192.168.152.2', 'end': '192.168.152.254'}}}]} - info: expect_str = ['libvirt (active)', 'target: ACCEPT', 'interfaces: .*%s' % br, 'services: dhcp dhcpv6 dns ssh tftp', 'protocols: icmp ipv6-icmp', 'rule priority="32767" reject'] - iface_acpi: diff --git a/libvirt/tests/cfg/virtual_network/passt/passt_attach_detach.cfg b/libvirt/tests/cfg/virtual_network/passt/passt_attach_detach.cfg index 4b0062b4d56..9f659d9ddb6 100644 --- a/libvirt/tests/cfg/virtual_network/passt/passt_attach_detach.cfg +++ b/libvirt/tests/cfg/virtual_network/passt/passt_attach_detach.cfg @@ -5,6 +5,7 @@ outside_ip = 'www.redhat.com' start_vm = no mtu = 65520 + multiple_nexthops = yes variants user_type: - root_user: test_user = root @@ -24,6 +25,11 @@ - detach: add_iface = yes - attach_detach: + variants: + - default: + - vhostuser: + vhostuser = yes + func_supported_since_libvirt_ver = (10, 10, 0) variants: - ip_portfw: alias = {'name': 'ua-c87b89ff-b769-4abc-921f-30d42d7aec5b'} @@ -36,12 +42,14 @@ iface_attrs = {'model': 'virtio', 'acpi': {'index': '1'}, 'ips': ${ips}, 'backend': ${backend}, 'source': {'dev': '${host_iface}'}, 'alias': ${alias}, 'type_name': 'user', 'portForwards': ${portForwards}} proc_checks = ['--tcp-ports 31339:41339', '--udp-ports 2025', f'--tcp-ports {host_ip}/9000'] ipv6_prefix = 128 - vm_iface = eno1 vm_ping_outside = pass vm_ping_host_public = pass tcp_port_list = [9000, '*:31339'] - udp_port_list = ['0.0.0.0:2025', '[::]:2025'] + udp_port_list = ['*:2025'] conn_check_args_0 = ('TCP4', 'localhost', 31339, 41339, True, None) conn_check_args_1 = ('TCP6', 'localhost', 31339, 41339, True, None) conn_check_args_2 = ('UDP4', 'localhost', 2025, 2025, True, None) conn_check_args_3 = ('UDP6', 'localhost', 2025, 2025, True, None) + s390-virtio: + iface_attrs = {'model': 'virtio', 'ips': ${ips}, 'backend': ${backend}, 'source': {'dev': '${host_iface}'}, 'alias': ${alias}, 'type_name': 'user', 'portForwards': ${portForwards}} + vm_iface = enc1 diff --git a/libvirt/tests/cfg/virtual_network/passt/passt_connectivity_between_2vms.cfg b/libvirt/tests/cfg/virtual_network/passt/passt_connectivity_between_2vms.cfg index 09cf6bd6d07..2df722f8527 100644 --- a/libvirt/tests/cfg/virtual_network/passt/passt_connectivity_between_2vms.cfg +++ b/libvirt/tests/cfg/virtual_network/passt/passt_connectivity_between_2vms.cfg @@ -36,8 +36,14 @@ ipv6_addr_c = '2001:db8:ac10:fd01::20' ips = {'ips': [{'address': '${ipv4_addr_c}', 'family': 'ipv4', 'prefix': '24'}, {'address': '${ipv6_addr_c}', 'family': 'ipv6'}]} iface_c_attrs = {'model': 'virtio', 'acpi': {'index': '1'}, **${ips}, 'backend': ${backend}, 'source': {'dev': '${host_iface}'}, 'type_name': 'user'} - vm_c_iface = eno1 conn_check_args_0 = ('TCP4', server_default_gw, None, 41335, 41335) conn_check_args_1 = ('TCP6', server_default_gw_v6, vm_c_iface, 41335, 41335) conn_check_args_2 = ('UDP4', server_default_gw, None, 21335, 21335) conn_check_args_3 = ('UDP6', server_default_gw_v6, vm_c_iface, 21335, 21335) + s390-virtio: + iface_attrs = {'model': 'virtio', **${ips}, 'backend': ${backend}, 'source': {'dev': '${host_iface}'}, 'type_name': 'user', **${portForwards}} + iface_c_attrs = {'model': 'virtio', **${ips}, 'backend': ${backend}, 'source': {'dev': '${host_iface}'}, 'type_name': 'user'} + conn_check_args_0 = ('TCP4', server_default_gw, None, 41335, 41335) + conn_check_args_1 = ('TCP6', server_default_gw_v6, vm_c_iface, 41335, 41335) + conn_check_args_2 = ('UDP4', server_default_gw, None, 21335, 21335) + conn_check_args_3 = ('UDP6', server_default_gw_v6, vm_c_iface, 21335, 21335) diff --git a/libvirt/tests/cfg/virtual_network/passt/passt_function.cfg b/libvirt/tests/cfg/virtual_network/passt/passt_function.cfg index f8951abd3f9..7442b461675 100644 --- a/libvirt/tests/cfg/virtual_network/passt/passt_function.cfg +++ b/libvirt/tests/cfg/virtual_network/passt/passt_function.cfg @@ -5,6 +5,7 @@ outside_ip = 'www.redhat.com' start_vm = no mtu = 65520 + multiple_nexthops = yes variants user_type: - root_user: test_user = root @@ -14,38 +15,72 @@ - non_root_user: test_user = USER.EXAMPLE test_passwd = PASSWORD.EXAMPLE - user_id = + user_id = unpr_vm_name = UNPRIVILEGED_VM.EXAMPLE socket_dir = f'/run/user/{user_id}/libvirt/qemu/run/passt/' variants scenario: - minimal: - iface_attrs = {'model': 'virtio', 'acpi': {'index': '1'}, 'type_name': 'user', 'backend': {'type': 'passt'}, 'source': {'dev': '${host_iface}'}} + iface_attrs = {'model': 'virtio', 'acpi': {'index': '1'}, 'type_name': 'user', 'backend': {'type': 'passt'}, 'source': {'dev': host_iface}} vm_iface = eno1 vm_ping_outside = pass + s390-virtio: + iface_attrs = {'model': 'virtio', 'type_name': 'user', 'backend': {'type': 'passt'}, 'source': {'dev': host_iface}} + vm_iface = enc1 - ip_portfw: + ipv6_prefix = 128 alias = {'name': 'ua-c87b89ff-b769-4abc-921f-30d42d7aec5b'} backend = {'type': 'passt'} ips = [{'address': '172.17.2.4', 'family': 'ipv4', 'prefix': '24'}, {'address': '2001:db8:ac10:fd01::20', 'family': 'ipv6'}] - portForward_0 = {'attrs': {'proto': 'tcp'}, 'ranges': [{'start': '31339', 'to': '41339'}]} - portForward_1 = {'attrs': {'proto': 'udp'}, 'ranges': [{'start': '2025'}]} - portForward_2 = {'attrs': {'proto': 'tcp', 'address': host_ip}, 'ranges': [{'start': '4025', 'end': '4035', 'to': '5025'},{'start': '9000'}, {'start': '4030', 'end': '4034', 'exclude': 'yes'}]} - portForward_3 = {'attrs': {'proto': 'udp', 'address': host_ip_v6}, 'ranges': [{'start': '8002'}, {'start': '4431', 'to': '4432'}]} - portForwards = [${portForward_0}, ${portForward_1}, ${portForward_2}, ${portForward_3}] - iface_attrs = {'model': 'virtio', 'acpi': {'index': '1'}, 'ips': ${ips}, 'backend': ${backend}, 'source': {'dev': '${host_iface}'}, 'alias': ${alias}, 'type_name': 'user', 'portForwards': ${portForwards}} - proc_checks = ['--tcp-ports 31339:41339', '--udp-ports 2025', f'--tcp-ports {host_ip}/4025-4035:5025-5035,9000,~4030-4034', f'--udp-ports {host_ip_v6}/8002,4431:4432'] - ipv6_prefix = 128 vm_iface = eno1 vm_ping_outside = pass vm_ping_host_public = pass - tcp_port_list = [4025, 4026, 4027, 4028, 4029, 4035, 9000, '*:31339'] - udp_port_list = ['0.0.0.0:2025', '[::]:2025', f'[{host_ip_v6}]:4431', f'[{host_ip_v6}]:8002'] - conn_check_args_0 = ('TCP4', 'localhost', 31339, 41339, True, None) - conn_check_args_1 = ('TCP4', host_ip, 31339, 41339, True, None) - conn_check_args_2 = ('TCP4', host_ip, 4025, 5025, True, None) - conn_check_args_3 = ('TCP4', 'localhost', 4025, 5025, False, 'Connection refused') - conn_check_args_4 = ('TCP4', host_ip, 4030, 4030, False, 'Connection refused') - conn_check_args_5 = ('TCP6', 'localhost', 31339, 41339, True, None) - conn_check_args_6 = ('TCP6', '::1', 31339, 41339, True, None) - conn_check_args_7 = ('UDP4', 'localhost', 2025, 2025, True, None) - conn_check_args_8 = ('UDP6', host_ip_v6, 4431, 4432, True, None) - conn_check_args_9 = ('UDP6', '::1', 4431, 4432, False, None) + s390-virtio: + vm_iface = enc1 + variants: + - ip_addr: + portForward_0 = {'attrs': {'proto': 'tcp'}, 'ranges': [{'start': '31339', 'to': '41339'}]} + portForward_1 = {'attrs': {'proto': 'udp'}, 'ranges': [{'start': '2025'}]} + portForward_2 = {'attrs': {'proto': 'tcp', 'address': host_ip}, 'ranges': [{'start': '4025', 'end': '4035', 'to': '5025'},{'start': '9000'}, {'start': '4030', 'end': '4034', 'exclude': 'yes'}]} + portForward_3 = {'attrs': {'proto': 'udp', 'address': host_ip_v6}, 'ranges': [{'start': '8002'}, {'start': '4431', 'to': '4432'}]} + portForwards = [${portForward_0}, ${portForward_1}, ${portForward_2}, ${portForward_3}] + proc_checks = ['--tcp-ports 31339:41339', '--udp-ports 2025', f'--tcp-ports {host_ip}/4025-4035:5025-5035,9000,~4030-4034', f'--udp-ports {host_ip_v6}/8002,4431:4432'] + tcp_port_list = [4025, 4026, 4027, 4028, 4029, 4035, 9000, '*:31339'] + udp_port_list = ['*:2025', f'[{host_ip_v6}]:4431', f'[{host_ip_v6}]:8002'] + conn_check_args_0 = ('TCP4', host_ip, 31339, 41339, True, None) + conn_check_args_1 = ('TCP4', host_ip, 4025, 5025, True, None) + conn_check_args_2 = ('TCP4', 'localhost', 4025, 5025, False, 'Connection refused') + conn_check_args_3 = ('TCP4', 'localhost', 31339, 41339, True, None) + conn_check_args_4 = ('TCP4', host_ip, 4030, 4030, False, 'Connection refused') + conn_check_args_5 = ('TCP6', 'localhost', 31339, 41339, True, None) + conn_check_args_6 = ('TCP6', '::1', 31339, 41339, True, None) + conn_check_args_7 = ('UDP4', 'localhost', 2025, 2025, True, None) + conn_check_args_8 = ('UDP6', host_ip_v6, 4431, 4432, True, None) + conn_check_args_9 = ('UDP6', '::1', 4431, 4432, False, None) + - dev_only: + portForward_0 = {'attrs': {'proto': 'tcp', 'dev': host_iface}, 'ranges': [{'start': '31339', 'to': '41339'}]} + portForward_1 = {'attrs': {'proto': 'udp', 'dev': host_iface}, 'ranges': [{'start': '2025'}]} + portForwards = [${portForward_0}, ${portForward_1}] + tcp_port_list = [f'*%{host_iface}:31339'] + udp_port_list = [f'*%{host_iface}:2025'] + conn_check_args_1 = ('TCP4', host_ip, 31339, 41339, True, None) + conn_check_args_2 = ('TCP6', host_ip_v6, 31339, 41339, True, None) + conn_check_args_3 = ('UDP4', host_ip, 2025, 2025, True, None) + conn_check_args_4 = ('UDP6', host_ip_v6, 2025, 2025, True, None) + - dev_and_ip: + portForward_0 = {'attrs': {'proto': 'tcp', 'address': host_ip, 'dev': host_iface}, 'ranges': [{'start': '31339', 'to': '41339'}]} + portForward_1 = {'attrs': {'proto': 'udp', 'address': host_ip, 'dev': host_iface}, 'ranges': [{'start': '2025'}]} + portForward_2 = {'attrs': {'proto': 'tcp', 'address': host_ip_v6, 'dev': host_iface}, 'ranges': [{'start': '51339'}]} + portForwards = [${portForward_0}, ${portForward_1}, ${portForward_2}] + tcp_port_list = [f'{host_ip}%{host_iface}:31339', f'[{host_ip_v6}]%{host_iface}:51339'] + udp_port_list = [f'{host_ip}%{host_iface}:2025'] + conn_check_args_1 = ('TCP4', host_ip, 31339, 41339, True, None) + conn_check_args_2 = ('UDP4', host_ip, 2025, 2025, True, None) + conn_check_args_3 = ('TCP6', host_ip_v6, 51339, 51339, True, None) + iface_attrs = {'model': 'virtio', 'acpi': {'index': '1'}, 'ips': ${ips}, 'backend': ${backend}, 'source': {'dev': host_iface}, 'alias': ${alias}, 'type_name': 'user', 'portForwards': ${portForwards}} + s390-virtio: + iface_attrs = {'model': 'virtio', 'ips': ${ips}, 'backend': ${backend}, 'source': {'dev': host_iface}, 'alias': ${alias}, 'type_name': 'user', 'portForwards': ${portForwards}} + variants: + - default: + - vhostuser: + vhostuser = yes + func_supported_since_libvirt_ver = (10, 10, 0) diff --git a/libvirt/tests/cfg/virtual_network/passt/passt_lifecycle.cfg b/libvirt/tests/cfg/virtual_network/passt/passt_lifecycle.cfg new file mode 100644 index 00000000000..64ed3b6c5d4 --- /dev/null +++ b/libvirt/tests/cfg/virtual_network/passt/passt_lifecycle.cfg @@ -0,0 +1,68 @@ +- virtual_network.passt.lifecycle: + type = passt_lifecycle + func_supported_since_libvirt_ver = (9, 0, 0) + host_iface = + outside_ip = 'www.redhat.com' + start_vm = no + mtu = 65520 + multiple_nexthops = no + variants operation: + - save_restore: + operation_a = save + operation_b = restore + options_a = {'name': vm_name, 'path': save_path} + options_b = {'path': save_path} + passt_running = no + - managedsave_start: + operation_a = managedsave + operation_b = start + passt_running = no + - suspend_resume: + operation_a = suspend + operation_b = resume + passt_running = yes + variants: + - default: + - vhostuser: + vhostuser = yes + func_supported_since_libvirt_ver = (10, 10, 0) + variants user_type: + - non_root_user: + test_user = USER.EXAMPLE + test_passwd = PASSWORD.EXAMPLE + user_id = + unpr_vm_name = UNPRIVILEGED_VM.EXAMPLE + socket_dir = f'/run/user/{user_id}/libvirt/qemu/run/passt/' + - root_user: + test_user = root + user_id = 107 + log_dir = /run/user/${user_id} + socket_dir = f'/run/libvirt/qemu/passt/' + variants scenario: + - ip_portfw: + ipv6_prefix = 128 + alias = {'name': 'ua-c87b89ff-b769-4abc-921f-30d42d7aec5b'} + backend = {'type': 'passt'} + ips = [{'address': '172.17.2.4', 'family': 'ipv4', 'prefix': '24'}, {'address': '2001:db8:ac10:fd01::20', 'family': 'ipv6'}] + vm_iface = eno1 + vm_ping_outside = pass + vm_ping_host_public = pass + portForward_0 = {'attrs': {'proto': 'tcp'}, 'ranges': [{'start': '31339', 'to': '41339'}]} + portForward_1 = {'attrs': {'proto': 'udp'}, 'ranges': [{'start': '2025'}]} + portForward_2 = {'attrs': {'proto': 'tcp', 'address': host_ip}, 'ranges': [{'start': '4025', 'end': '4035', 'to': '5025'},{'start': '9000'}, {'start': '4030', 'end': '4034', 'exclude': 'yes'}]} + portForwards = [${portForward_0}, ${portForward_1}, ${portForward_2}] + proc_checks = ['--tcp-ports 31339:41339', '--udp-ports 2025', f'--tcp-ports {host_ip}/4025-4035:5025-5035,9000,~4030-4034'] + tcp_port_list = [4025, 4026, 4027, 4028, 4029, 4035, 9000, '*:31339'] + udp_port_list = ['*:2025'] + conn_check_args_0 = ('TCP4', host_ip, 31339, 41339, True, None) + conn_check_args_1 = ('TCP4', host_ip, 4025, 5025, True, None) + conn_check_args_2 = ('TCP4', 'localhost', 4025, 5025, False, 'Connection refused') + conn_check_args_3 = ('TCP4', 'localhost', 31339, 41339, True, None) + conn_check_args_4 = ('TCP4', host_ip, 4030, 4030, False, 'Connection refused') + conn_check_args_5 = ('TCP6', 'localhost', 31339, 41339, True, None) + conn_check_args_6 = ('TCP6', '::1', 31339, 41339, True, None) + conn_check_args_7 = ('UDP4', 'localhost', 2025, 2025, True, None) + iface_attrs = {'model': 'virtio', 'acpi': {'index': '1'}, 'ips': ${ips}, 'backend': ${backend}, 'source': {'dev': host_iface}, 'alias': ${alias}, 'type_name': 'user', 'portForwards': ${portForwards}} + s390-virtio: + vm_iface = enc1 + iface_attrs = {'model': 'virtio', 'ips': ${ips}, 'backend': ${backend}, 'source': {'dev': host_iface}, 'alias': ${alias}, 'type_name': 'user', 'portForwards': ${portForwards}} diff --git a/libvirt/tests/cfg/virtual_network/passt/passt_negative_setting.cfg b/libvirt/tests/cfg/virtual_network/passt/passt_negative_setting.cfg index 6dcec38bb14..400a56c7aa3 100644 --- a/libvirt/tests/cfg/virtual_network/passt/passt_negative_setting.cfg +++ b/libvirt/tests/cfg/virtual_network/passt/passt_negative_setting.cfg @@ -27,21 +27,22 @@ log_file = /var/log/passt.log error_msg = "Couldn't open log file .*: Permission denied" - rm_passt_pgk: - error_msg = unable to get SELinux context for '/usr/bin/passt': No such file or directory + error_msg = "No such file or directory" - non_exist_host_iface: host_iface = eno999 error_msg = Invalid interface name .*: No such device - inactive_host_iface: error_msg = External interface not usable + passt_version = 0^20250121.g4f2c8e7 - non_exist_bind_ip: portForwards = {'portForwards': [{'ranges': [{'start': '9000'}], 'attrs': {'proto': 'tcp', 'address': 'IP_EXAMPLE'}}]} - error_msg = Failed to bind any port for '-t .*', exiting + error_msg = Failed to bind port - port_occupied: portForwards = {'portForwards': [{'ranges': [{'start': 'PORT_EXAMPLE'}], 'attrs': {'proto': 'tcp'}}]} - error_msg = Failed to bind any port for '-t .*', exiting + error_msg = Failed to bind port - port_under_1024: portForwards = {'portForwards': [{'ranges': [{'start': 'PORT_EXAMPLE'}], 'attrs': {'proto': 'tcp'}}]} - error_msg = Failed to bind any port for '-t .*', exiting + error_msg = Failed to bind port - port_outofrange: port = 65536 portForwards = {'portForwards': [{'ranges': [{'start': '${port}'}], 'attrs': {'proto': 'tcp'}}]} diff --git a/libvirt/tests/cfg/virtual_network/passt/passt_reconnect.cfg b/libvirt/tests/cfg/virtual_network/passt/passt_reconnect.cfg index 023d3911a4b..f1b42407108 100644 --- a/libvirt/tests/cfg/virtual_network/passt/passt_reconnect.cfg +++ b/libvirt/tests/cfg/virtual_network/passt/passt_reconnect.cfg @@ -5,7 +5,7 @@ outside_ip = 'www.redhat.com' start_vm = no mtu = 65520 - qemu_cmd_check = "reconnect":5 + multiple_nexthops = no variants user_type: - root_user: test_user = root @@ -20,6 +20,11 @@ unpr_vm_name = UNPRIVILEGED_VM.EXAMPLE virsh_uri = 'qemu+ssh://${test_user}@localhost/session' socket_dir = f'/run/user/{user_id}/libvirt/qemu/run/passt/' + variants: + - default: + - vhostuser: + vhostuser = 'yes' + func_supported_since_libvirt_ver = (10, 10, 0) variants: - ip_portfw: alias = {'alias': {'name': 'ua-c87b89ff-b769-4abc-921f-30d42d7aec5b'}} @@ -35,8 +40,11 @@ vm_ping_outside = pass vm_ping_host_public = pass tcp_port_list = ['*:31339'] - udp_port_list = ['0.0.0.0:2025', '[::]:2025'] + udp_port_list = ['*:2025'] conn_check_args_0 = ('TCP4', 'localhost', 31339, 41339, True, None) conn_check_args_1 = ('TCP6', 'localhost', 31339, 41339, True, None) conn_check_args_2 = ('UDP4', 'localhost', 2025, 2025, True, None) conn_check_args_3 = ('UDP6', 'localhost', 2025, 2025, True, None) + s390-virtio: + iface_attrs = {'model': 'virtio', **${ips}, 'backend': ${backend}, 'source': {'dev': '${host_iface}'}, **${alias}, 'type_name': 'user', **${portForwards}} + vm_iface = enc1 diff --git a/libvirt/tests/cfg/virtual_network/passt/passt_transfer_file.cfg b/libvirt/tests/cfg/virtual_network/passt/passt_transfer_file.cfg index f5182c27464..278e118fadd 100644 --- a/libvirt/tests/cfg/virtual_network/passt/passt_transfer_file.cfg +++ b/libvirt/tests/cfg/virtual_network/passt/passt_transfer_file.cfg @@ -4,6 +4,7 @@ host_iface = outside_ip = 'www.redhat.com' start_vm = no + multiple_nexthops = no variants user_type: - root_user: test_user = root @@ -18,6 +19,11 @@ unpr_vm_name = UNPRIVILEGED_VM.EXAMPLE virsh_uri = 'qemu+ssh://${test_user}@localhost/session' socket_dir = f'/run/user/{user_id}/libvirt/qemu/run/passt/' + variants: + - default: + - vhostuser: + vhostuser = 'yes' + func_supported_since_libvirt_ver = (10, 10, 0) variants: - ip_portfw: alias = {'alias': {'name': 'ua-c87b89ff-b769-4abc-921f-30d42d7aec5b'}} @@ -28,13 +34,14 @@ portForwards = {'portForwards': [${portForward_0}]} iface_attrs = {'model': 'virtio', 'acpi': {'index': '1'}, **${ips}, 'backend': ${backend}, 'source': {'dev': '${host_iface}'}, **${alias}, 'type_name': 'user', **${portForwards}} ipv6_prefix = 128 - vm_iface = eno1 + s390-virtio: + iface_attrs = {'model': 'virtio', **${ips}, 'backend': ${backend}, 'source': {'dev': '${host_iface}'}, **${alias}, 'type_name': 'user', **${portForwards}} variants file_size: - 10M: bs = 1M - 1G: bs = 100M - test_file = /tmp/${file_size}_file + test_file = /var/tmp/${file_size}_file rec_file = out_${file_size} cmd_create_file = dd if=/dev/urandom bs=${bs} count=10 > ${test_file} cmd_listen = f'socat -u {prot}-LISTEN:{port},reuseaddr OPEN:${rec_file},create' diff --git a/libvirt/tests/cfg/virtual_network/qos/check_actual_network_throughput.cfg b/libvirt/tests/cfg/virtual_network/qos/check_actual_network_throughput.cfg new file mode 100644 index 00000000000..0ed26f8cf7e --- /dev/null +++ b/libvirt/tests/cfg/virtual_network/qos/check_actual_network_throughput.cfg @@ -0,0 +1,38 @@ +- virtual_network.qos.check_actual_network_throughput: + type = check_actual_network_throughput + start_vm = no + timeout = 240 + host_iface = + inbound = {'average': '512', 'peak': '1024', 'burst': '32'} + outbound = {'average': '128', 'peak': '1024', 'burst': '32'} + iface_bw_attrs = {'bandwidth': {'inbound': ${inbound}, 'outbound': ${outbound}}} + variants iface_type: + - network: + net_bw_attrs = {'bandwidth_inbound': ${inbound}, 'bandwidth_outbound': ${outbound}} + variants net_fwm: + - nat: + variants: + - net_with_qos: + net_attrs = ${net_bw_attrs} + iface_bw_attrs = {} + - iface_with_qos: + iface_attrs = {'source': {'network': 'default'}, 'model': 'virtio', 'type_name': 'network', **${iface_bw_attrs}} + - br: + net_fwm = bridge + iface_attrs = {'type_name': 'network', 'model': 'virtio', 'source': {'network': net_name}} + variants br_type: + - linux_br: + net_attrs = {'name': net_name, 'forward': {'mode': 'bridge'}, 'bridge': {'name': br_name}, **${net_bw_attrs}} + - ovs_br: + net_attrs = {'name': net_name, 'forward': {'mode': 'bridge'}, 'bridge': {'name': br_name}, **${net_bw_attrs}, 'virtualport_type': 'openvswitch'} + - br: + iface_type = bridge + variants br_type: + - linux_br: + iface_attrs = {'type_name': 'bridge', 'source': {'bridge': br_name}, 'model': 'virtio', **${iface_bw_attrs}} + - ovs_br: + iface_attrs = {'type_name': 'bridge', 'source': {'bridge': br_name}, 'model': 'virtio', **${iface_bw_attrs}, 'virtualport': {'type': 'openvswitch'}} + libvirtd_debug_file = /var/log/libvirt/libvird.log + libvirtd_debug_level = 1 + expect_msg = warning.*Setting different .peak. value than .average. for QoS for OVS interface.*might have unexpected results + throuput_bw = 1024 diff --git a/libvirt/tests/cfg/virtual_network/qos/check_actual_network_throughput_direct.cfg b/libvirt/tests/cfg/virtual_network/qos/check_actual_network_throughput_direct.cfg new file mode 100644 index 00000000000..6c75ae87695 --- /dev/null +++ b/libvirt/tests/cfg/virtual_network/qos/check_actual_network_throughput_direct.cfg @@ -0,0 +1,18 @@ +- virtual_network.qos.check_actual_network_throughput.direct: + type = check_actual_network_throughput_direct + start_vm = no + vm2_name = vm2 + vms = avocado-vt-vm1 vm2 + timeout = 240 + host_iface = + inbound = {'average': '64', 'peak': '1024', 'burst': '32'} + outbound = {'average': '64', 'peak': '1024', 'burst': '32'} + iface_bw_attrs = {'bandwidth': {'inbound': ${inbound}, 'outbound': ${outbound}}} + variants: + - with_network: + net_attrs = {'name': net_name, 'forward_interface': [{'dev': host_iface}], 'forward': {'mode': 'bridge'}} + iface_attrs = {'type_name': 'network', 'source': {'network': net_name}, 'model': 'virtio', **${iface_bw_attrs}} + iface_attrs_2 = {'type_name': 'network', 'source': {'network': net_name}, 'model': 'virtio'} + - without_network: + iface_attrs = {'type_name': 'direct', 'source': {'dev': host_iface, 'mode': 'bridge'}, 'model': 'virtio', **${iface_bw_attrs}} + iface_attrs_2 = {'type_name': 'direct', 'source': {'dev': host_iface, 'mode': 'bridge'}, 'model': 'virtio'} diff --git a/libvirt/tests/cfg/virtual_network/qos/check_bandwidth_by_domiftune.cfg b/libvirt/tests/cfg/virtual_network/qos/check_bandwidth_by_domiftune.cfg new file mode 100644 index 00000000000..03718250ee0 --- /dev/null +++ b/libvirt/tests/cfg/virtual_network/qos/check_bandwidth_by_domiftune.cfg @@ -0,0 +1,18 @@ +- virtual_network.qos.check_bandwidth_by_domiftune: + type = check_bandwidth_by_domiftune + start_vm = no + timeout = 240 + host_iface = + net_attrs = {'bandwidth_outbound': {'average': '500', 'peak': '1000', 'burst': '1024'}, 'bandwidth_inbound': {'average': '1000', 'peak': '5000', 'burst': '5120'}} + update_bw = {'inbound': {'average': '100', 'peak': '200', 'burst': '300'}, 'outbound': {'average': '200', 'peak': '300', 'burst': '200'}} + variants iface_type: + - nat: + iface_attrs = {'source': {'network': 'default'}, 'model': 'virtio', 'type_name': 'network'} + bw_with_floor = + update_bw = {'inbound': {'average': '100', 'peak': '200', 'burst': '300', 'floor': '150'}, 'outbound': {'average': '200', 'peak': '300', 'burst': '200'}} + - direct: + iface_attrs = {'source': {'dev': host_iface, 'mode': 'bridge'}, 'model': 'virtio', 'type_name': 'direct'} + - br: + br_type = linux_br + iface_type = bridge + iface_attrs = {'source': {'bridge': br_name}, 'model': 'virtio', 'type_name': 'bridge'} diff --git a/libvirt/tests/cfg/virtual_network/qos/check_qos_floor.cfg b/libvirt/tests/cfg/virtual_network/qos/check_qos_floor.cfg new file mode 100644 index 00000000000..4ef075f6174 --- /dev/null +++ b/libvirt/tests/cfg/virtual_network/qos/check_qos_floor.cfg @@ -0,0 +1,16 @@ +- virtual_network.qos.check_qos_floor: + type = check_qos_floor + start_vm = no + timeout = 240 + net_attrs = {'name': net_name, 'forward': {'mode': 'nat'}, 'ips': [{'dhcp_ranges': {'attrs': {'start': '192.168.100.2', 'end': '192.168.100.254'}}, 'netmask': '255.255.255.0', 'address': '192.168.100.1'}]} + iface_attrs = {'source': {'network': net_name}, 'type_name': 'network', 'model': 'virtio'} + variants net_type: + - with_floor: + bw = {'bandwidth_outbound': {'average': '400', 'peak': '800', 'burst': '512'}, 'bandwidth_inbound': {'average': '500', 'peak': '400', 'burst': '512'}} + net_attrs = {**${net_attrs}, **${bw}} + iface_bw = {'bandwidth': {'inbound': {'average': '300', 'peak': '200', 'floor': '100', 'burst': '256'}, 'outbound': {'average': '200', 'peak': '400', 'burst': '256'}}} + - without_floor: + status_error = yes + err_msg = Invalid use of 'floor' on interface with MAC address .* - network .* has no inbound QoS set + iface_bw = {'bandwidth': {'inbound': {'average': '150', 'peak': '200', 'floor': '100', 'burst': '256'}, 'outbound': {'average': '200', 'peak': '400', 'burst': '256'}}} + iface_attrs = {**${iface_attrs}, **${iface_bw}} diff --git a/libvirt/tests/cfg/virtual_network/qos/test_bandwidth_boundry.cfg b/libvirt/tests/cfg/virtual_network/qos/test_bandwidth_boundry.cfg new file mode 100644 index 00000000000..12ff9905211 --- /dev/null +++ b/libvirt/tests/cfg/virtual_network/qos/test_bandwidth_boundry.cfg @@ -0,0 +1,21 @@ +- virtual_network.qos.test_bandwidth_boundry: + type = test_bandwidth_boundry + start_vm = yes + variants bw_type: + - inbound: + - outbound: + variants scenario: + - boundry: + bw_args = 4294967295,4294967295,4194303 + - over_boundry_average: + bw_args = 1000000000000000000,4096,4096 + status_error = yes + err_msg = ${bw_type} rate larger than maximum 4294967295 + - over_boundry_peak: + bw_args = 4096,1000000000000000000,4096 + status_error = yes + err_msg = ${bw_type} rate larger than maximum 4294967295 + - over_boundry_burst: + bw_args = 1024000,4096,4194304 + status_error = yes + err_msg = numerical overflow: value '4194304' is too big for 'burst' parameter, maximum is '4194303' diff --git a/libvirt/tests/cfg/virtual_network/resolve_vm_hostname_by_resolvectl.cfg b/libvirt/tests/cfg/virtual_network/resolve_vm_hostname_by_resolvectl.cfg new file mode 100644 index 00000000000..b4398266fa8 --- /dev/null +++ b/libvirt/tests/cfg/virtual_network/resolve_vm_hostname_by_resolvectl.cfg @@ -0,0 +1,28 @@ +- virtual_network.resolve_vm_hostname_by_resolvectl: + type = resolve_vm_hostname_by_resolvectl + start_vm = no + vms = avocado-vt-vm1 vm2 + timeout = 240 + func_supported_since_libvirt_ver = (10, 3, 0) + localonly = yes + register_attr = {} + ip_attrs = {'hosts': [{'attrs': {'mac': mac_a, 'name': 'vm1', 'ip': '192.168.122.32'}}]} + ips = {'vm_ip': 'vm1', 'vm_with_domain_ip': 'vm1.example.com', 'vmtest_ip': 'vmtest', 'vmtest_with_domain_ip': 'vmtest.example.com'} + variants register: + - yes: + register_attr = {'register': '${register}'} + host_ping_vm = fail + host_ping_vm_with_domain = pass + host_ping_vmtest = fail + host_ping_vmtest_with_domain = pass + - no: + register_attr = {'register': '${register}'} + host_ping_vm_with_domain = fail + - omitted: + host_ping_vm_with_domain = fail + - localonly_no: + localonly = no + register_attr = {'register': 'yes'} + status_error = yes + err_msg = Failed to define network + net_attrs = {'domain': {'name': 'example.com', 'localOnly': '${localonly}', **${register_attr}}} diff --git a/libvirt/tests/cfg/virtual_network/update_device/unsupported_live_update_add.cfg b/libvirt/tests/cfg/virtual_network/update_device/unsupported_live_update_add.cfg new file mode 100644 index 00000000000..c9a8a4426ef --- /dev/null +++ b/libvirt/tests/cfg/virtual_network/update_device/unsupported_live_update_add.cfg @@ -0,0 +1,31 @@ +- virtual_network.update_device.unsupported_live_update.add: + type = unsupported_live_update + start_vm = no + timeout = 240 + base_iface_attrs = {'mac_address': mac, 'type_name': 'network', 'source': {'network': 'default'}, 'model': 'virtio'} + status_error = yes + variants: + - acpi_index: + no s390-virtio + update_attrs = {'acpi': {'index': '6'}} + err_msg = changing device 'acpi index' is not allowed + - sndbuf: + update_attrs = {'tune': {'sndbuf': 2000}} + err_msg = unable to change config on 'network' network type + - mtu: + update_attrs = {'mtu': {'size': '9000'}} + err_msg = cannot modify MTU + - boot_order: + set_boot = yes + update_attrs = {'boot': '3'} + err_msg = cannot modify network device boot index setting + - rom: + no s390-virtio + update_attrs = {'rom': {'enabled': 'yes'}} + err_msg = cannot modify network device rom enabled setting + - backend: + update_attrs = {'backend': {'tap': '/dev/net/tun'}} + err_msg = cannot modify network device backend settings + - driver: + update_attrs = {'driver': {'driver_attr': {'name': 'vhost', 'queues': '8', 'rx_queue_size': '1024'}}} + err_msg = cannot modify virtio network device driver attributes diff --git a/libvirt/tests/cfg/virtual_network/update_device/unsupported_live_update_alter.cfg b/libvirt/tests/cfg/virtual_network/update_device/unsupported_live_update_alter.cfg new file mode 100644 index 00000000000..b46a0c3b44d --- /dev/null +++ b/libvirt/tests/cfg/virtual_network/update_device/unsupported_live_update_alter.cfg @@ -0,0 +1,52 @@ +- virtual_network.update_device.unsupported_live_update.alter: + type = unsupported_live_update + start_vm = no + timeout = 240 + status_error = yes + variants: + - acpi_index: + no s390-virtio + extra_attrs = {'acpi': {'index': '4'}} + update_attrs = {'acpi': {'index': '6'}} + err_msg = changing device 'acpi index' is not allowed + - sndbuf: + extra_attrs = {'tune': {'sndbuf': 1600}} + update_attrs = {'tune': {'sndbuf': 2000}} + err_msg = unable to change config on 'network' network type + - mtu: + extra_attrs = {'mtu': {'size': '6000'}} + update_attrs = {'mtu': {'size': '9000'}} + err_msg = cannot modify MTU + - boot_order: + set_boot = yes + extra_attrs = {'boot': '2'} + update_attrs = {'boot': '3'} + err_msg = cannot modify network device boot index setting + - rom: + no s390-virtio + extra_attrs = {'rom': {'enabled': 'no'}} + update_attrs = {'rom': {'enabled': 'yes'}} + err_msg = cannot modify network device rom enabled setting + - target_dev: + extra_attrs = {'target': {'dev': 'test'}} + update_attrs = {'target': {'dev': 'newtap'}} + err_msg = cannot modify network device tap name + - model_type: + update_attrs = {'model': 'e1000e'} + err_msg = cannot modify network device model from .* to .* + - backend: + extra_attrs = {'backend': {'tap': '/dev/net/tun', 'vhost': '/dev/vhost-net'}} + tmp_attrs = {'backend': None} + update_attrs = {'backend': {'tap': '/dev/net/tun'}} + err_msg = cannot modify network device backend settings + - driver: + update_attrs = {'driver': {'driver_attr': {'name': 'vhost', 'queues': '8', 'rx_queue_size': '1024'}}} + err_msg = cannot modify virtio network device driver attributes + - alias_name: + extra_attrs = {'alias': {'name': 'ua-47034d36-5483-411c-86f8-7989d08d762b'}} + update_attrs = {'alias': {'name': 'ua-testnet888'}} + err_msg = device not found: no device found at address .* matching MAC address .* and alias .* + - mac: + update_attrs = {'mac_address': '52:54:00:44:e1:55'} + err_msg = device not found: no device found at address .* matching MAC address .* and alias .* + base_iface_attrs = {'mac_address': mac, 'type_name': 'network', 'source': {'network': 'default'}, 'model': 'virtio'} diff --git a/libvirt/tests/cfg/virtual_network/update_device/unsupported_live_update_delete.cfg b/libvirt/tests/cfg/virtual_network/update_device/unsupported_live_update_delete.cfg new file mode 100644 index 00000000000..d4dd90285dd --- /dev/null +++ b/libvirt/tests/cfg/virtual_network/update_device/unsupported_live_update_delete.cfg @@ -0,0 +1,44 @@ +- virtual_network.update_device.unsupported_live_update.delete: + type = unsupported_live_update + start_vm = no + timeout = 240 + status_error = yes + variants: + - acpi_index: + no s390-virtio + extra_attrs = {'acpi': {'index': '4'}} + del_attr = acpi + err_msg = changing device 'acpi index' is not allowed + - sndbuf: + extra_attrs = {'tune': {'sndbuf': 1600}} + del_attr = tune + err_msg = unable to change config on 'network' network type + - mtu: + extra_attrs = {'mtu': {'size': '6000'}} + del_attr = mtu + err_msg = cannot modify MTU + - boot_order: + set_boot = yes + extra_attrs = {'boot': '2'} + del_attr = boot + err_msg = cannot modify network device boot index setting + - rom: + no s390-virtio + extra_attrs = {'rom': {'enabled': 'no'}} + del_attr = rom + err_msg = cannot modify network device rom enabled setting + - model_type: + no s390-virtio + del_attr = model + err_msg = cannot modify network device model from .* to .* + - backend: + extra_attrs = {'backend': {'tap': '/dev/net/tun', 'vhost': '/dev/vhost-net'}} + del_attr = backend + err_msg = cannot modify network device backend settings + - driver: + del_attr = driver + err_msg = cannot modify virtio network device driver attributes + - mac: + del_attr = mac_address + err_msg = "cannot change network interface mac address|device not found" + base_iface_attrs = {'mac_address': mac, 'type_name': 'network', 'source': {'network': 'default'}, 'model': 'virtio'} diff --git a/libvirt/tests/cfg/virtual_network/update_device/update_device_coalesce.cfg b/libvirt/tests/cfg/virtual_network/update_device/update_device_coalesce.cfg new file mode 100644 index 00000000000..15c053c1371 --- /dev/null +++ b/libvirt/tests/cfg/virtual_network/update_device/update_device_coalesce.cfg @@ -0,0 +1,35 @@ +- virtual_network.update_device.coalesce: + type = update_device_coalesce + host_iface = + start_vm = no + timeout = 240 + outside_ip = 'www.redhat.com' + extra_attrs = {} + vm_ping_outside = pass + variants: + - delete_iface_coalesce: + rx_frames = 32 + coalesce = {'coalesce': {'max': '${rx_frames}'}} + - add_iface_coalesce: + coalesce = {} + updated_rx_frames = 64 + updated_coalesce = {'coalesce': {'max': '${updated_rx_frames}'}} + - update_iface_coalesce: + rx_frames = 64 + coalesce = {'coalesce': {'max': '${rx_frames}'}} + updated_rx_frames = 32 + updated_coalesce = {'coalesce': {'max': '${updated_rx_frames}'}} + variants: + - nat_net: + iface_type = network + iface_source = {'source': {'network': 'default'}} + - linux_br: + iface_type = bridge + br_type = linux_br + iface_source = {'source': {'bridge': br_name}} + - ovs_br: + iface_type = bridge + br_type = ovs_br + iface_source = {'source': {'bridge': br_name}} + extra_attrs = {'virtualport': {'type': 'openvswitch'}} + iface_attrs = {'type_name': '${iface_type}', **${coalesce}, **${iface_source}, 'model': 'virtio', 'mac_address': mac, **${extra_attrs}} diff --git a/libvirt/tests/cfg/virtual_network/update_device/update_driver_non_virtio.cfg b/libvirt/tests/cfg/virtual_network/update_device/update_driver_non_virtio.cfg new file mode 100644 index 00000000000..4f9b10bdbcd --- /dev/null +++ b/libvirt/tests/cfg/virtual_network/update_device/update_driver_non_virtio.cfg @@ -0,0 +1,20 @@ +- virtual_network.update_device.driver_non_virtio: + type = update_driver_non_virtio + start_vm = no + timeout = 240 + outside_ip = "www.redhat.com" + vm_ping_outside = pass + func_supported_since_libvirt_ver = (10, 6, 0) + variants test_scenario: + - define_with_invaid_driver: + exist_attrs = {'driver': {'driver_host': {'csum':'off'}}} + update_setting = {"link_state": "down"} + - update_with_invalid_driver: + update_setting = {"link_state": "down", 'driver': {'driver_host': {'csum':'off'}}} + variants model_type: + - e1000e: + only x86_64 + - rtl8139: + only x86_64 + iface_attrs = {"model": "${model_type}", "type_name": "network", "source": {"network": "default"}} + diff --git a/libvirt/tests/cfg/virtual_network/update_device/update_iface_link_state.cfg b/libvirt/tests/cfg/virtual_network/update_device/update_iface_link_state.cfg new file mode 100644 index 00000000000..a5a0f9d5134 --- /dev/null +++ b/libvirt/tests/cfg/virtual_network/update_device/update_iface_link_state.cfg @@ -0,0 +1,38 @@ +- virtual_network.update_device.iface_link_state: + type = update_iface_link_state + start_vm = no + timeout = 240 + outside_ip = "www.redhat.com" + vm_ping_outside = pass + variants test_scenario: + - add: + updated_link_state = "down" + - delete: + initial_link_state = "down" + updated_link_state = + - update: + initial_link_state = "down" + updated_link_state = "up" + variants model_type: + - virtio: + - e1000e: + only x86_64 + - igb: + only x86_64 + func_supported_since_libvirt_ver = (9, 3, 0) + - rtl8139: + only x86_64 + variants interface_type: + - network: + iface_base_attrs = {"type_name": "network", "source": {"network": "default"}} + - direct: + only virtio + host_iface = + iface_base_attrs = {"type_name": "direct", "source": {"dev": host_iface, "mode": "bridge"}} + - ethernet: + only virtio + host_iface = + create_tap = "yes" + iface_base_attrs = {"type_name": "ethernet", "target": {"dev": tap_name, "managed": "no"}} + + iface_attrs = {"model": "${model_type}", **${iface_base_attrs}} diff --git a/libvirt/tests/cfg/virtual_network/update_device/update_iface_portgroup.cfg b/libvirt/tests/cfg/virtual_network/update_device/update_iface_portgroup.cfg new file mode 100644 index 00000000000..d4748a4aa6c --- /dev/null +++ b/libvirt/tests/cfg/virtual_network/update_device/update_iface_portgroup.cfg @@ -0,0 +1,17 @@ +- virtual_network.update_device.iface_portgroup.qos: + type = update_iface_portgroup + start_vm = no + timeout = 240 + host_iface = + pg_a = {'default': 'yes', 'name': 'sales', 'bandwidth_inbound': {'average': '100', 'peak': '200', 'burst': '512'}, 'bandwidth_outbound': {'average': '50', 'peak': '100', 'burst': '256'}} + pg_b = {'name': 'engineering', 'bandwidth_inbound': {'average': '200', 'peak': '300', 'burst': '256'}, 'bandwidth_outbound': {'average': '100', 'peak': '200', 'burst': '128'}} + pg_attrs = {'portgroups': [${pg_a}, ${pg_b}]} + update_attrs = {'portgroup': 'engineering'} + variants net_type: + - nat: + net_attrs = ${pg_attrs} + - linux_br: + net_attrs = {'name': net_name, 'forward': {'mode': 'bridge'}, 'bridge': {'name': br_name}, **${pg_attrs}} + - ovs_br: + net_attrs = {'name': net_name, 'forward': {'mode': 'bridge'}, 'virtualport_type': 'openvswitch', 'bridge': {'name': br_name}, **${pg_attrs}} + iface_attrs = {'model': 'virtio', 'type_name': 'network', 'source': {'network': net_name}} diff --git a/libvirt/tests/cfg/virtual_network/update_device/update_iface_qos.cfg b/libvirt/tests/cfg/virtual_network/update_device/update_iface_qos.cfg new file mode 100644 index 00000000000..4d846fc23b4 --- /dev/null +++ b/libvirt/tests/cfg/virtual_network/update_device/update_iface_qos.cfg @@ -0,0 +1,38 @@ +- virtual_network.update_device.iface_qos: + type = update_iface_qos + start_vm = no + timeout = 240 + host_iface = + extra_attrs = {} + variants: + - inbound_outbound: + scope = ['inbound', 'outbound'] + - inbound_only: + scope = ['outbound'] + - outbound_only: + scope = ['outbound'] + variants operation: + - add: + update_attrs = {'bandwidth': {'outbound': {'average': '200', 'peak': '400', 'burst': '600'},'inbound': {'average': '100', 'peak': '300', 'burst': '500'}}} + - update: + extra_attrs = {'bandwidth': {'outbound': {'average': '200', 'peak': '400', 'burst': '600'},'inbound': {'average': '100', 'peak': '300', 'burst': '500'}}} + update_attrs = {'bandwidth': {'outbound': {'average': '300', 'peak': '400', 'burst': '500'},'inbound': {'average': '500', 'peak': '700', 'burst': '900'}}} + - delete: + extra_attrs = {'bandwidth': {'outbound': {'average': '200', 'peak': '400', 'burst': '600'},'inbound': {'average': '100', 'peak': '300', 'burst': '500'}}} + update_attrs = {'bandwidth': {'outbound': {'average': '0', 'peak': '0', 'burst': '0'},'inbound': {'average': '0', 'peak': '0', 'burst': '0'}}} + variants method: + - update-device: + delete: + only inbound_outbound + - domiftune: + variants iface_setting: + - net_iface_default_net: + iface_attrs = {'source': {'network': 'default'}, 'type_name': 'network'} + - br_iface_linux_br: + br_type = linux_br + iface_attrs = {'type_name': 'bridge', 'source': {'bridge': br_name}} + - br_iface_ovs_br: + br_type = ovs_br + iface_attrs = {'type_name': 'bridge', 'source': {'bridge': br_name}, 'virtualport': {'type': 'openvswitch'}} + - direct_bridge_iface: + iface_attrs = {'type_name': 'direct', 'source': {'dev': host_iface, 'mode': 'bridge'}} diff --git a/libvirt/tests/cfg/virtual_network/update_device/update_iface_qos_invalid.cfg b/libvirt/tests/cfg/virtual_network/update_device/update_iface_qos_invalid.cfg new file mode 100644 index 00000000000..e7745b141b9 --- /dev/null +++ b/libvirt/tests/cfg/virtual_network/update_device/update_iface_qos_invalid.cfg @@ -0,0 +1,32 @@ +- virtual_network.update_device.iface_qos.invalid: + type = update_iface_qos_invalid + start_vm = no + timeout = 240 + status_error = yes + iface_attrs = {'source': {'network': 'default'}, 'type_name': 'network', 'model': 'virtio'} + variants: + - neg_value: + update_attrs = {'bandwidth': {'inbound': {'average': '-1', 'peak': '5000', 'burst': '1024'}}} + err_msg = could not convert bandwidth average value|Expected non-negative integer value + - big_value: + func_supported_since_libvirt_ver = (10,8,0) + variants: + - average: + update_attrs = {'bandwidth': {'inbound': {'average': '100000000000000000', 'peak': '5000', 'burst': '1024'}}} + err_msg = numerical overflow: value .* is too big for 'average' parameter, maximum is + - peak: + update_attrs = {'bandwidth': {'inbound': {'average': '5000', 'peak': '100000000000000000', 'burst': '1024'}}} + err_msg = numerical overflow: value .* is too big for 'peak' parameter, maximum is + - burst: + update_attrs = {'bandwidth': {'inbound': {'average': '1024000', 'peak': '4096', 'burst': '4194304'}}} + err_msg = numerical overflow: value .* is too big for 'burst' parameter, maximum is + - max_value: + func_supported_since_libvirt_ver = (10,8,0) + update_attrs = {'bandwidth': {'inbound': {'average': '18014398509481984', 'peak': '5000', 'burst': '4194303'}}} + status_error = no + - no_mandatory_average: + update_attrs = {'bandwidth': {'outbound': {'peak': '5000', 'burst': '1024'}}} + err_msg = Missing mandatory average or floor attributes + - floor_without_bandwidth: + update_attrs = {'bandwidth': {'outbound': {'average': '128', 'peak': '256', 'burst': '256'},'inbound': {'average': '1000', 'peak': '5000', 'floor': '200', 'burst': '1024'}}} + err_msg = Invalid use of 'floor' on interface with MAC address .* - network .* has no inbound QoS set diff --git a/libvirt/tests/cfg/virtual_network/update_device/update_iface_source.cfg b/libvirt/tests/cfg/virtual_network/update_device/update_iface_source.cfg new file mode 100644 index 00000000000..8f179d20612 --- /dev/null +++ b/libvirt/tests/cfg/virtual_network/update_device/update_iface_source.cfg @@ -0,0 +1,28 @@ +- virtual_network.update_device.iface_source: + type = update_iface_source + host_iface = + start_vm = no + outside_ip = 'www.redhat.com' + vm_ping_outside = pass + timeout = 240 + nat_net_attrs = {'name': net_name, 'forward': {'mode': 'nat'}, 'ips': [{'dhcp_ranges': {'attrs': {'start': '192.168.120.2', 'end': '192.168.120.254'}}, 'address': '192.168.120.1', 'netmask': '255.255.255.0'}]} + variants scenario: + - default_net_to_nat: + iface_attrs = {'source': {'network': 'default'}, 'type_name': 'network'} + net_attrs = ${nat_net_attrs} + update_attrs = {'source': {'network': net_name}} + - br_to_br: + iface_attrs = {'source': {'bridge': 'virbr0'}, 'type_name': 'bridge'} + net_attrs = ${nat_net_attrs} + update_attrs = {'source': {'bridge': net_br}} + - direct_vepa_to_br: + status_error = yes + err_msg = Operation not supported: unable to change config on 'direct' network type + iface_attrs = {'type_name': 'direct', 'source': {'dev': host_iface, 'mode': 'vepa'}} + update_attrs = {'source': {'dev': host_iface, 'mode': 'bridge'}} + - default_net_to_direct_net: + status_error = yes + err_msg = Operation not supported: unable to change config on 'network' network type + iface_attrs = {'source': {'network': 'default'}, 'type_name': 'network'} + net_attrs = {'name': net_name, 'forward': {'mode': 'bridge'}, 'forward_interface': [{'dev': host_iface}]} + update_attrs = {'source': {'network': net_name}} diff --git a/libvirt/tests/cfg/virtual_network/update_device/update_iface_trustGuestRxFilters.cfg b/libvirt/tests/cfg/virtual_network/update_device/update_iface_trustGuestRxFilters.cfg new file mode 100644 index 00000000000..9716f98a9b1 --- /dev/null +++ b/libvirt/tests/cfg/virtual_network/update_device/update_iface_trustGuestRxFilters.cfg @@ -0,0 +1,19 @@ +- virtual_network.update_device.update_iface_trustGuestRxFilters: + type = update_iface_trustGuestRxFilters + start_vm = no + timeout = 240 + host_iface = + outside_ip = 'www.redhat.com' + func_supported_since_libvirt_ver = (10, 0, 0) + variants: + - yes_to_no: + trustGRF = 'yes' + update_attrs = {'trustGuestRxFilters': 'no'} + vm_ping_outside = fail + err_msg = f'Mac address of {target_dev} on host should not change' + - no_to_yes: + trustGRF = 'no' + update_attrs = {'trustGuestRxFilters': 'yes'} + vm_ping_outside = pass + err_msg = f'Mac address of {target_dev} on host should be the same as vm' + iface_attrs = {'type_name': 'direct', 'trustGuestRxFilters': '${trustGRF}', 'model': 'virtio', 'source': {'dev': host_iface, 'mode': 'bridge'}} diff --git a/libvirt/tests/cfg/virtual_network/update_device/update_iface_type_live.cfg b/libvirt/tests/cfg/virtual_network/update_device/update_iface_type_live.cfg index df0e02f7a1b..339f0ad7eb9 100644 --- a/libvirt/tests/cfg/virtual_network/update_device/update_iface_type_live.cfg +++ b/libvirt/tests/cfg/virtual_network/update_device/update_iface_type_live.cfg @@ -3,12 +3,35 @@ host_iface = start_vm = no timeout = 240 + extra_attrs = {} + check_link = yes variants: - bridge_type: iface_type = bridge create_linux_br = yes net_attrs = {'name': net_name, 'bridge': {'name': linux_br}, 'forward': {'mode': 'bridge'}} + - ovsbr_type: + iface_type = bridge + create_ovs_br = yes + net_attrs = {'name': net_name, 'bridge': {'name': linux_br}, 'forward': {'mode': 'bridge'}} + extra_attrs = {'virtualport': {'type': 'openvswitch'}} + variants: + - default: + - no_change: + check_link = no + with_iface_xml = yes + variants operation: + - default: + - attach_device: + - attach_interface: + net_attrs = {'name': net_name, 'bridge': {'name': linux_br}, 'forward': {'mode': 'bridge'}, 'virtualport_type': 'openvswitch'} + variants xml_opt: + - active: + xml_opt = + - inactive: + xml_opt = --inactive + - direct_type: iface_type = direct net_attrs = {'name': net_name, 'forward': {'mode': 'bridge'}, 'forward_interface': [{'dev': host_iface}]} - iface_attrs = {'model': 'virtio', 'type_name': 'network', 'source': {'network': net_name}, 'mac_address': mac} + iface_attrs = {'model': 'virtio', 'type_name': 'network', 'source': {'network': net_name}, 'mac_address': mac, **${extra_attrs}} diff --git a/libvirt/tests/cfg/virtual_network/update_device/update_iface_with_identifier.cfg b/libvirt/tests/cfg/virtual_network/update_device/update_iface_with_identifier.cfg new file mode 100644 index 00000000000..00450effbdd --- /dev/null +++ b/libvirt/tests/cfg/virtual_network/update_device/update_iface_with_identifier.cfg @@ -0,0 +1,41 @@ +- virtual_network.update_device.iface_with_identifier: + type = update_iface_with_identifier + start_vm = no + timeout = 240 + iface_a_attrs = {'source': {'network': 'default'}, 'model': 'virtio', 'type_name': 'network', 'alias': {'name': alias_a}} + iface_b_attrs = {'source': {'network': 'default'}, 'model': 'virtio', 'type_name': 'network', 'alias': {'name': alias_b}} + update_attrs = {'link_state': 'down'} + err_msg_matching = device not found: no device found at address .* matching MAC address .* and alias .* + variants scenario: + - mac_only: + del_tags = ['alias', 'address'] + status_error = no + - alias_only: + del_tags = ['address', 'mac'] + status_error = no + update: + status_error = yes + err_msg = cannot change network interface mac address from .* to .* + - pci_address_only: + del_tags = ['alias', 'mac'] + status_error = no + update: + status_error = yes + err_msg = cannot change network interface mac address from .* to .* + - right_mac_alias_wrong_pci: + no s390-virtio + status_error = yes + err_msg = ${err_msg_matching} + update_attrs = {'link_state': 'down'} + update_pci = yes + - right_mac_pci_wrong_alias: + status_error = yes + err_msg = ${err_msg_matching} + update_attrs = {'link_state': 'down', 'alias': {'name': rand_alias}} + - wrong_mac_right_alias_pci: + status_error = yes + err_msg = ${err_msg_matching} + update_attrs = {'link_state': 'down', 'mac_address': rand_mac} + variants operation: + - update: + - hotunplug: diff --git a/libvirt/tests/cfg/virtual_network/update_device/update_iface_with_options_active.cfg b/libvirt/tests/cfg/virtual_network/update_device/update_iface_with_options_active.cfg new file mode 100644 index 00000000000..bde26fdeafc --- /dev/null +++ b/libvirt/tests/cfg/virtual_network/update_device/update_iface_with_options_active.cfg @@ -0,0 +1,32 @@ +- virtual_network.update_device.with_options.active_vm: + type = update_iface_with_options + start_vm = no + timeout = 240 + vm_active = True + iface_attrs = {'link_state': 'up', 'source': {'network': 'default'}} + update_attrs = {'link_state': 'down', 'source': {'network': 'default'}} + variants options: + - live: + update_expect = {'active': True, 'inactive': False} + - live_persistent: + update_expect = {'active': True, 'inactive': True} + - live_config: + update_expect = {'active': True, 'inactive': True} + - live_current: + status_error = yes + err_msg = Options .* and .* are mutually exclusive + update_expect = {'active': False, 'inactive': False} + - current: + update_expect = {'active': True, 'inactive': False} + - persistent: + update_expect = {'active': True, 'inactive': True} + - persistent_current: + status_error = yes + err_msg = Options .* and .* are mutually exclusive + update_expect = {'active': False, 'inactive': False} + - config: + update_expect = {'active': False, 'inactive': True} + - config_persistent: + update_expect = {'active': True, 'inactive': True} + - none: + update_expect = {'active': True, 'inactive': False} diff --git a/libvirt/tests/cfg/virtual_network/update_device/update_iface_with_options_inactive.cfg b/libvirt/tests/cfg/virtual_network/update_device/update_iface_with_options_inactive.cfg new file mode 100644 index 00000000000..93422f8e06b --- /dev/null +++ b/libvirt/tests/cfg/virtual_network/update_device/update_iface_with_options_inactive.cfg @@ -0,0 +1,38 @@ +- virtual_network.update_device.with_options.inactive_vm: + type = update_iface_with_options + start_vm = no + timeout = 240 + vm_active = False + iface_attrs = {'link_state': 'up'} + update_attrs = {'link_state': 'down'} + variants options: + - live: + status_error = yes + err_msg = Requested operation is not valid: domain is not running + update_expect = {'inactive': False} + - live_persistent: + status_error = yes + err_msg = Requested operation is not valid: domain is not running + update_expect = {'inactive': False} + - live_config: + status_error = yes + err_msg = Requested operation is not valid: domain is not running + update_expect = {'inactive': False} + - live_current: + status_error = yes + err_msg = Options --current and --live are mutually exclusive + update_expect = {'inactive': False} + - current: + update_expect = {'inactive': True} + - persistent: + update_expect = {'inactive': True} + - persistent_current: + status_error = yes + err_msg = Options --persistent and --current are mutually exclusive + update_expect = {'inactive': False} + - config: + update_expect = {'inactive': True} + - config_persistent: + update_expect = {'inactive': True} + - none: + update_expect = {'inactive': True} diff --git a/libvirt/tests/cfg/virtual_network/update_device/update_iface_with_unchangable.cfg b/libvirt/tests/cfg/virtual_network/update_device/update_iface_with_unchangable.cfg new file mode 100644 index 00000000000..95e8d02da6e --- /dev/null +++ b/libvirt/tests/cfg/virtual_network/update_device/update_iface_with_unchangable.cfg @@ -0,0 +1,21 @@ +- virtual_network.update_device.with_unchangable: + type = update_iface_with_unchangable + start_vm = no + host_iface = + iface_attrs_boot = 2 + iface_attrs_model = virtio + iface_attrs_rom = {'bar': 'on', 'file': '/usr/share/ipxe/1af41000.rom'} + driver_host = {'driver_host': {'csum': 'off', 'gso': 'off', 'tso4': 'off', 'tso6': 'off', 'ecn': 'off', 'ufo': 'off', 'mrg_rxbuf': 'off'}} + driver_guest = {'driver_guest': {'csum': 'off', 'tso4': 'off', 'tso6': 'off', 'ecn': 'off', 'ufo': 'off'}} + driver_attr = {'driver_attr': {'name': 'vhost', 'txmode': 'iothread', 'ioeventfd': 'on', 'event_idx': 'off', 'queues': '5', 'rx_queue_size': '256', 'tx_queue_size': '256'}} + iface_attrs_driver = {**${driver_host}, **${driver_guest}, **${driver_attr}} + iface_attrs_link_state = up + iface_attrs_target = {'dev': 'tar'} + iface_attrs_mtu = {'size': '1500'} + iface_attrs_type_name = network + iface_attrs_source = {'network': 'default', 'bridge': 'virbr0'} + iface_attrs_tune = {'sndbuf': 1600} + iface_attrs_alias = {'name': 'ua-823c76fa-ee1d-4278-a613-2ba8ba179b61'} + update_attrs = {'link_state': 'down'} + s390-virtio: + iface_attrs_rom = {} diff --git a/libvirt/tests/cfg/virtual_network/update_device/update_port_isolated.cfg b/libvirt/tests/cfg/virtual_network/update_device/update_port_isolated.cfg new file mode 100644 index 00000000000..6419871abd2 --- /dev/null +++ b/libvirt/tests/cfg/virtual_network/update_device/update_port_isolated.cfg @@ -0,0 +1,36 @@ +- virtual_network.update_device.port_isolated: + type = update_port_isolated + vms = avocado-vt-vm1 vm2 + start_vm = no + timeout = 240 + outside_ip = 'www.redhat.com' + host_iface = + vm_ping_outside = pass + vm_ping_host_public = pass + func_supported_since_libvirt_ver = (6, 2, 0) + variants net: + - nat_network: + iface_source = "'default'" + - linux_br: + create_linux_br = yes + net_attrs = {'bridge': {'name': linux_br}, 'forward': {'mode': 'bridge'}, 'name': net_br} + iface_source = net_br + set_iface = yes + variants: + - default_to_yes: + port_attrs = {} + update_port_attrs = {'port': {'isolated': 'yes'}} + vm_ping_ep_vm = pass + ping_after_update = fail + - yes_to_no: + port_attrs = {'port': {'isolated': 'yes'}} + update_port_attrs = {'port': {'isolated': 'no'}} + vm_ping_ep_vm = fail + ping_after_update = pass + - yes_to_default: + port_attrs = {'port': {'isolated': 'yes'}} + update_port_attrs = {} + vm_ping_ep_vm = fail + ping_after_update = pass + iface_attrs = {'type_name': 'network', 'source': {'network': iface_source}, 'model': 'virtio', **${port_attrs}} + cli_iface_attrs = {'type_name': 'network', 'source': {'network': iface_source}, 'model': 'virtio', 'port': {'isolated': 'yes'}} diff --git a/libvirt/tests/cfg/vm_create_destroy_concurrently.cfg b/libvirt/tests/cfg/vm_create_destroy_concurrently.cfg new file mode 100644 index 00000000000..5f78d9bdfd3 --- /dev/null +++ b/libvirt/tests/cfg/vm_create_destroy_concurrently.cfg @@ -0,0 +1,5 @@ +- vm_create_destroy_concurrently: + type = vm_create_destroy_concurrently + start_vm = no + num_threads = 3 + run_time = 1800 diff --git a/libvirt/tests/cfg/vm_start_destroy_repeatedly.cfg b/libvirt/tests/cfg/vm_start_destroy_repeatedly.cfg new file mode 100644 index 00000000000..1cd0e48689e --- /dev/null +++ b/libvirt/tests/cfg/vm_start_destroy_repeatedly.cfg @@ -0,0 +1,13 @@ +- vm_start_destroy_repeatedly: + type = vm_start_destroy_repeatedly + num_cycles = 3000 + start_vm = no + test_timeout = 288000 + check_hugepage_status = False + variants: + - hugepage: + num_cycles = 100 + check_hugepage_status = True + mb_params = {'hugepages': {}, 'source_type': 'memfd', 'access_mode': 'shared'} + vm_attrs = {'memory': 8388608, 'memory_unit': 'KiB'} + - @default: diff --git a/libvirt/tests/deps/cve_2023_3750.sh b/libvirt/tests/deps/cve_2023_3750.sh index 63ef3b29caa..2f46c84c87c 100644 --- a/libvirt/tests/deps/cve_2023_3750.sh +++ b/libvirt/tests/deps/cve_2023_3750.sh @@ -7,7 +7,7 @@ POOL=$1 VOL=$2 function test_run() { while true;do - parallel -N0 "virsh -r 'pool-list; vol-info --pool $1 $2'" ::: {1..100} + seq 1 100 | xargs -n 1 -P 10 -I {} sh -c 'virsh -r "pool-list; vol-info --pool $1 --vol $2"' -- $1 $2 done } diff --git a/libvirt/tests/deps/negative_domcapabilities_s390x.xml b/libvirt/tests/deps/negative_domcapabilities_s390x.xml index f0839d5b7e0..34cc5bae07e 100644 --- a/libvirt/tests/deps/negative_domcapabilities_s390x.xml +++ b/libvirt/tests/deps/negative_domcapabilities_s390x.xml @@ -35,6 +35,7 @@ gen15a-base + diff --git a/libvirt/tests/deps/qemu_wrapper.py b/libvirt/tests/deps/qemu_wrapper.py new file mode 100755 index 00000000000..08943968ff4 --- /dev/null +++ b/libvirt/tests/deps/qemu_wrapper.py @@ -0,0 +1,12 @@ +#!/usr/bin/env python + +import os +import sys +import time + +TIMEOUT = 5 +QEMU_PATH = "/usr/libexec/qemu-kvm" + +time.sleep(TIMEOUT) +sys.argv[0] = QEMU_PATH +os.execv(QEMU_PATH, sys.argv) diff --git a/libvirt/tests/src/backingchain/blockcommit/check_allocation_watermark_during_blockcommit.py b/libvirt/tests/src/backingchain/blockcommit/check_allocation_watermark_during_blockcommit.py index 1bed6dfcd76..c01d2008f81 100644 --- a/libvirt/tests/src/backingchain/blockcommit/check_allocation_watermark_during_blockcommit.py +++ b/libvirt/tests/src/backingchain/blockcommit/check_allocation_watermark_during_blockcommit.py @@ -1,8 +1,7 @@ -import time +import re from avocado.utils import lv_utils -from virttest import data_dir from virttest import utils_disk from virttest import utils_misc from virttest import virsh @@ -14,6 +13,8 @@ from provider.backingchain import blockcommand_base from provider.virtual_disk import disk_base +virsh_debug = {'debug': True, 'ignore_status': False} + def run(test, params, env): """ @@ -29,7 +30,7 @@ def run(test, params, env): def setup_test(): """ - Set disk + Set disk. """ test_obj.new_image_path = disk_obj.add_vm_disk( disk_type, disk_dict) @@ -49,7 +50,6 @@ def run_test(): snap_num=1, extra=extra_option, snap_path=path_list[index], clean_snap_file=False) - alloc_new_dict_1 = get_alloc_result() write_file(format_disk, "/mnt/file_%s" % index) format_disk = False @@ -63,42 +63,34 @@ def run_test(): test_obj.new_dev) test.log.debug("After creating snaps, The xml is:\n%s", vmxml) - # Manual case requires to sleep 5 seconds and check the domstats again - time.sleep(5) - test.log.info("TEST_STEP2: Check %s keep changing " - "during blockcommit.", disappear_alloc) - cmd = "blockcommit %s %s %s " % (vm_name, target_disk, - commit_option) + test.log.info("TEST_STEP2: Check %s keep changing during blockcommit.", changing_alloc) + alloc_value = get_alloc_result().get(changing_index) + cmd = "blockcommit %s %s %s " % (vm_name, target_disk, commit_option) virsh_session = virsh.VirshSession(virsh_exec=virsh.VIRSH_EXEC, auto_close=True) virsh_session.sendline(cmd) test.log.debug("blockcommit cmd: %s", cmd) - alloc_dict = {} - for i in range(0, 2): - alloc_new_dict = get_alloc_result() - test.log.debug('Current alloc dict is:%s, last alloc dict is :%s', - alloc_new_dict, alloc_dict) - if alloc_new_dict.get(disappear_index) == \ - alloc_dict.get(disappear_index, ""): - test.fail("%s should keep changing during blockcommit %s." % ( - disappear_alloc, virsh_session.get_stripped_output())) - alloc_dict = alloc_new_dict - time.sleep(1) + def _alloc_changed(): + new_alloc = get_alloc_result() + test.log.debug("Commit result:%s", virsh_session.get_stripped_output()) + test.log.debug("Currently, %s changes from %s to %s" % ( + changing_alloc, alloc_value, new_alloc[changing_index])) + return new_alloc[changing_index] != alloc_value + + if not utils_misc.wait_for(_alloc_changed, timeout=120, step=0.1): + test.fail("%s is not changing during blockcommit in 120s." % changing_alloc) + test.log.debug("Checked the %s changing successfully" % changing_alloc) test.log.info("TEST_STEP3: Check %s should disappear" % disappear_alloc) - if utils_misc.wait_for(lambda: commit_success_msg in - virsh_session.get_stripped_output(), 40, step=0.01): - alloc_new_dict = get_alloc_result() - if disappear_alloc in alloc_new_dict: - test.fail("The % should not be in %s" % (disappear_alloc, - alloc_new_dict)) - else: - test.log.debug("Current commit result:%s ", - virsh_session.get_stripped_output()) - test.fail("Blockcommit still not finish in 40s, " - "Please control commit speed to test :%s", - (virsh_session.get_stripped_output())) + if not utils_misc.wait_for( + lambda: commit_success_msg in virsh_session.get_stripped_output(), + 30, step=0.01): + virsh.blockjob(vm_name, target_disk, options=" --abort", **virsh_debug) + alloc_new_dict = get_alloc_result() + if disappear_alloc in alloc_new_dict: + test.fail("The % should not be in %s" % (disappear_alloc, + alloc_new_dict)) def teardown_test(): """ @@ -125,8 +117,8 @@ def prepare_snap_path(): disk_format="qcow2") path.append(source_path) elif disk_type == "nfs": - for item in range(0, snap_nums): - source_path = data_dir.get_data_dir() + "/images/snap_%s" % ( + for item in range(1, snap_nums+1): + source_path = params.get("nfs_mount_dir") + "/snap_%s" % ( item) path.append(source_path) return path @@ -142,8 +134,7 @@ def write_file(format_disk, file_name): if format_disk: cmd = "mkfs.ext4 /dev/%s;mount /dev/%s /mnt" % (target_disk, target_disk) session.cmd_status_output(cmd) - utils_disk.dd_data_to_vm_disk(session, file_name, bs='1M', - count='50') + utils_disk.dd_data_to_vm_disk(session, file_name, bs=bs, count=count) session.close() def get_alloc_result(): @@ -165,14 +156,14 @@ def get_alloc_result(): disk_dict = eval(params.get('disk_dict', '{}')) target_disk = params.get('target_disk') commit_option = params.get('commit_option') - disappear_index = params.get('disappear_index') disappear_alloc = params.get('disappear_alloc') + changing_index = params.get('changing_index') + changing_alloc = params.get('changing_alloc') commit_success_msg = params.get('commit_success_msg') extra_option = params.get('extra_option') disk_type = params.get('disk_type') domstats_option = params.get('domstats_option') snap_nums = int(params.get('snap_nums')) - vg_name, lv_name, lv_size = 'vg0', 'lv', "200M" vm = env.get_vm(vm_name) vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) @@ -180,7 +171,10 @@ def get_alloc_result(): test_obj = blockcommand_base.BlockCommand(test, vm, params) disk_obj = disk_base.DiskBase(test, vm, params) - + disk_obj.disk_size = "1G" + vg_name = disk_obj.vg_name + lv_name, lv_size = re.findall(r"\D+", disk_obj.lv_name)[0], params.get("lv_size") + bs, count = params.get("write_file_bs"), params.get("write_file_count") try: setup_test() run_test() diff --git a/libvirt/tests/src/backingchain/blockcopy/blockcopy_with_async_option.py b/libvirt/tests/src/backingchain/blockcopy/blockcopy_with_async_option.py index 336e852c6f5..2b9ce8aeefe 100644 --- a/libvirt/tests/src/backingchain/blockcopy/blockcopy_with_async_option.py +++ b/libvirt/tests/src/backingchain/blockcopy/blockcopy_with_async_option.py @@ -74,11 +74,17 @@ def _check_res(case, virsh_session=None): event_output)) elif case == 'async': + def _check_path(): + try: + check_obj.check_backingchain_from_vmxml( + disk_type, target_disk, [test_obj.copy_image]) + return True + except Exception as e: + return False + test.log.info("TEST_STEP2: Check expected chain") - expected_chain = test_obj.\ - convert_expected_chain(expected_chain_index) - check_obj.check_backingchain_from_vmxml(disk_type, target_disk, - expected_chain) + if not utils_misc.wait_for(_check_path, 60): + test.fail('Expect source file to be %s' % [test_obj.copy_image]) def _get_session(): """ diff --git a/libvirt/tests/src/backingchain/blockcopy/blockcopy_with_different_qcow2_properties.py b/libvirt/tests/src/backingchain/blockcopy/blockcopy_with_different_qcow2_properties.py index 39e828860de..4212abf18ed 100644 --- a/libvirt/tests/src/backingchain/blockcopy/blockcopy_with_different_qcow2_properties.py +++ b/libvirt/tests/src/backingchain/blockcopy/blockcopy_with_different_qcow2_properties.py @@ -1,9 +1,10 @@ import re +from virttest import libvirt_version from virttest import virsh - from virttest.libvirt_xml import vm_xml from virttest.utils_test import libvirt +from virttest.utils_libvirt import libvirt_disk from provider.backingchain import blockcommand_base from provider.backingchain import check_functions @@ -24,14 +25,20 @@ def setup_test(): Prepare image with properties and snap chain """ test.log.info("SETUP:Prepare image with properties and snap chain") + if property_item == "with_datastore": + libvirt.create_local_disk("file", path=datastore_path, size=image_size, + disk_format=image_format) libvirt.create_local_disk("file", path=image_path, size=image_size, disk_format=image_format, extra=image_extras) check_property(image_path, property_item) prepare_disk() - test_obj.backingchain_common_setup(create_snap=True, - snap_num=1, extra=snap_extra) - check_property(test_obj.snap_path_list[0], property_item) + test_obj.backingchain_common_setup( + create_snap=True, snap_num=1, snap_path=snap_path, extra=snap_extra) + + if property_item == "extended_l2_and_cluster_size": + check_property(test_obj.snap_path_list[0], property_item) + check_obj.check_backingchain_from_vmxml(disk_type, target_disk, expected_chain_after_snap) def run_test(): """ @@ -43,8 +50,16 @@ def run_test(): ignore_status=False, debug=True) - test.log.info("TEST_STEP2:Check properties after blockcopy.") - check_property(copy_image, property_item) + test.log.info("TEST_STEP2:Check guest xml and image properties " + "after blockcopy.") + check_obj.check_backingchain_from_vmxml(disk_type, target_disk, + [copy_image]) + + if property_item == "extended_l2_and_cluster_size": + check_property(copy_image, property_item) + + test.log.info("TEST_STEP3: Write file in guest") + libvirt_disk.check_virtual_disk_io(vm, target_disk) def teardown_test(): """ @@ -54,6 +69,8 @@ def teardown_test(): test_obj.backingchain_common_teardown() test_obj.clean_file(copy_image) test_obj.clean_file(image_path) + if datastore_path: + test_obj.clean_file(datastore_path) bkxml.sync() @@ -71,6 +88,8 @@ def check_property(path, property_item): cluster_size_value = int(re.findall(r"\d+", cluster_size)[0])*1024*1024 check_obj.check_image_info(path, 'csize', cluster_size_value) + elif property_item == "with_datastore": + check_obj.check_image_info(path, 'data file', datastore_path) def prepare_disk(): """ @@ -82,6 +101,7 @@ def prepare_disk(): test_obj.new_image_path = disk_obj.add_vm_disk( disk_type, disk_dict, new_image_path=image_path) + libvirt_version.is_libvirt_feature_supported(params) # Process cartesian parameters vm_name = params.get("main_vm") target_disk = params.get('target_disk') @@ -98,6 +118,9 @@ def prepare_disk(): property_item = params.get('property') cluster_size = params.get('cluster_size') expected_extended_l2 = params.get('expected_extended_l2') + datastore_path = params.get("datastore_path") + snap_path = params.get("snap_path") + expected_chain_after_snap = eval(params.get("expected_chain_after_snap", '{}')) encryption_disk = params.get('enable_encrypt_disk', 'no') == "yes" vm = env.get_vm(vm_name) diff --git a/libvirt/tests/src/backingchain/blockcopy/blockcopy_with_zero_length_disk.py b/libvirt/tests/src/backingchain/blockcopy/blockcopy_with_zero_length_disk.py index 67ce1f01fbc..c738fda1cb7 100644 --- a/libvirt/tests/src/backingchain/blockcopy/blockcopy_with_zero_length_disk.py +++ b/libvirt/tests/src/backingchain/blockcopy/blockcopy_with_zero_length_disk.py @@ -53,7 +53,7 @@ def prepare_transient_guest(): test.log.debug("Define guest by xml:\n%s", vmxml) virsh.undefine(vm_name, options='--nvram', debug=True, ignore_status=False) - virsh.create(vmxml.xml, shell=True) + virsh.create(vmxml.xml, debug=True, ignore_status=False) def run_test(): """ diff --git a/libvirt/tests/src/backingchain/blockcopy_options.py b/libvirt/tests/src/backingchain/blockcopy_options.py index 079eedf7df9..ee97cdbd042 100644 --- a/libvirt/tests/src/backingchain/blockcopy_options.py +++ b/libvirt/tests/src/backingchain/blockcopy_options.py @@ -42,7 +42,6 @@ def setup_blockcopy_extended_l2(): test_obj.new_image_path = image_path # start get old parts session = vm.wait_for_login() - test_obj.old_parts = utils_disk.get_parts_list(session) session.close() # attach new disk if encryption_disk: @@ -84,9 +83,8 @@ def test_blockcopy_extended_l2(): expected_value='true') # Check domain write file session = vm.wait_for_login() - new_parts = utils_disk.get_parts_list(session) - added_parts = list(set(new_parts).difference(set(test_obj.old_parts))) - utils_disk.linux_disk_check(session, added_parts[0]) + added_disk, _ = libvirt_disk.get_non_root_disk_name(session) + utils_disk.linux_disk_check(session, added_disk) session.close() def teardown_blockcopy_extended_l2(): diff --git a/libvirt/tests/src/backingchain/blockjob/blockjob_with_raw_option.py b/libvirt/tests/src/backingchain/blockjob/blockjob_with_raw_option.py index ff920fb645c..7a53bd0ddd8 100644 --- a/libvirt/tests/src/backingchain/blockjob/blockjob_with_raw_option.py +++ b/libvirt/tests/src/backingchain/blockjob/blockjob_with_raw_option.py @@ -87,12 +87,12 @@ def _abort_job(): test.log.info("Check if the job can be aborted successfully") if utils_misc.wait_for( lambda: libvirt.check_blockjob(vm_name, - dev, "progress", "100(.00)?"), 100): + dev, "progress", "100(.00)?"), 300): virsh.blockjob(vm_name, dev, options=' --pivot', debug=True, ignore_status=False) else: - test.fail("Blockjob timeout in 100 sec.") + test.fail("Blockjob timeout in 300 sec.") test.log.info("TEST_STEP3: Check the output of 'blockjob --raw' " "after aborting the job") diff --git a/libvirt/tests/src/backingchain/virsh_domblk/domblkthreshold_with_backingchain_element.py b/libvirt/tests/src/backingchain/virsh_domblk/domblkthreshold_with_backingchain_element.py index cce2f6acb2e..ddfce7a2781 100644 --- a/libvirt/tests/src/backingchain/virsh_domblk/domblkthreshold_with_backingchain_element.py +++ b/libvirt/tests/src/backingchain/virsh_domblk/domblkthreshold_with_backingchain_element.py @@ -1,10 +1,13 @@ import re +import time from virttest import utils_disk from virttest import virsh +from virttest import utils_misc from virttest.libvirt_xml import vm_xml from provider.backingchain import blockcommand_base +from provider.virtual_disk import disk_base def run(test, params, env): @@ -16,27 +19,34 @@ def setup(): Prepare active domain and backingchain """ test.log.info("Setup env.") + test_obj.new_image_path = disk_obj.add_vm_disk(disk_type, disk_dict, + size=disk_size) test_obj.backingchain_common_setup(create_snap=True, - snap_num=4) + snap_num=4, extra=snap_extra) + test.log.debug("Preparing xml is:\n %s", vm_xml.VMXML.new_from_dumpxml(vm.name)) def test_backing_target(): """ Do domblkthreshold for the backing file device target """ - test.log.info("TEST_STEP1:Set domblkthreshold for backing file device") + test.log.info("TEST_STEP1-2:Set domblkthreshold for backing file device") + time.sleep(5) virsh.domblkthreshold(vm_name, '%s[%s]' % (target_disk, domblk_index), domblk_threshold, debug=True, ignore_status=False) - check_domstats_threshold(domstats_option, domblk_threshold) + check_domstats_threshold(domstats_option, actual_threshold) - test.log.info("TEST_STEP2:Do blockcommit and check event") + test.log.info("TEST_STEP3-4:Write file and check event") + expected_event = event % (vm_name, target_disk, domblk_index, + actual_threshold) event_session = virsh.EventTracker.start_get_event(vm_name) write_file() + check_event(event_session, expected_event, existed=False) + + test.log.info("TEST_STEP5-7:Do blockcommit and check event") virsh.blockcommit(vm.name, target_disk, - commit_options % test_obj.snap_path_list[1], + commit_options % test_obj.snap_path_list[0], ignore_status=False, debug=True) - expected_event = event % (vm_name, target_disk, domblk_index, - domblk_threshold) check_event(event_session, expected_event) check_domstats_threshold(domstats_option) @@ -45,17 +55,17 @@ def test_entire_disk(): Do domblkthreshold for the entire disk device target """ test.log.info("TEST_STEP1:Set domblkthreshold for the entire disk") + time.sleep(5) virsh.domblkthreshold(vm_name, '%s' % target_disk, domblk_threshold, debug=True, ignore_status=False) - check_domstats_threshold(domstats_option, domblk_threshold) + check_domstats_threshold(domstats_option, actual_threshold) test.log.info("TEST_STEP2:Write file in guest and check event") event_session = virsh.EventTracker.start_get_event(vm_name) write_file() - expected_event = event % (vm_name, target_disk, domblk_threshold) + expected_event = event % (vm_name, target_disk, actual_threshold) check_event(event_session, expected_event) - check_domstats_threshold(domstats_option) def teardown(): """ @@ -77,13 +87,20 @@ def check_domstats_threshold(options, threshold_value=None): :param threshold_value: domstats threshold value, if it is None, result should be no output """ - result = virsh.domstats(vm_name, options, debug=True, - ignore_status=False).stdout_text.strip() if not threshold_value: + result = virsh.domstats(vm_name, options, debug=True, + ignore_status=False).stdout_text.strip() pattern = "block.*.threshold" if re.search(pattern, result): test.fail("Threshold: %s should not be in %s" % (pattern, result)) else: + if not utils_misc.wait_for( + lambda: + bool(threshold_value) == ('threshold' in virsh.domstats( + vm_name, options, debug=True).stdout_text.strip()), 30, 2): + test.fail('Failed to get expected threshold value in 30s') + result = virsh.domstats(vm_name, options, debug=True, + ignore_status=False).stdout_text.strip() pattern = r"block.*.threshold=%s" % threshold_value if not re.search(pattern, result): test.fail("Not get correct threshold: %s should be in %s" % ( @@ -94,21 +111,31 @@ def write_file(): Write file in guest """ session = vm.wait_for_login() - utils_disk.dd_data_to_vm_disk(session, large_file, bs='4M', count='200') + cmd = "mkfs.ext4 /dev/%s;mount /dev/%s /mnt" % (target_disk, target_disk) + session.cmd_status_output(cmd) + utils_disk.dd_data_to_vm_disk(session, mount_file, bs='8M', count='400') session.close() - def check_event(event_session, expected_event): + def check_event(event_session, expected_event, existed=True): """ Check event correct :param event_session: virsh session :param expected_event: expected event pattern + :param existed: if event existed, default True """ test.log.debug('Checking event pattern is -> %s', expected_event) - event_output = virsh.EventTracker.finish_get_event(event_session) - if not re.search(expected_event, event_output): - test.fail('Not find: %s from event output:%s' % ( - expected_event, event_output)) + event_output = event_session.get_stripped_output() + search_res = re.search(expected_event, event_output) + if existed: + if not search_res: + test.fail('Not find: %s from event output:%s' % ( + expected_event, event_output)) + else: + if search_res: + test.fail('Event:%s should not exist in output:%s' % ( + expected_event, event_output)) + test.log.debug("Checking event successfully") # Process cartesian parameters vm_name = params.get("main_vm") @@ -117,11 +144,18 @@ def check_event(event_session, expected_event): case_name = params.get('case_name', '') target_disk = params.get('target_disk') domblk_threshold = params.get('domblk_threshold') + actual_threshold = params.get('actual_threshold') domblk_index = params.get('domblk_index') domstats_option = params.get('domstats_option') commit_options = params.get('commit_options') + disk_dict = eval(params.get('disk_dict', '{}')) + disk_type = params.get("disk_type") + disk_size = params.get("disk_size") + mount_file = params.get("mount_file", "/mnt/file") + snap_extra = params.get("snap_extra") test_obj = blockcommand_base.BlockCommand(test, vm, params) + disk_obj = disk_base.DiskBase(test, vm, params) vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) bkxml = vmxml.copy() diff --git a/libvirt/tests/src/backingchain/virtual_disks_snapshot_blockpull.py b/libvirt/tests/src/backingchain/virtual_disks_snapshot_blockpull.py index 842a73a7dd5..14b9087bd82 100644 --- a/libvirt/tests/src/backingchain/virtual_disks_snapshot_blockpull.py +++ b/libvirt/tests/src/backingchain/virtual_disks_snapshot_blockpull.py @@ -9,9 +9,6 @@ from virttest import virt_vm from virttest import virsh -from virttest import utils_disk - - from virttest.utils_test import libvirt from virttest.utils_libvirt import libvirt_disk @@ -335,12 +332,9 @@ def start_middletotop_blkpull_on_vm(): # Initialize one NbdExport object nbd = None - # Start VM and get all partitions in VM. + # Start VM if vm.is_dead(): vm.start() - session = vm.wait_for_login() - old_parts = utils_disk.get_parts_list(session) - session.close() vm.destroy(gracefully=False) # Back up xml file. @@ -359,7 +353,11 @@ def start_middletotop_blkpull_on_vm(): setup_nbd_env(params) try: vm.start() - vm.wait_for_login().close() + session = vm.wait_for_login() + disk_name = device_target + if additional_disk: + disk_name, _ = libvirt_disk.get_non_root_disk_name(session) + session.close() except virt_vm.VMStartError as details: # VM cannot be started if status_error: @@ -368,7 +366,7 @@ def start_middletotop_blkpull_on_vm(): test.fail("VM should start but failed: %s" % str(details)) if fill_in_vm: - libvirt_disk.fill_null_in_vm(vm, device_target) + libvirt_disk.fill_null_in_vm(vm, disk_name) if backend_path in ['native_path']: external_snapshot_disks = libvirt_disk.make_external_disk_snapshots(vm, device_target, "blockpull_snapshot", snapshot_take) diff --git a/libvirt/tests/src/backingchain/with_disk_attributes_test/commit_pull_with_disk_source_attributes.py b/libvirt/tests/src/backingchain/with_disk_attributes_test/commit_pull_with_disk_source_attributes.py new file mode 100644 index 00000000000..7f85a320db1 --- /dev/null +++ b/libvirt/tests/src/backingchain/with_disk_attributes_test/commit_pull_with_disk_source_attributes.py @@ -0,0 +1,79 @@ +import os + +from virttest import data_dir +from virttest import virsh +from virttest import libvirt_version +from virttest.libvirt_xml import vm_xml +from virttest.utils_test import libvirt + +from provider.backingchain import blockcommand_base +from provider.backingchain import check_functions +from provider.virtual_disk import disk_base + + +def run(test, params, env): + """ + Do blockcommit/blockpull with different attributes of source elements. + 1) Prepare a running guest with the following source elements and create snapshots: + - datastore + 2) Do blockcommit/blockpull and check dumpxml. + """ + + def setup_test(): + """ + Prepare a running guest with different source elements and create snapshots. + """ + test.log.info("Setup env: prepare a running guest and snap chain.") + data_file = data_dir.get_data_dir() + '/datastore.img' + data_file_option = params.get("data_file_option") % data_file + back_obj.new_image_path = disk_obj.add_vm_disk(disk_type, disk_dict, new_image_path="", + extra=data_file_option) + back_obj.backingchain_common_setup(create_snap=True, snap_num=snap_num) + disk_xml = virsh.dumpxml(vm_name, "--xpath //disk", debug=True).stdout_text + if data_file not in disk_xml: + test.fail("Can't get the datastore element automatically!") + return data_file, back_obj.new_image_path + + def run_test(): + """ + Do blockcommit/blockpull for the guest with different source attributes. + """ + test.log.info("TEST_STEP1: Do blockcommit/blockpull.") + if block_cmd == "blockcommit": + virsh.blockcommit(vm_name, target_disk, common_options+blockcommit_options, + ignore_status=False, debug=True) + if block_cmd == "blockpull": + virsh.blockpull(vm_name, target_disk, common_options, + ignore_status=False, debug=True) + test.log.info("TEST_STEP2: Check expected disk image.") + expected_chain = back_obj.convert_expected_chain(expected_chain_index) + check_obj.check_backingchain_from_vmxml(disk_type, target_disk, expected_chain) + + libvirt_version.is_libvirt_feature_supported(params) + vm_name = params.get("main_vm") + target_disk = params.get("target_disk") + disk_type = params.get("disk_type") + disk_dict = eval(params.get("disk_dict", "{}")) + common_options = params.get("common_options") + snap_num = int(params.get("snap_num")) + block_cmd = params.get("block_cmd") + blockcommit_options = params.get("blockcommit_options", "") + expected_chain_index = params.get("expected_chain_index") + + vm = env.get_vm(vm_name) + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + bkxml = vmxml.copy() + + back_obj = blockcommand_base.BlockCommand(test, vm, params) + check_obj = check_functions.Checkfunction(test, vm, params) + disk_obj = disk_base.DiskBase(test, vm, params) + + try: + data_file, new_image_path = setup_test() + run_test() + finally: + libvirt.clean_up_snapshots(vm_name) + bkxml.sync() + for file in [data_file, new_image_path]: + if os.path.exists(file): + os.remove(file) diff --git a/libvirt/tests/src/bios/boot_integration.py b/libvirt/tests/src/bios/boot_integration.py index 8f8864fc1d0..708341e0a84 100755 --- a/libvirt/tests/src/bios/boot_integration.py +++ b/libvirt/tests/src/bios/boot_integration.py @@ -78,7 +78,7 @@ def console_check(vm, pattern, debug_log=False): :return: function returning true if console output matches pattern """ def _matches(): - output = vm.serial_console.get_stripped_output() + output = vm.serial_console.get_output() matches = re.search(pattern, output, re.S) if debug_log: logging.debug("Checked for '%s' in '%s'", pattern, output) diff --git a/libvirt/tests/src/controller/controller_functional.py b/libvirt/tests/src/controller/controller_functional.py index 2fc99baa89a..c1990521bee 100644 --- a/libvirt/tests/src/controller/controller_functional.py +++ b/libvirt/tests/src/controller/controller_functional.py @@ -281,23 +281,24 @@ def get_controller_addr(cntlr_type=None, model=None, index=None, cntlr_bus=None) (cntlr_type is None or elem.type == cntlr_type) and (model is None or elem.model == model) and (index is None or elem.index == index)): - addr_elem = elem.address - if addr_elem is None: - test.error("Can not find 'Address' " - "element for the controller") - p4 = None - if 'ccw' == cntlr_bus: - p1 = int(addr_elem.attrs.get('cssid'), 0) - p2 = int(addr_elem.attrs.get('ssid'), 0) - p3 = int(addr_elem.attrs.get('devno'), 0) - else: - p1 = int(addr_elem.attrs.get('bus'), 0) - p2 = int(addr_elem.attrs.get('slot'), 0) - p3 = int(addr_elem.attrs.get('function'), 0) - p4 = addr_elem.attrs.get('multifunction') - addr_str = '%02d:%02x.%1d' % (p1, p2, p3) - logging.debug("Controller address is %s", addr_str) - return (addr_str, p1, p2, p3, p4) + if elem._get_list("address"): + addr_elem = elem.address + if addr_elem is None: + test.error("Can not find 'Address' " + "element for the controller") + p4 = None + if 'ccw' == cntlr_bus: + p1 = int(addr_elem.attrs.get('cssid'), 0) + p2 = int(addr_elem.attrs.get('ssid'), 0) + p3 = int(addr_elem.attrs.get('devno'), 0) + else: + p1 = int(addr_elem.attrs.get('bus'), 0) + p2 = int(addr_elem.attrs.get('slot'), 0) + p3 = int(addr_elem.attrs.get('function'), 0) + p4 = addr_elem.attrs.get('multifunction') + addr_str = '%02d:%02x.%1d' % (p1, p2, p3) + logging.debug("Controller address is %s", addr_str) + return (addr_str, p1, p2, p3, p4) return (None, None, None, None, None) diff --git a/libvirt/tests/src/controller/pci_controller_memreserve.py b/libvirt/tests/src/controller/pci_controller_memreserve.py new file mode 100644 index 00000000000..45dc3fd4e47 --- /dev/null +++ b/libvirt/tests/src/controller/pci_controller_memreserve.py @@ -0,0 +1,220 @@ +import logging as log +import re + +from virttest import libvirt_version +from virttest import virsh + +from virttest.libvirt_xml.vm_xml import VMXML +from virttest.utils_libvirt import libvirt_pcicontr +from virttest.utils_libvirt import libvirt_vmxml +from virttest.utils_test import libvirt + +from provider.guest_os_booting import guest_os_booting_base as guest_os + +# Using as lower capital is not the best way to do, but this is just a +# workaround to avoid changing the entire file. +logging = log.getLogger('avocado.' + __name__) + + +def get_mem_reserve_size_in_vm(test, contr_addr, params, session): + """ + Get mem reserve size of specified controller within vm + + :param test: test object + :param contr_addr: str, the controller address + :param params: dict, test parameters + :param session: vm session + :return: int, the controller's memory reserve size + """ + contr_pattern = params.get("contr_pattern") + # According to test results, pcie root port's address in vm xml + # is consistent with the one within the vm, but pci-bridge doesn't. + # For example, + # Pci-bridge address in vm xml: + #
+ # But + # lspci shows in the vm: + # 08:01.0 PCI bridge: Red Hat, Inc. QEMU PCI-PCI bridge + # So codes do not match the address for pci-bridge so far + if contr_pattern.count("%s"): + contr_pattern = params.get("contr_pattern") % contr_addr + + lspci_output = session.cmd_output("lspci").strip() + test.log.debug("The lspci in vm:\n%s", lspci_output) + + found_contr = re.findall(contr_pattern, lspci_output) + if not found_contr: + test.fail("Can not find the controller with pattern %s" % contr_pattern) + test.log.debug("Found the controller:%s", found_contr[0]) + contr_addr = found_contr[0].split(" ")[0] + cmd = "lspci -vvv -s %s | grep 'Memory behind bridge:'" % contr_addr + contr_info = session.cmd_output(cmd).strip() + test.log.debug("Got the controller detailed information:%s", contr_info) + mem_reserve_size = re.findall("\[size=(.*)M\]", contr_info)[0] + test.log.debug("Got the default memory reserve size: %sM", mem_reserve_size) + return int(mem_reserve_size) + + +def get_controller_address(controller_xml, test): + """ + Get the controller's address from vm xml. + It only applies to pcie-root-port controller because pci-bridge's + address in vm xml is different with the one within the vm. + + For example, bus='0x00' slot='0x02' function='0x7' + In the lspci, the device address: 00:02.7 + + :param controller_xml: the controller's xml object + :param test: test object + :return: str, the expected controller's address within the vm + """ + test.log.debug("The controller:%s", controller_xml) + cntl_attrs = controller_xml.fetch_attrs()["address"]["attrs"] + bus = cntl_attrs["bus"].removeprefix("0x") + slot = cntl_attrs["slot"].removeprefix("0x") + func = cntl_attrs["function"].removeprefix("0x") + addr_in_vm = bus + ":" + slot + "." + func + test.log.debug("The address for this controller:%s", addr_in_vm) + return addr_in_vm + + +def get_controller(test, vm_xml, contr_dict): + """ + Get the controller from the vm xml + + :param test: test object + :param vm_xml: VMXML object + :param contr_dict: dict, the controller's configuration + :return: controller xml object + """ + contr_index = contr_dict["index"] + contr_model = contr_dict["model"] + contr_type = contr_dict["type"] + for cntl in vm_xml.devices.by_device_tag('controller'): + if (cntl.type == contr_type and + cntl.model == contr_model and + cntl.index == contr_index): + logging.debug("Found the controller:%s", cntl) + return cntl + test.error("Fail to get the controller in guest xml with " + "index %s, model %s, type %s" % (contr_index, + contr_model, + contr_type)) + + +def check__memReserve_by_controller_xml(test, params, vm_name, target_cntl): + """ + Check memory reserve value of specified controller in vm xml + + :param test: test object + :param params: dict, test parameters + :param vm_name: str, vm name + :param target_cntl: controller's xml + """ + cur_vm_xml = VMXML.new_from_dumpxml(vm_name) + expect_memReserve = params.get("memReserve") + cntl = get_controller(test, cur_vm_xml, target_cntl) + actual_memReserve = cntl.target.get("memReserve") + if not actual_memReserve or int(actual_memReserve) != int(expect_memReserve): + test.fail("Expect memReserve to be %s, " + "but found %s" % (expect_memReserve, actual_memReserve)) + else: + test.log.debug("Verify: The memReserve value in guest xml - PASS") + + +def update_vm_xml(test, params, vm_xml): + """ + Update vm xml with necessary controllers + + :param test: test object + :param params: dict, test parameters + :param vm_xml: VMXML object + """ + def _add_contr(controller_dict): + """ + Common function for adding a controller to vm xml + + :param controller_dict: dict, controller configuration + """ + dev_obj = libvirt_vmxml.create_vm_device_by_type("controller", controller_dict) + libvirt.add_vm_device( + vm_xml, dev_obj, virsh_instance=virsh + ) + test.log.debug("Add controller configuration:%s", controller_dict) + + test.log.debug("Step: Get maximum index of specified controller") + depend_contr_dict = params.get("depend_contr_dict") + contr_dict = params.get("contr_dict") + ret_indexes = libvirt_pcicontr.get_max_contr_indexes(vm_xml, + 'pci', + "pcie-root-port") + cntr_index = int(ret_indexes[0]) + if depend_contr_dict: + cntr_index += 1 + depend_contr_dict = eval(depend_contr_dict % cntr_index) + _add_contr(depend_contr_dict) + + test.log.debug("Step: Add controller with specified configuration") + contr_dict = contr_dict % (cntr_index + 1) + params["contr_dict"] = contr_dict + _add_contr(eval(contr_dict)) + + +def run(test, params, env): + """ + Test PCI controllers' memory reserve option + 1. Backup guest xml before the tests + 2. Modify guest xml and define the guest + 3. Start guest + 4. Do checking in vm xml and within vm + """ + libvirt_version.is_libvirt_feature_supported(params) + + firmware_type = params.get("firmware_type") + loader_dict = eval(params.get("loader_dict", "{}")) + new_memReserve = params.get("memReserve") + expect_memReserve = params.get("expect_memReserve", new_memReserve) + params['expect_memReserve'] = expect_memReserve + virsh_options = {'debug': True, 'ignore_status': False} + + vm_name = guest_os.get_vm(params) + vm = env.get_vm(vm_name) + vm_xml_obj = VMXML.new_from_inactive_dumpxml(vm_name) + vm_xml_backup = vm_xml_obj.copy() + try: + test.log.debug("Step: Update vm firmware configuration") + vmxml = guest_os.prepare_os_xml(vm_name, loader_dict, firmware_type=firmware_type) + test.log.debug("Step: Configure the controller with specified memReserve value") + update_vm_xml(test, params, vmxml) + cur_vm_xml = VMXML.new_from_inactive_dumpxml(vm_name) + contr_dict = eval(params.get("contr_dict")) + test.log.debug("Step: Get the added controller xml") + target_cntl = get_controller(test, cur_vm_xml, contr_dict) + test.log.debug("Step: Get the address of the added controller") + contr_address = get_controller_address(target_cntl, test) + + test.log.debug("Step: Start vm") + virsh.start(vm_name, **virsh_options) + logging.debug("Test VM XML after starting:" + "\n%s", VMXML.new_from_dumpxml(vm_name)) + + test.log.debug("Step: Check vm dumpxml for specified memReserve value") + check__memReserve_by_controller_xml(test, params, vm_name, target_cntl) + test.log.debug("Step: Check the controller's new reserved memory value in vm") + session = vm.wait_for_login() + actual_reserve_size = get_mem_reserve_size_in_vm(test, + contr_address, + params, + session + ) + actual_reserve_size = int(actual_reserve_size) * 1024 + if actual_reserve_size != int(expect_memReserve): + test.fail("Expect mem reserve size " + "in vm to be %d, but found %d" % (expect_memReserve, + actual_reserve_size)) + else: + test.log.debug("Verify: The mem reserve size " + "in vm is %d as expected - PASS", actual_reserve_size) + session.close() + finally: + vm_xml_backup.sync() diff --git a/libvirt/tests/src/cpu/aarch64_cpu_sve.py b/libvirt/tests/src/cpu/aarch64_cpu_sve.py index f0bab842961..d2ffc4f9feb 100644 --- a/libvirt/tests/src/cpu/aarch64_cpu_sve.py +++ b/libvirt/tests/src/cpu/aarch64_cpu_sve.py @@ -1,8 +1,9 @@ +import json import re import logging as log -from avocado.utils import process from avocado.core import exceptions +from avocado.utils import process from virttest import virsh from virttest import utils_package @@ -16,6 +17,382 @@ logging = log.getLogger('avocado.' + __name__) +def get_vector_lengths(vm_name): + """ + Get the supported and unsupported vector lengths on the host + + :param vm_name: str, the vm name + :return: (dict, dict), the supported and unsupported vector list + """ + cmd = '{"execute":"query-cpu-model-expansion", "arguments": {"type": "full", "model": {"name":"host"}}}' + virsh_opt = {"debug": True, "ignore_status": False} + unsupported_list = [] + supported_list = [] + ret = virsh.qemu_monitor_command(vm_name, cmd, **virsh_opt) + length_obj = json.loads(ret.stdout_text.strip()) + props_dict = length_obj.get("return").get("model").get("props") + for v_length, status in props_dict.items(): + match = re.findall("sve(\d+)", v_length) + if not match: + continue + if not status: + unsupported_list.append(int(match[0])) + elif status: + supported_list.append(int(match[0])) + supported_list.sort(reverse=True) + unsupported_list.sort(reverse=True) + logging.debug("The unsupported vector length in the vm:%s", unsupported_list) + logging.debug("The supported vector length in the vm:%s", supported_list) + return (supported_list, unsupported_list) + + +def prepare_env(vm, params, test): + """ + Prepare test env + + :param vm: The virtual machine + :param params: dict, test parameters + :param test: test object + """ + check_sve = params.get("check_sve", "") + host_without_sve = "yes" == params.get("host_without_sve", "no") + check_sve_config = params.get("check_sve_config", "") + session = None + try: + # Cancel test if the Host doesn't support or supports SVE based on configuration + if process.run(check_sve, ignore_status=True, shell=True).exit_status: + if not host_without_sve: + test.cancel("Host doesn't support SVE") + else: + return + else: + if host_without_sve: + test.cancel("Host supports SVE") + + if not vm.is_alive(): + vm.start() + session = vm.wait_for_login(timeout=120) + current_boot = session.cmd("uname -r").strip() + # To enable SVE: Hardware support && enable kconfig + # CONFIG_ARM64_SVE + if session.cmd_status(check_sve_config % current_boot): + test.cancel("Guest kernel doesn't enable CONFIG_ARM64_SVE") + + # Install lscpu tool that check whether CPU has SVE + if (not utils_package.package_install("util-linux") + or not utils_package.package_install("util-linux", session)): + test.error("Failed to install util-linux") + + except (exceptions.TestCancel, exceptions.TestError): + raise + except Exception as e: + test.error("Failed to prepare test env: %s" % e) + finally: + if session: + session.close() + + +def get_max_sve_len_in_guest(vm_session, params, test): + """ + Get the maximum supported sve length of guest + + :param vm_session: The virtual machine session + :param params: dict, test parameters + :param test: test object + :return: str, maximum vector length. Format: e.g sve512 + """ + get_maximum_sve_len = params.get("get_maximum_sve_length", "") + sve_length_bit = "" + try: + ret = vm_session.cmd(get_maximum_sve_len).strip() + # dmesg record maximum sve length in bytes + sve_length_byte = re.search(r"length (\d+) bytes", ret).groups()[0] + # Change max_length into sve + length(bit) E.g. sve512 + sve_length_bit = "sve" + str(int(sve_length_byte) * 8) + logging.debug("The guest maximum SVE vector length is %s", sve_length_bit) + except Exception as e: + test.fail("Failed to get maximum guest SVE vector length: %s" % e) + + return sve_length_bit + + +def guest_has_sve(vm_session, params, test): + """ + Check whether guest has SVE + + :param vm_session: The virtual machine session + :param params: dict, test parameters + :param test: test object + + :return True if guest has sve + """ + check_sve = params.get("check_sve", "") + ret = False + try: + if not vm_session.cmd_status(check_sve): + ret = True + except Exception as e: + test.error("Failed to check guest SVE: %s" % e) + return ret + + +def check_vector_length_supported(vector_length, supported_list): + """ + Check if a given vector length is supported on the host + + :param vector_length: str, sve length + :param supported_list: list, sve lengths supported + :return: bool, True if supported, otherwise False + """ + match = re.findall("sve(\d+)", vector_length) + if match and int(match[0]) in supported_list: + return True + else: + logging.warning("The vector length %s (in bits) is " + "unsupported on the host" % vector_length) + return False + + +def gen_disable_features(enable_length, supported_list): + """ + Generate the cpu features to be disabled + + :param enable_length: str, sve length to be enabled + :param supported_list: dict, sve lengths supported + :return: list, disabled cpu features + """ + result = [] + enable_length = re.findall("sve(\d+)", enable_length)[0] + for a_length in supported_list: + if a_length > int(enable_length): + result.append({"sve%d" % a_length: "disable"}) + return result + + +def gen_cpu_features(supported_list, unsupported_list, params, test): + """ + Generate cpu features + + :param supported_list: dict, sve lengths supported + :param unsupported_list: dict, sve lengths unsupported + :param params: dict, test parameters + :param test: test object + :return: list, cpu features + """ + all_supports = params.get("all_supports", "no") == "yes" + status_error = "yes" == params.get("status_error", "no") + vector_length = params.get("vector_length") + cpu_xml_policy = params.get("cpu_xml_policy", "require") + unsupported_len = params.get("unsupported_len") + discontinous_len = params.get("discontinous_len") + result = [] + + if not status_error: + if all_supports: + result.append({"sve": cpu_xml_policy}) + for a_length in supported_list: + result.append({"sve%d" % a_length: cpu_xml_policy}) + return result + if vector_length: + if not check_vector_length_supported(vector_length, supported_list): + test.cancel("The vector length is not supported on the host") + result.append({vector_length: cpu_xml_policy}) + result.extend(gen_disable_features(vector_length, supported_list)) + else: + result.append({"sve": cpu_xml_policy}) + else: + vector_length_list = params.get("vector_length_list") + if unsupported_len: + if len(unsupported_list) > 1: + result.append({"sve%d" % unsupported_list[0]: cpu_xml_policy}) + else: + test.cancel("No unsupported vector length by the host is available") + elif discontinous_len: + if len(supported_list) == 1: + test.cancel("Require at least two supported " + "sve lengths for the test, but only one is found") + result.append({"sve%d" % supported_list[0]: "require"}) + result.append({"sve%d" % supported_list[len(supported_list) - 1]: "disable"}) + elif vector_length_list: + vector_length_list = eval(vector_length_list) + for one_len in vector_length_list: + result.append(one_len) + else: + if vector_length: + result.append({vector_length: cpu_xml_policy}) + return result + + +def update_cpu_xml(cpu_xml, params, test, supported_list, unsupported_list): + """ + Update vm cpu xml object + + :param cpu_xml: VMCPUXML instance + :param params: dict, test parameters + :param test: test object + :param supported_list: list, sve lengths supported + :param unsupported_list: list, sve lengths unsupported + """ + if not supported_list and not unsupported_list: + # There is no sve support on the host. + # This is to expect an error message with sve=require + # when starting the vm. + vector_list = [{'sve': params.get("cpu_xml_policy")}] + else: + vector_list = gen_cpu_features(supported_list, + unsupported_list, + params, + test) + for vector in vector_list: + for length, policy in vector.items(): + cpu_xml.add_feature(length, policy) + logging.debug("cpu_xml is %s" % cpu_xml) + + +def execute_cmds(cmd, session, test, timeout=720, ignore_status=False): + """ + Execute a command with vm session + + :param cmd: str, the command to be executed + :param session: vm session + :param test: test object + :param timeout: int, defaults to 360 + :param ignore_status: bool, defaults to False + :return: str, the output of the command + """ + status, output = session.cmd_status_output(cmd, timeout=timeout) + if status: + msg = "Fail to execute %s with error %s,\ + message: %s" % (cmd, status, output) + if not ignore_status: + test.fail(msg) + else: + test.log.error(msg) + return output + + +def run_optimized_routines_in_guest(session, params, test): + """ + Run optimized routines test suite within the guest + + :param session: vm session + :param params: dict, test parameters + :param test: test object + """ + execute_cmds(params.get("optimized_repo_cmd"), session, test) + execute_cmds(params.get("optimized_compile_cmd"), session, test) + output = execute_cmds(params.get("optimized_execute_cmd"), session, test) + results = re.findall(r"^(\w+) \w+sve$", output, re.M) + if not all([result == "PASS" for result in results]): + test.fail("The optimized-routines sve tests have failures in log\n%s" % results) + else: + test.log.debug("Verify optimized-routines sve tests in guest - PASS") + + +def execute_sve_stress_by_suite(length_list, session, params, test): + """ + Execute sve_stress test suite within the guest + + :param length_list: list, sve lengths + :param session: vm session + :param params: dict, test parameters + :param test: test object + """ + sve_stress_exec_cmd = params.get("sve_stress_exec_cmd") + sve_exec_timeout = int(params.get("sve_exec_timeout")) + + for a_length in length_list: + exec_cmd = sve_stress_exec_cmd % a_length + output = session.cmd_output(exec_cmd, + timeout=sve_exec_timeout + 10) + results_lines = [result for result in output.splitlines() if + result.startswith("Terminated by")] + if len(re.findall(r"no error", output, re.M)) != len(results_lines): + test.log.debug("Test results: %s", results_lines) + test.fail("SVE stress test failed") + test.log.debug("Verify sve stress test for length %s (in bytes) - PASS" % a_length) + + +def run_sve_ptrace_test_in_guest(session, params, test): + """ + Run sve_ptrace test suite within the guest + + :param session: vm session + :param params: dict, test parameters + :param test: test object + """ + sve_ptrace_exec_cmd = params.get("sve_ptrace_exec_cmd") + output = session.cmd_output(sve_ptrace_exec_cmd) + results_lines = [result for result in output.splitlines() if + result.startswith("# Totals:")] + pat = "fail:(\d+).*xfail:(\d+).*error:(\d+)" + match = re.findall(pat, results_lines[0]) + if match: + if any([int(match[0][0]), int(match[0][1]), int(match[0][2])]): + test.fail("The sve-ptrace test fail with errors:%s" % results_lines[0]) + else: + test.error("Can not get Totals: line from test result") + test.log.debug("Verify sve ptrace test - PASS") + + +def verify_sve_length_by_suite(supported_list, session, params, test): + """ + Verify the supported sve lengths are same with test suite output + + :param supported_list: list, supported sve length (in bits), like [128, 256] + :param session: vm session + :param params: dict, test parameters + :param test: test object + :return: list, sve length (in bytes) list from test suite command + like ['16', '32'] + """ + sve_stress_get_lenths = params.get("sve_stress_get_lenths") + output = execute_cmds(sve_stress_get_lenths, session, test) + results = re.findall(r"# (\d+)$", output, re.M) + new_results = [int(result) * 8 for result in results] + if set(new_results) != set(supported_list): + test.fail("The sve-probe-vls output %s does " + "not match the supported sve lenths %s" % (results, + supported_list)) + else: + test.log.debug("Verify sve-probe-vls output in guest - PASS") + return results + + +def prepare_kernel_selftest_in_guest(session, params, test): + """ + Prepare the kernel self test repo in the guest + + :param session: vm session + :param params: dict, test parameters + :param test: test object + """ + kernel_version = session.cmd_output("uname -r").rsplit('.', 1)[0] + srpm = "kernel-%s.src.rpm" % kernel_version + linux_name = "linux-%s.tar.xz" % kernel_version + kernel_download_cmd = params.get("kernel_download_cmd") % (srpm, + srpm) + kernel_tar_cmd = params.get("kernel_tar_cmd") % linux_name + kernel_selftest_compile_cmd = params.get("kernel_selftest_compile_cmd") + + execute_cmds(kernel_download_cmd, session, test) + execute_cmds(kernel_tar_cmd, session, test) + execute_cmds(kernel_selftest_compile_cmd, session, test) + + +def run_sve_stress_test_in_guest(supported_list, session, params, test): + """ + Run sve stress test suite within the guest + + :param supported_list: list, supported sve lengths + :param session: vm session + :param params: dict, test parameters + :param test: test object + """ + sve_lengths = verify_sve_length_by_suite(supported_list, session, params, test) + execute_sve_stress_by_suite(sve_lengths, session, params, test) + + def run(test, params, env): """ Test aarch64 SVE feature @@ -26,128 +403,33 @@ def run(test, params, env): """ vm_name = params.get("main_vm", "avocado-vt-vm1") vm = env.get_vm(vm_name) - start_vm = params.get("start_vm", "no") - check_sve = params.get("check_sve", "") - check_sve_config = params.get("check_sve_config", "") - get_maxium_sve_length = params.get("get_maxium_sve_length", "") - cpu_xml_mode = params.get("cpu_xml_mode", "host-passthrough") - cpu_xml_policy = params.get("cpu_xml_policy", "require") - status_error = "yes" == params.get("status_error", "no") define_error = "yes" == params.get("define_error", "no") expect_sve = "yes" == params.get("expect_sve", "yes") expect_msg = params.get("expect_msg", "") vector_length = params.get("vector_length", "sve") - vector_lenth_list = params.get("vector_lenth_list", "") - - def _prepare_env(vm): - """ - Prepare test env - - :param vm: The virtual machine - """ - try: - if not vm.is_alive(): - vm.start() - session = vm.wait_for_login(timeout=120) - current_boot = session.cmd('uname -r').strip() - - # Install lscpu tool that check whether CPU has SVE - if (not utils_package.package_install("util-linux") - or not utils_package.package_install("util-linux", session)): - test.error("Failed to install util-linux") - # Cancel test if host doesn't support SVE - if process.run(check_sve, - ignore_status=True, shell=True).exit_status: - test.cancel("Host doesn't support SVE") - # To enable SVE: Hardware support && enable kconfig - # CONFIG_ARM64_SVE - if session.cmd_status(check_sve_config % current_boot): - test.cancel("Guest kernel doesn't enable CONFIG_ARM64_SVE") - except (exceptions.TestCancel, exceptions.TestError): - raise - except Exception as e: - test.error("Failed to prepare test env: %s" % e) - finally: - if session: - session.close() - - def _get_maxium_sve_length(vm): - """ - Get the maximum supported sve length of guest - - : return maximum vector length. Format: e.g sve512 - """ - try: - session = None - if not vm.is_alive(): - vm.start() - session = vm.wait_for_login(timeout=120) - ret = session.cmd(get_maxium_sve_length).strip() - # dmesg record maximum sve length in bytes - sve_length_byte = re.search("length (\d+) bytes", ret).groups()[0] - # Change max_length into sve + length(bit) E.g. sve512 - sve_length_bit = "sve" + str(int(sve_length_byte) * 8) - logging.debug("guest sve_length_bit is %s" % sve_length_bit) - except Exception as e: - test.fail("Failed to get guest SVE Vector length: %s" % e) - finally: - if session: - session.close() - return sve_length_bit - - def _guest_has_sve(vm): - """ - Check whether guest has SVE + sve_stress_exec_cmd = params.get("sve_stress_exec_cmd") + sve_ptrace_exec_cmd = params.get("sve_ptrace_exec_cmd") + optimized_execute_cmd = params.get("optimized_execute_cmd") + target_dir = params.get("target_dir") + host_without_sve = "yes" == params.get("host_without_sve") + supported_list = None + unsupported_list = None - :param vm: The virtual machine + prepare_env(vm, params, test) + if not host_without_sve: + supported_list, unsupported_list = get_vector_lengths(vm_name) - :return True if guest has sve - """ - try: - ret = False - session = None - if not vm.is_alive(): - vm.start() - session = vm.wait_for_login(timeout=120) - if not session.cmd_status(check_sve): - ret = True - except Exception as e: - test.error("Failed to check guest SVE: %s" % e) - finally: - if session: - session.close() - return ret - - # Close guest and edit guest xml - if vm.is_alive() and start_vm == "no": + if vm.is_alive(): vm.destroy(gracefully=False) vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) original_vm_xml = vmxml.copy() - try: - # Install lscpu && Check host sve support && - # Check guest guest kernel support - _prepare_env(vm) - - # Create cpu xml and modify SVE cpu_xml = vm_xml.VMCPUXML() cpu_xml.mode = cpu_xml_mode - # For sve, each SVE vector_length is a feature name - # E.g. sve128 sve256 sve512 - if vector_lenth_list: - vector_list = eval(vector_lenth_list) - for vector in vector_list: - for length, policy in vector.items(): - cpu_xml.add_feature(length, policy) - else: - cpu_xml.add_feature(vector_length, cpu_xml_policy) - - logging.debug("cpu_xml is %s" % cpu_xml) - - # Updae vm's cpu + update_cpu_xml(cpu_xml, params, test, supported_list, unsupported_list) vmxml.cpu = cpu_xml try: vmxml.sync() @@ -155,42 +437,61 @@ def _guest_has_sve(vm): except LibvirtXMLError as e: if define_error: if not re.search(expect_msg, str(e)): - test.fail("Expect definition failure: %s but got %s" % (expect_msg, str(e))) - return True + test.fail("Expect definition failure: %s but got %s" % + (expect_msg, str(e))) + else: + test.log.debug("Verify the expected vm definition error - PASS") + return else: test.error("Failed to define guest: %s" % str(e)) - result = virsh.start(vm_name) - libvirt.check_exit_status(result, status_error) - - if status_error: - # Test boot failed - if result.exit_status: - if not re.search(expect_msg, result.stderr.strip()): - logging.debug(result.stderr.strip()) - test.fail("Failed to get expect err msg: %s" % expect_msg) - else: - logging.info("Get expected err msg %s" % expect_msg) - else: - # Test boot successfully + result = virsh.start(vm_name, debug=True, ignore_status=True) + libvirt.check_result(result, expected_fails=expect_msg) + # Test boot successfully + if not status_error: + session = vm.wait_for_login(timeout=120) if expect_sve: - # Enable SVE in domain xml - if not _guest_has_sve(vm): + # Expect SVE is enabled in domain xml + if not guest_has_sve(session, params, test): test.fail("Expect guest cpu enable SVE") - - # SVE available with only the selected vector + else: + test.log.debug("Verify sve is enabled in guest - PASS") + # Expect SVE is available with only the selected vector expect_vector_length = vector_length + available_maximum_sve_length = get_max_sve_len_in_guest(session, params, test) if vector_length == "sve": - expect_vector_length = "sve512" - if expect_vector_length != _get_maxium_sve_length(vm): + expect_vector_length = "sve%d" % supported_list[0] + if expect_vector_length != available_maximum_sve_length: test.fail("Expect guest support %s" % vector_length) + else: + test.log.debug("Verify the supported maximum " + "vector length is %s in guest " + "- PASS" % expect_vector_length) + + install_pkgs = eval(params.get("install_pkgs", "[]")) + if install_pkgs and not utils_package.package_install(install_pkgs, session, 360): + test.error("Failed to install %s on guest." % install_pkgs) + + if target_dir: + execute_cmds("mkdir -p %s" % target_dir, session, test) + if params.get("kernel_testing_dir"): + prepare_kernel_selftest_in_guest(session, params, test) + if sve_stress_exec_cmd: + run_sve_stress_test_in_guest(supported_list, session, params, test) + if sve_ptrace_exec_cmd: + run_sve_ptrace_test_in_guest(session, params, test) + if optimized_execute_cmd: + run_optimized_routines_in_guest(session, params, test) + execute_cmds("rm -rf %s" % target_dir, session, test) else: # Disable SVE in domain xml - if _guest_has_sve(vm): + if guest_has_sve(session, params, test): test.fail("Expect guest cpu disable SVE") - + else: + test.log.debug("Verify sve is disabled in guest - PASS") + if session: + session.close() finally: - # Restore guest if vm.is_alive(): vm.destroy(gracefully=False) original_vm_xml.sync() diff --git a/libvirt/tests/src/cpu/aarch64_gic_version.py b/libvirt/tests/src/cpu/aarch64_gic_version.py new file mode 100644 index 00000000000..e6ae67c4278 --- /dev/null +++ b/libvirt/tests/src/cpu/aarch64_gic_version.py @@ -0,0 +1,119 @@ +import re +import logging + +from avocado.utils import process +from virttest import virsh +from virttest.libvirt_xml import vm_xml +from virttest.utils_test import libvirt + + +LOG = logging.getLogger('avocado.' + __name__) + + +def run(test, params, env): + """ + Test GIC version feature + + :param test: QEMU test object + :param params: Dictionary with the test parameters + :param env: Dictionary with test environment. + """ + vm_name = params.get("main_vm", "avocado-vt-vm1") + vm = env.get_vm(vm_name) + + start_vm = params.get("start_vm", "no") + check_gic_command_host = params.get("check_gic_command_host", "") + check_gic_command_guest = params.get("check_gic_command_guest", "") + gic_version = params.get("gic_version", "") + + status_error = "yes" == params.get("status_error", "no") + err_msg = params.get("err_msg", "") + + def _check_host_support(vm): + """ + Check the host support for GIC + + :param vm: The virtual machine + """ + # Checks whether CPU has GIC + if not process.run( + check_gic_command_host, + ignore_status=True, + shell=True).stdout_text: + test.cancel("Host doesn't support CPU GIC") + + def _check_vm_start(vm): + """ + Verifies GIC version setting in VM XML works as expected. + + :param vm: The virtual machine + :param gic_version: The GIC version value to set and verify + """ + # Update VM XML with the specified GIC version + # Start the VM and capture the output + result = virsh.start(vm.name, debug=True) + libvirt.check_exit_status(result, status_error) + + def _check_gic_version(vm, gic_version): + """ + Check the host and guest gic version + + :param vm: The virtual machine + :param gic_version: The GIC version value to test (eg, "2", "3", or "host") + """ + if not vm.is_alive(): + LOG.debug("VM is not active, skipping GIC version check") + return + + session = None + try: + # Check GIC version on host + host_gic_version_output = process.run( + check_gic_command_host, shell=True).stdout_text + + match = re.search(r"(GICv\d+)", host_gic_version_output) + if not match: + test.fail("Could not determine host GIC version") + else: + actual_host_gic_version = match.group(1) + + # Verify guest GIC version based on GIC version + session = vm.wait_for_login(timeout=120) + ret_guest = session.cmd_output(check_gic_command_guest) + + exp_gic_version = actual_host_gic_version if gic_version == 'host' else 'GICv%s' % gic_version + if exp_gic_version not in ret_guest: + test.fail( + f"Guest GIC version mismatch for GICv{gic_version}. Expected: {exp_gic_version}, Actual: {ret_guest}") + + finally: + if session: + session.close() + + # Close guest and edit guest xml + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + original_vm_xml = vmxml.copy() + + try: + # Additional preparation steps for GIC tests can be added here + _check_host_support(vm) + + vm_features = vmxml.features + vm_features.add_feature('gic', 'version', gic_version) + vmxml.features = vm_features + LOG.debug(f"Testing GIC version: {gic_version}") + + LOG.debug("Original VM XML:\n{original_vm_xml}") + + LOG.debug("Updated VM XML:\n{vmxml}") + + vmxml.sync() + + _check_vm_start(vm) + _check_gic_version(vm, gic_version) + + finally: + # Restore guest + if vm.is_alive(): + vm.destroy(gracefully=False) + original_vm_xml.sync() diff --git a/libvirt/tests/src/cpu/iothread.py b/libvirt/tests/src/cpu/iothread.py index 13cde5619ce..48afd624431 100644 --- a/libvirt/tests/src/cpu/iothread.py +++ b/libvirt/tests/src/cpu/iothread.py @@ -45,6 +45,7 @@ def update_iothread_xml(define_error=False): """ vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) vm_attrs = eval(params.get("vm_attrs", "{}")) + iothread_config = eval(params.get("iothread_config", "{}")) del vmxml.cputune del vmxml.iothreadids del vmxml.iothreads @@ -55,6 +56,9 @@ def update_iothread_xml(define_error=False): if iothread_ids: ids_xml = vm_xml.VMIothreadidsXML() ids_xml.iothread = [{'id': id} for id in iothread_ids.split()] + if iothread_config: + ids_xml.iothread = iothread_config['iothread'] + vmxml.iothreadids = ids_xml # Set cputune if any([iothreadpins, iothreadscheds, iothread_quota, iothread_period]): @@ -226,9 +230,13 @@ def exec_iothreadadd(): iothreadadd, "add") # Check xml xml_info = vm_xml.VMXML.new_from_dumpxml(vm_name) - if {'id': iothreadadd} not in xml_info.iothreadids.iothread: - test.fail("The iothread id {} is not added into xml" - .format(iothreadadd)) + found = False + for a_iothread in xml_info.iothreadids.iothread: + if iothreadadd == a_iothread['id']: + found = True + if not found: + test.fail("The iothread id {} is not " + "added into xml".format(iothreadadd)) def exec_iothreadpin(): """ @@ -236,7 +244,6 @@ def exec_iothreadpin(): :raise: test.fail if virsh command failed """ - thread_id, cpuset = iothreadpin.split() virsh.iothreadpin(vm_name, thread_id, cpuset, debug=True) update_expected_iothreadinfo(exp_iothread_info, @@ -247,6 +254,73 @@ def exec_iothreadpin(): if item not in xml_info.cputune.iothreadpins: test.fail("Unable to get {} from xml".format(item)) + def _reassemble_iothread_config(mapping): + """ + Reassemble iothreads using configuration + + :param mapping: dict, mapping from command line option to object key + :return: dict, the assembled iothreads + """ + iothread_config = eval(params.get('iothread_config', '{}')) + iothreadset_val = params.get('iothreadset_val') + iothread1 = {'id': params.get('iothreadset_id')} + tmp_poll = {} + lst = iothreadset_val.split('--') + for item in lst: + if not item: + continue + if item.split()[0] in mapping: + tmp_poll.update({mapping[item.split()[0]]: item.split()[1]}) + else: + iothread1.update({re.sub('-', '_', item.split()[0]): item.split()[1]}) + iothread1.update({'poll': tmp_poll}) + iothread_config['iothread'].append(iothread1) + logging.debug("Configured iothreads:%s", iothread_config['iothread']) + return iothread_config + + def _verify_iothreadids_by_domstats(iothread_id, mapping, iothread_attrs): + """ + Verify domstats output for iothreads + + :param iothread_id: str, iothread id + :param mapping: dict, mapping from command line option to object key + :param iothread_attrs: dict, attributes for iothread + """ + current_poll_info = get_iothread_pool(vm_name, iothread_id) + converted_poll_dict = {} + for key, value in current_poll_info.items(): + key_iothread = mapping[key[key.rindex('.') + 1: len(key)]] + converted_poll_dict.update({key_iothread: value}) + + if converted_poll_dict != iothread_attrs['poll']: + test.fail("Expect iothread poll info to be '%s'," + " but found '%s'" % (iothread_attrs['poll'], + converted_poll_dict)) + logging.debug("Verify domstats output for iothread %s - PASS", iothread_id) + + def verify_iothread_by_vm_xml(): + """ + Verify iothreads by checking dump vm xml + """ + mapping = {'poll-max-ns': 'max', 'poll-grow': 'grow', 'poll-shrink': 'shrink'} + iothread_config = _reassemble_iothread_config(mapping) + vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) + iothreadid_list = vmxml.iothreadids.iothread + for one_iothread in iothreadid_list: + iothread_attrs = one_iothread.fetch_attrs() + iothread_id = iothread_attrs['id'] + iothread_id_found = False + for iothread_cfg in iothread_config['iothread']: + if iothread_id == iothread_cfg['id']: + iothread_id_found = True + if iothread_attrs != iothread_cfg: + test.fail("Expect iothread to be '%s', " + "but found '%s'" % (iothread_cfg, iothread_attrs)) + if not iothread_id_found: + test.fail("The iothread '%s' is not expected in vm xml" % iothread_id) + _verify_iothreadids_by_domstats(iothread_id, mapping, iothread_attrs) + logging.debug("Verify iothread attributes by vm xml - PASS") + def verify_thread_pool(): """ Verify the thread pool values are updated correctly @@ -298,14 +372,16 @@ def verify_poll(): check_iothread_pool(UPDATE_IOTHREAD_POOL, exp_pool, True) logging.debug("Verify iothread poll: PASS") - def exec_iothreadset(): + def exec_iothreadset(need_verify=True): """ Run "virsh iothreadset" and do checking according to the parameters + :param need_verify: boolean, True to verify more, + False to only execute iothreadset """ test_poll = True if '--poll' in params.get('iothreadset_val') else False test_thread_pool = True if '--thread-pool' in params.get('iothreadset_val') else False - if test_poll: + if test_poll and need_verify: # Check domstats before run virsh iothreadset global ORG_IOTHREAD_POOL ORG_IOTHREAD_POOL = get_iothread_pool(vm_name, iothreadset_id) @@ -316,9 +392,9 @@ def exec_iothreadset(): if err_msg: libvirt.check_result(result, expected_fails=err_msg) - if test_poll: + if test_poll and need_verify: verify_poll() - if test_thread_pool: + if test_thread_pool and need_verify: verify_thread_pool() def exec_attach_disk(vm_name, source, target, thread_id, @@ -468,10 +544,12 @@ def _exec_schedinfo(items, update_error=False): pre_vm_stats = params.get("pre_vm_stats") restart_libvirtd = "yes" == params.get("restart_libvirtd", "no") restart_vm = "yes" == params.get("restart_vm", "no") - start_vm = "yes" == params.get("start_vm", "no") + need_start_vm = "yes" == params.get("need_start_vm", "no") test_operations = params.get("test_operations") cmd_options = params.get("cmd_options", '') + check_iotheadids_inactive = params.get("check_iotheadids_inactive") + status_error = "yes" == params.get("status_error", "no") define_error = "yes" == params.get("define_error", "no") err_msg = params.get("err_msg") @@ -517,7 +595,8 @@ def _exec_schedinfo(items, update_error=False): elif action == "iothreadpin": exec_iothreadpin() elif action == "iothreadset": - exec_iothreadset() + need_verify = False if check_iotheadids_inactive else True + exec_iothreadset(need_verify) elif action == "checkschedinfo": check_schedinfo() elif action == "attachdisk": @@ -542,7 +621,7 @@ def _exec_schedinfo(items, update_error=False): after_restart_domstas, True) # Check if vm could start successfully - if start_vm: + if need_start_vm: if vm.is_alive(): vm.destroy() result = virsh.start(vm_name, debug=True) @@ -550,6 +629,8 @@ def _exec_schedinfo(items, update_error=False): libvirt.check_exit_status(result, status_error) if err_msg: libvirt.check_result(result, expected_fails=err_msg) + if check_iotheadids_inactive: + verify_iothread_by_vm_xml() if not status_error: iothread_info = libvirt.get_iothreadsinfo(vm_name) diff --git a/libvirt/tests/src/cpu/lifecycle_time.py b/libvirt/tests/src/cpu/lifecycle_time.py index 491617d43c9..6b506b60284 100644 --- a/libvirt/tests/src/cpu/lifecycle_time.py +++ b/libvirt/tests/src/cpu/lifecycle_time.py @@ -39,7 +39,7 @@ def run(test, params, env): session.close() lines = out.split('\n') - if len(lines) < 2 or 'real\t0m1.00' not in lines[1]: + if len(lines) < 2 or 'real\t0m1.0' not in lines[1]: test.fail("VM seems to have slept longer than expected: %s" % out) except Exception as e: test.error("Test error: %s" % e) diff --git a/libvirt/tests/src/cpu/max_vcpus.py b/libvirt/tests/src/cpu/max_vcpus.py index 339bac3f2eb..e5aa323472b 100644 --- a/libvirt/tests/src/cpu/max_vcpus.py +++ b/libvirt/tests/src/cpu/max_vcpus.py @@ -88,6 +88,7 @@ def set_iommu(vmxml, **dargs): report_num_q35_7_8 = params.get('report_num_q35_7_8', '') report_num_q35_8_3 = params.get('report_num_q35_8_3', '') report_num_q35_8_4 = params.get('report_num_q35_8_4', '') + report_num_q35_9_6 = params.get('report_num_q35_9_6', '') logging.info('Check the output of virsh capabilities') xmltreefile = capability_xml.CapabilityXML().xmltreefile machtype_vcpunum_dict = {} @@ -108,25 +109,22 @@ def set_iommu(vmxml, **dargs): .format(report_num_pc_7, machtype_vcpunum_dict[key])) if key.startswith('pc-q35') or key == 'q35': + exp_val = report_num_q35_7_8 if key == "pc-q35-rhel7.3.0": - if machtype_vcpunum_dict[key] != report_num_q35_73: - test.fail('Test failed as q35_rhel73_max_vcpus_num ' - 'in virsh_capa is wrong. Expected: {} ' - 'Actual: {}.' - .format(report_num_q35_73, - machtype_vcpunum_dict[key])) + exp_val = report_num_q35_73 + elif key == "pc-q35-rhel9.6.0" or key == "pc-q35-rhel10.0.0" or key == 'q35': + exp_val = report_num_q35_9_6 else: - exp_val = report_num_q35_7_8 if libvirt_version.version_compare(7, 0, 0): exp_val = report_num_q35_8_4 elif libvirt_version.version_compare(6, 6, 0): exp_val = report_num_q35_8_3 - if machtype_vcpunum_dict[key] != exp_val: - test.fail('Test failed as the q35_max_vcpus_num in ' - 'virsh_capa is wrong. Expected: {} ' - 'Actual: {}.' - .format(exp_val, - machtype_vcpunum_dict[key])) + if machtype_vcpunum_dict[key] != exp_val: + test.fail('Test failed as the q35_max_vcpus_num for' + ' machine type:{} in virsh_capa is wrong.' + ' Expected: {}, Actual: {}.' + .format(key, exp_val, + machtype_vcpunum_dict[key])) # Test i440fx VM starts with 240(positive)/241(negative) vcpus and hot-plugs vcpus to 240 if check.startswith('i440fx_test'): @@ -168,7 +166,8 @@ def set_iommu(vmxml, **dargs): vmxml.vcpu = int(guest_vcpu) set_iommu(vmxml) result_need_check = virsh.define(vmxml.xml, debug=True) - + if libvirt_version.version_compare(10, 10, 0): + err_msg = "" # Add ioapic and iommu device in xml for q35 VM if check.startswith('ioapic_iommu'): logging.info('Modify features') diff --git a/libvirt/tests/src/cpu/multi_vms_with_stress.py b/libvirt/tests/src/cpu/multi_vms_with_stress.py new file mode 100644 index 00000000000..fec03d42e7c --- /dev/null +++ b/libvirt/tests/src/cpu/multi_vms_with_stress.py @@ -0,0 +1,82 @@ +import logging as log + +from avocado.utils import cpu + +from virttest import utils_test +from virttest.libvirt_xml import vm_xml + +LOG = log.getLogger('avocado.' + __name__) + + +def run(test, params, env): + """ + Test that multiple vms can start when stress workload is running on the host. + + Steps: + 1. Prepare 3 vms that each have even vcpu number around 2/3 of # host_online_cpu + 2. Start stress workload on the host + 3. Start all vms and verify vms could be logged in normally + 4. Verify all vms could be gracefully shutdown successfully + """ + memory = params.get("memory", "4194304") + main_vm_name = params.get("main_vm") + main_vm = env.get_vm(main_vm_name) + vm_names = params.get("vm_names").split() + vms = [main_vm] + vmxml_backups = [] + + # Get vms + for i, vm_name in enumerate(vm_names): + vms.append(main_vm.clone(vm_name)) + + for vm in vms: + # Back up domain XMLs + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm.name) + vmxml_backups.append(vmxml.copy()) + # Increase memory + vmxml.memory = int(memory) + vmxml.current_mem = int(memory) + vmxml.sync() + + try: + # Get host online cpu number + host_online_cpus = cpu.online_count() + LOG.debug("Host online CPU number: %s", str(host_online_cpus)) + + # Prepare 3 vms and each vm has even vcpus number which is about 2/3 of # host_online_cpu + for i, vm in enumerate(vms): + if vm.is_alive(): + vm.destroy() + vcpus_num = host_online_cpus * 2 // int(len(vms)) + if (vcpus_num % 2 != 0): + vcpus_num += 1 + vm_xml.VMXML.new_from_inactive_dumpxml(vm.name).set_vm_vcpus(vm.name, vcpus_num, vcpus_num, topology_correction=True) + LOG.debug("Defined vm %s with '%s' vcpu(s)", vm.name, str(vcpus_num)) + + # Start stress workload on the host + # params must include stress_args + utils_test.load_stress("stress_on_host", params=params) + + # Start all vms and verify vms could be logged in normally + for vm in vms: + vm.prepare_guest_agent() + vm.wait_for_login() + if (vm.state() != "running"): + test.fail("VM %s should be running, not %s" % (vm.name, vm.state())) + + # Verify all vms could be gracefully shutdown successfully + for vm in vms: + vm.shutdown() + if (vm.state() != "shut off"): + test.fail("VM %s should be shut off, not %s" % (vm.name, vm.state())) + + finally: + # Stop stress workload + utils_test.unload_stress("stress_on_host", params=params) + + # Recover VMs + for i, vm in enumerate(vms): + if vm.is_alive(): + vm.destroy(gracefully=False) + LOG.info("Restoring vm %s...", vm.name) + vmxml_backups[i].sync() diff --git a/libvirt/tests/src/cpu/topology.py b/libvirt/tests/src/cpu/topology.py new file mode 100644 index 00000000000..3af517fefe2 --- /dev/null +++ b/libvirt/tests/src/cpu/topology.py @@ -0,0 +1,57 @@ +import logging +import re +import time + +from virttest import virsh +from virttest.libvirt_xml import VMXML + +LOG = logging.getLogger('avocado.' + __name__) + + +def get_cpus(session): + """ + Retrieves the CPU extended info + + :param session: VM session + """ + output = session.cmd_output("lscpu --extended") + LOG.debug("VM cpus:\n%s", output) + return [x for x in output.split("\n") if re.match(r"^\s+\d\s", x)] + + +def run(test, params, env): + """ + Confirm hotplugged VPCU is available and placed in topology. + + :param test: QEMU test object + :param params: Dictionary with the test parameters + :param env: Dictionary with test environment. + """ + + vm_name = params.get("main_vm") + max_vcpus = int(params.get("max_vcpus")) + current_vcpus = int(params.get("current_vcpus")) + cores = int(params.get("cores")) + threads = int(params.get("threads")) + sockets = int(params.get("sockets")) + vm = env.get_vm(vm_name) + vmxml = VMXML.new_from_inactive_dumpxml(vm_name) + orig_xml = vmxml.copy() + hotplug = current_vcpus != max_vcpus + + try: + VMXML.set_vm_vcpus(vm_name, max_vcpus, current_vcpus, + sockets, cores, threads, add_topology=True) + vm.start() + with vm.wait_for_login() as session: + cpus = get_cpus(session) + if current_vcpus != len(cpus): + test.fail("Unexpected number of cpus in guest: %s" % len(cpus)) + if hotplug: + virsh.setvcpus(vm_name, max_vcpus) + time.sleep(5) + cpus = get_cpus(session) + if max_vcpus != len(cpus): + test.fail("Unexpected number of cpus in guest: %s" % len(cpus)) + finally: + orig_xml.sync() diff --git a/libvirt/tests/src/cpu/vcpu_affinity.py b/libvirt/tests/src/cpu/vcpu_affinity.py index ce421beff11..25116fb4839 100644 --- a/libvirt/tests/src/cpu/vcpu_affinity.py +++ b/libvirt/tests/src/cpu/vcpu_affinity.py @@ -10,10 +10,13 @@ from virttest import utils_libvirtd from virttest import libvirt_cgroup +from provider.cpu import patch_total_cpu_count_s390x + # Using as lower capital is not the best way to do, but this is just a # workaround to avoid changing the entire file. logging = log.getLogger('avocado.' + __name__) +patch_total_cpu_count_s390x(cpuutil) def check_vcpu_placement(test, params): diff --git a/libvirt/tests/src/cpu/vcpu_feature.py b/libvirt/tests/src/cpu/vcpu_feature.py index 709f939f643..2577e31f8d6 100644 --- a/libvirt/tests/src/cpu/vcpu_feature.py +++ b/libvirt/tests/src/cpu/vcpu_feature.py @@ -49,6 +49,7 @@ def update_cpu_xml(): cpu_mode = params.get('cpu_mode', "host-passthrough") cpu_check = params.get('cpu_check', "full") feature_name = params.get('feature_name', "vmx") + feature_check_name = params.get('feature_check_name', feature_name) feature_policy = params.get('feature_policy', "require") host_supported_feature = "yes" == params.get("host_supported_feature", "no") check_vm_feature = "yes" == params.get("check_vm_feature", "no") @@ -58,10 +59,9 @@ def update_cpu_xml(): bkxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) try: - if not libvirt_version.version_compare(6, 0, 0): - test.cancel("Libvirt version is too low for this test.") + libvirt_version.is_libvirt_feature_supported(params) - flags_cmd = "grep -q %s /proc/cpuinfo" % feature_name + flags_cmd = "grep -qw %s /proc/cpuinfo" % feature_check_name res = process.run(flags_cmd, shell=True, ignore_status=True).exit_status if host_supported_feature == bool(res): test.cancel('The host does not support current test!') @@ -75,14 +75,20 @@ def update_cpu_xml(): if err_msg: libvirt.check_result(result, err_msg) + vm_session = None if not status_error and check_vm_feature: vm_session = vm.wait_for_login() res = vm_session.cmd_status(flags_cmd) # TODO: Add checks for other feature policies if feature_policy == "disable": if not res: - test.fail("The vm unexpectedly contains %s flag" - % feature_name) + test.fail("The vm unexpectedly contains %s flag" % feature_name) + + check_qemu_pattern = params.get('check_qemu_pattern', "") + # we don't expect for now negative cases for the check_qemu_pattern + if check_qemu_pattern: + logging.debug(f"TEST_STEP: checking pattern in qemu-kvm command line:{check_qemu_pattern}.") + libvirt.check_qemu_cmd_line(check_qemu_pattern) finally: if vm.is_alive(): diff --git a/libvirt/tests/src/cpu/vcpu_max_topology.py b/libvirt/tests/src/cpu/vcpu_max_topology.py new file mode 100644 index 00000000000..2614f1dee6d --- /dev/null +++ b/libvirt/tests/src/cpu/vcpu_max_topology.py @@ -0,0 +1,185 @@ +import logging as log + +from avocado.utils import cpu + +from virttest import cpu as cpuutil +from virttest.libvirt_xml import vm_xml + + +LOG = log.getLogger('avocado.' + __name__) + + +def run(test, params, env): + """ + Test that the vm can start with vcpus which is equal to host online cpu number + and vm topology is consistent to those configured. + + Steps: + 1. Configure the vm topology with specified number of sockets, cores, and clusters + 2. Start configured vm with guest agent + 3. Check that the vm setup is consistent with the topology configured + 3a. Check the lscpu output + 3b. Check the kernel file for core id for each vcpu + 3c. Check the vcpu cluster number + 3d. Check the cluster cpu list + """ + vm_name = params.get("main_vm") + vm = env.get_vm(vm_name) + memory = params.get("memory", "4194304") + vcpus_placement = params.get("vcpus_placement", "static") + sockets_param = params.get("sockets", "") + cores_param = params.get("cores", "") + clusters_param = params.get("clusters", "") + + vcpus_num = 0 + sockets_list = [] + cores_list = [] + clusters_list = [] + + # Back up domain XML + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + vmxml_backup = vmxml.copy() + + try: + # Modify vm + if vm.is_alive(): + vm.destroy() + vmxml.placement = vcpus_placement + vmxml.memory = int(memory) + vmxml.current_mem = int(memory) + vmxml.sync() + + # Set vcpus_num to the host online cpu number + vcpus_num = cpu.online_count() + LOG.debug("Host online CPU number: %s", str(vcpus_num)) + + # Setting number of sockets, cores, and clusters + # one_socket case + # cores = vcpus_num // number of clusters + if sockets_param == "one": + sockets_list = [1] + + # many_clusters case + if clusters_param == "many": + # Ensure that vcpus_num is evenly divisible by the number of clusters + clusters_list = [clusters for clusters in [2, 4, 6] if vcpus_num % clusters == 0] + cores_list = [vcpus_num // clusters for clusters in clusters_list] + # default_clusters case + else: + cores_list = [vcpus_num] + + # one_core_per_socket case + elif sockets_param == "many" and cores_param == "one": + sockets_list = [vcpus_num] + cores_list = [1] + + # many_cores_per_socket + # Ensure that vcpus_num is evenly divisible by the number of cores + else: + # many_clusters case + # sockets = vcpus_num // number of cores // number of clusters + if clusters_param == "many": + # defaulting to either 2 or 3 cores + cores = 2 if vcpus_num % 2 == 0 else 3 + clusters_list = [clusters for clusters in [2, 4, 6] if (vcpus_num / cores) % clusters == 0] + cores_list = [cores] * (len(clusters_list)) + sockets_list = [(vcpus_num // cores) // clusters for clusters in clusters_list] + # default_clusters case + # sockets * cores = vcpus_num + else: + cores_list = [cores for cores in [2, 4, 6] if vcpus_num % cores == 0] + sockets_list = [vcpus_num // cores for cores in cores_list] + + if not sockets_list or not cores_list: + test.error("The number of sockets or cores is not valid") + elif (len(cores_list) == 1): + # len(sockets_list) will also be 1 + set_and_check_topology(test, vm, vcpus_num, sockets_list[0], cores_list[0]) + else: + for i, cores in enumerate(cores_list): + if (cores == 0): + continue + if (len(sockets_list) == 1): + if clusters_list: + set_and_check_topology(test, vm, vcpus_num, sockets_list[0], cores, clusters_list[i]) + else: + set_and_check_topology(test, vm, vcpus_num, sockets_list[0], cores) + else: + if (sockets_list[i] == 0): + continue + if clusters_list: + set_and_check_topology(test, vm, vcpus_num, sockets_list[i], cores, clusters_list[i]) + else: + set_and_check_topology(test, vm, vcpus_num, sockets_list[i], cores) + + finally: + # Recover VM + if vm.is_alive(): + vm.destroy(gracefully=False) + LOG.info("Restoring vm...") + vmxml_backup.sync() + + +def set_and_check_topology(test, vm, vcpus_num, sockets, cores, clusters=1): + ''' + Perform steps 2-3 for each vm topology configuration + + :param test: test object + :param vm: defined vm + :param vcpus_num: number of vcpus to set + :param sockets: number of sockets to set + :param cores: number of cores to set + :param clusters: number of clusters to set, default 1 + ''' + vm_xml.VMXML.new_from_dumpxml(vm.name).set_vm_vcpus( + vm.name, + vcpus_num, + sockets=sockets, + cores=cores, + threads=1, + clusters=clusters, + add_topology=True + ) + LOG.debug("Defined guest with '%s' vcpu(s), '%s' socket(s), and '%s' core(s), and '%s' cluster(s)", + str(vcpus_num), str(sockets), str(cores), str(clusters)) + + # Start guest agent in vm and wait for login + vm.prepare_guest_agent() + session = vm.wait_for_login() + + # Check kernel file for core id for each vcpu in the vm + for vcpu in range(vcpus_num): + cmd_coreid = f'cat /sys/devices/system/cpu/cpu{vcpu}/topology/core_id' + ret_coreid = session.cmd_output(cmd_coreid).strip() + if (str(vcpu) != ret_coreid): + test.fail("In the vm kernel file, the core id for vcpu %s should not be %s" % (vcpu, ret_coreid)) + + # Check vcpu cluster number + cmd_clusterid = 'cat /sys/devices/system/cpu/cpu*/topology/cluster_id | sort | uniq -c | wc -l' + ret_clusterid = session.cmd_output(cmd_clusterid).strip() + # The result should be equal to sockets * clusters + if (str(sockets * clusters) != ret_clusterid): + test.fail("In the vm kernel file, the vcpu cluster number should be %s, not %s" % (str(sockets * clusters), ret_clusterid)) + + # Check cluster cpu list + cmd_cluster_cpu_list = 'cat /sys/devices/system/cpu/cpu*/topology/cluster_cpus_list | sort | uniq -c | wc -l' + ret_cluster_cpu_list = session.cmd_output(cmd_cluster_cpu_list).strip() + # The result should be equal to sockets * clusters + if (str(sockets * clusters) != ret_cluster_cpu_list): + test.fail("In the vm kernel file, the cluster cpu list should be %s, not %s" % (str(sockets * clusters), ret_cluster_cpu_list)) + + # Check lscpu output within the vm is consistent with the topology configured + lscpu_output = cpuutil.get_cpu_info(session) + # get_cpu_info() should close the session + session.close() + lscpu_check_fail = "The configured topology is not consistent with the lscpu output within the vm for " + if (str(vcpus_num) != lscpu_output["CPU(s)"]): + test.fail(lscpu_check_fail + "CPU(s)") + elif (('0' + '-' + str(vcpus_num - 1)) != lscpu_output["On-line CPU(s) list"]): + test.fail(lscpu_check_fail + "on-line CPU(s) list") + elif ("1" != lscpu_output["Thread(s) per core"]): + test.fail(lscpu_check_fail + "thread(s) per core") + elif (str(sockets) != lscpu_output["Socket(s)"]): + test.fail(lscpu_check_fail + "socket(s)") + elif (str(cores * clusters) != lscpu_output["Core(s) per socket"]): + test.fail(lscpu_check_fail + "core(s) per socket") diff --git a/libvirt/tests/src/cpu/vcpu_metrics.py b/libvirt/tests/src/cpu/vcpu_metrics.py index 3c18b9c4855..a538ada69ba 100644 --- a/libvirt/tests/src/cpu/vcpu_metrics.py +++ b/libvirt/tests/src/cpu/vcpu_metrics.py @@ -16,6 +16,7 @@ import re import shutil import stat +import platform from avocado.utils import process @@ -23,6 +24,7 @@ from virttest import virsh from virttest.libvirt_xml import vm_xml +from virttest.libvirt_xml.xcepts import LibvirtXMLNotFoundError from virttest.utils_libvirt import libvirt_bios from virttest.utils_libvirt import libvirt_vmxml @@ -129,12 +131,25 @@ def setup_with_unprivileged_user(vm, params, test): test.log.debug("Remove 'dac' security driver for unprivileged user") vmxml.del_seclabel(by_attr=[('model', 'dac')]) libvirt_vmxml.modify_vm_device(vmxml, 'interface', interface_attrs) + vmxml.xmltreefile.remove_by_xpath("/devices/interface/driver", True) boot_disk = vmxml.devices.by_device_tag('disk')[0] first_disk_source = boot_disk.fetch_attrs()['source']['attrs']['file'] unprivileged_boot_disk_path = os.path.join(unprivileged_boot_disk_path, os.path.basename(first_disk_source)) disk_attrs = {'source': {'attrs': {'file': unprivileged_boot_disk_path}}} libvirt_vmxml.modify_vm_device(vmxml, 'disk', disk_attrs) + try: + os_attrs = { + "loader": vmxml.os.loader, + "loader_readonly": vmxml.os.loader_readonly, + "loader_type": vmxml.os.loader_type + } + except LibvirtXMLNotFoundError: + pass vmxml.os = libvirt_bios.remove_bootconfig_items_from_vmos(vmxml.os) + if vmxml.xmltreefile.find('features'): + arch = platform.machine().lower() + if vmxml.features.has_feature('acpi') and 'aarch64' in arch: + vmxml.set_os_attrs(**os_attrs) test.log.debug('VM XML after updating:\n%s', vmxml) test.log.debug("Step: Prepare boot disk image in unprivileged user's home directory") diff --git a/libvirt/tests/src/cpu/vcpu_misc.py b/libvirt/tests/src/cpu/vcpu_misc.py index 1264ab79a7a..616a493f551 100644 --- a/libvirt/tests/src/cpu/vcpu_misc.py +++ b/libvirt/tests/src/cpu/vcpu_misc.py @@ -189,20 +189,24 @@ def run(test, params, env): :param params: Dictionary with the test parameters :param env: Dictionary with test environment. """ - def do_snapshot(vm_name, expected_str): + def do_snapshot(vm_name, expected_str, params): """ Run snapshot related commands: snapshot-create-as, snapshot-list snapshot-dumpxml, snapshot-revert :param vm_name: vm name :param expected_str: expected string in snapshot-dumpxml + :param params: dict, test parameters :raise: test.fail if virsh command failed """ snapshot_name = vm_name + "-snap" + snapshot_options = params.get("snapshot_options") virsh_dargs = {'debug': True} - cmd_result = virsh.snapshot_create_as(vm_name, snapshot_name, - **virsh_dargs) + vm.start() + vm.wait_for_login().close() + cmd_result = virsh.snapshot_create_as( + vm_name, snapshot_options.format(snapshot_name), **virsh_dargs) libvirt.check_exit_status(cmd_result) try: @@ -219,6 +223,7 @@ def do_snapshot(vm_name, expected_str): cmd_result = virsh.snapshot_revert(vm_name, "", "--current", **virsh_dargs) libvirt.check_exit_status(cmd_result) + vm.destroy() libvirt_version.is_libvirt_feature_supported(params) vm_name = params.get('main_vm') @@ -238,6 +243,7 @@ def do_snapshot(vm_name, expected_str): bkxml = vmxml.copy() managed_save_file = "/var/lib/libvirt/qemu/save/%s.save" % vm_name maxphysaddr = params.get('maxphysaddr') + mem_file = params.get('mem_file', "") try: if check_vendor_id: @@ -269,8 +275,7 @@ def do_snapshot(vm_name, expected_str): if test_operations: for action in test_operations.split(","): if action == "do_snapshot": - do_snapshot(vm_name, expected_str_before_startup) - + do_snapshot(vm_name, expected_str_before_startup, params) if virsh_edit_cmd: status = libvirt.exec_virsh_edit(vm_name, virsh_edit_cmd.split(",")) if status == status_error: @@ -310,6 +315,8 @@ def do_snapshot(vm_name, expected_str): logging.debug("Recover test environment") if os.path.exists(managed_save_file): virsh.managedsave_remove(vm_name, debug=True) + if os.path.exists(mem_file): + os.remove(mem_file) if vm.is_alive(): vm.destroy() libvirt.clean_up_snapshots(vm_name, domxml=bkxml) diff --git a/libvirt/tests/src/cpu/vcpu_nested.py b/libvirt/tests/src/cpu/vcpu_nested.py index 6c732d59956..caa416ca8ce 100644 --- a/libvirt/tests/src/cpu/vcpu_nested.py +++ b/libvirt/tests/src/cpu/vcpu_nested.py @@ -109,6 +109,7 @@ def test_check_nested_capability(): Check whether the feature nested virt is enabled """ vm.wait_for_login() + vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) cpu_feature = vmxml.cpu.get_dict_type_feature() if cpu_feature['vmx'] != 'require': test.fail("The feature policy of 'vmx' should not be %s, but require." % cpu_feature['vmx']) diff --git a/libvirt/tests/src/cpu/vcpupin.py b/libvirt/tests/src/cpu/vcpupin.py index 642c1e3751e..ef6d2aaecad 100644 --- a/libvirt/tests/src/cpu/vcpupin.py +++ b/libvirt/tests/src/cpu/vcpupin.py @@ -3,6 +3,7 @@ import re from avocado.utils import cpu as cpuutils +from avocado.utils import process from virttest import data_dir from virttest import utils_misc @@ -365,6 +366,65 @@ def test_vcpupin_current_inactive_vm(test, vm, cpu_max_id, params): check_vcpuinfo_affinity(test, affinity, vcpupin_new_values) +def test_cpuset_limilted_in_cgroup(test, vm, cpu_max_id, params): + """ + Test Start VM with vcpupin config when machine cpuset is limited in cgroup + + :param test: test object + :param vm: vm object + :param cpu_max_id: maximum id of host cpu id + :param params: test parameters + """ + vm_attrs = eval(params.get('vm_attrs', '{}')) + rand_id = utils_misc.generate_random_string(3) + tmp_vm_name = 'test-vcpupin-' + rand_id + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm.name) + + config_path = '/sys/fs/cgroup/machine.slice/cpuset.cpus' + + bk_cpu_set = process.run( + f'cat {config_path}', shell=True, ignore_status=True).stdout_text + try: + process.run(f'echo "0,2,4,6,8" > {config_path}', shell=True) + process.run(f'cat {config_path}', shell=True) + + vm.destroy() + + # Create a new vm with vcpupin config + tmp_vmxml = vmxml.copy() + tmp_vmxml.setup_attrs(**vm_attrs) + tmp_vmxml.vm_name = tmp_vm_name + tmp_vmxml.del_uuid() + osxml = tmp_vmxml.os + os_attrs = osxml.fetch_attrs() + for k, v in list(os_attrs.items()): + if k.startswith('nvram'): + os_attrs.pop(k) + new_os = vm_xml.VMOSXML() + new_os.setup_attrs(**os_attrs) + tmp_vmxml.os = new_os + + tmp_vmxml.xmltreefile.write() + logging.debug(tmp_vmxml) + + virsh.create(tmp_vmxml.xml, debug=True, ignore_status=False) + logging.debug(virsh.dumpxml(tmp_vm_name).stdout_text) + + out = virsh.vcpupin(tmp_vm_name, debug=True, + ignore_status=False).stdout_text + out_dict = libvirt_misc.convert_to_dict(out) + vcpupin_conf = eval(params.get('vcpupin_conf')) + if out_dict != vcpupin_conf: + test.fail( + f'vcpupin output is not expected, should be {vcpupin_conf}') + + finally: + virsh.destroy(tmp_vm_name, debug=True) + if not vm.is_alive(): + vm.start() + process.run(f'echo {bk_cpu_set} > {config_path}', shell=True) + + def run(test, params, env): """ Run some tests for vcpupin with --live, --config @@ -373,6 +433,7 @@ def run(test, params, env): run_test = eval("test_%s" % test_case) vm_name = params.get("main_vm", "avocado-vt-vm1") vm = env.get_vm(vm_name) + update_xml = 'yes' == params.get("update_xml", "no") # Backup for recovery. vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) @@ -381,7 +442,8 @@ def run(test, params, env): try: if vm.is_alive(): vm.destroy() - update_vm_xml(vmxml, params) + if update_xml: + update_vm_xml(vmxml, params) vm.start() logging.debug(vm_xml.VMXML.new_from_dumpxml(vm_name)) # Get the host cpu max id diff --git a/libvirt/tests/src/virsh_cmd/domain/virsh_cpu_compare_xml.py b/libvirt/tests/src/cpu/virsh_cpu_compare_xml.py similarity index 74% rename from libvirt/tests/src/virsh_cmd/domain/virsh_cpu_compare_xml.py rename to libvirt/tests/src/cpu/virsh_cpu_compare_xml.py index 50a60077c2b..ce9501d5212 100644 --- a/libvirt/tests/src/virsh_cmd/domain/virsh_cpu_compare_xml.py +++ b/libvirt/tests/src/cpu/virsh_cpu_compare_xml.py @@ -1,6 +1,8 @@ import os import logging as log +from avocado.utils import cpu + from virttest import virsh from virttest import libvirt_version from virttest.libvirt_xml import vm_xml @@ -66,11 +68,48 @@ def get_domcapa_xml(extract=False): return domcapa_xml -def get_capa_xml(operate='', extract=False): +def get_different_cpu_vendor(test, current_cpu_vendor): + """ + Get a different cpu vendor from current host cpu vendor + + :param test: test object + :param current_cpu_vendor: str, current host cpu vendor + :return: str, the selected cpu vendor + """ + arch_cpu_vendor_mapping = {'x86_64': ['GenuineIntel', 'AuthenticAMD'], + 'aarch64': ['Ampere(R)', 'Ampere(TM)', + 'AppliedMicro', 'ARM', 'NVIDIA', + 'FUJITSU', 'Cavium Inc.', + 'Marvell', 'Qualcomm', + 'CN8890-2000BG2601-AAP-PR-Y-G', + 'CN8880-1800BG2601-CP-Y-G']} + + host_arch = cpu.get_arch() + if host_arch.lower() not in arch_cpu_vendor_mapping: + test.error("The host arch '%s' is not supported for this case" % host_arch) + cpu_vendors = arch_cpu_vendor_mapping[host_arch] + new_vendor = '' + for vendor_index in range(0, len(cpu_vendors)): + if cpu_vendors[vendor_index].count(current_cpu_vendor): + if vendor_index == len(cpu_vendors) - 1: + new_vendor = cpu_vendors[0] + else: + new_vendor = cpu_vendors[vendor_index + 1] + break + if new_vendor: + test.log.debug("Found a different cpu vendor '%s'", new_vendor) + return new_vendor + else: + test.error("Can not find a different one from " + "current cpu vendor '%s'" % current_cpu_vendor) + + +def get_capa_xml(test, operate='', extract=False): """ Get full capabilities xml or the cpu definition from capabilities xml + :param test: test object :param operate: Operation mode, decide file's detail :param extract: Setting True means to extract cpu definition from capabilities xml @@ -79,6 +118,9 @@ def get_capa_xml(operate='', extract=False): capa_xml = capability_xml.CapabilityXML() if operate == 'delete': capa_xml.remove_feature(num=-1) + elif operate == 'modify': + new_vendor = get_different_cpu_vendor(test, capa_xml.vendor) + capa_xml.vendor = new_vendor if extract: capa_xml.xmltreefile = capa_xml.xmltreefile.reroot('/host/cpu') return capa_xml @@ -138,7 +180,7 @@ def run(test, params, env): cpu_compare_xml = get_domcapa_xml(is_extracted) if file_type == "capa_xml": - cpu_compare_xml = get_capa_xml(cpu_compare_mode, is_extracted) + cpu_compare_xml = get_capa_xml(test, cpu_compare_mode, is_extracted) if cpu_compare_mode == "invalid_test": cpu_compare_xml = get_invalid_xml(cpu_compare_xml) diff --git a/libvirt/tests/src/cpu/vm_features.py b/libvirt/tests/src/cpu/vm_features.py index 0f45c97fed9..0821847aafc 100644 --- a/libvirt/tests/src/cpu/vm_features.py +++ b/libvirt/tests/src/cpu/vm_features.py @@ -11,6 +11,7 @@ from virttest.libvirt_xml import domcapability_xml from virttest.libvirt_xml import vm_xml from virttest.utils_test import libvirt +from virttest.utils_libvirt import libvirt_vmxml from virttest.libvirt_xml import xcepts # Using as lower capital is not the best way to do, but this is just a @@ -77,7 +78,7 @@ def get_hyperv_features_in_domcapabilities(): def update_hyperv_features(vmxml, hyperv_attr, test): """ Update specified hyperv features in vmxml - Sample hyperv_attr: {'relaxed': {'state': 'on'}, 'spinlocks': {'state': 'on', 'retries': '4096'}} + Sample hyperv_attr: {'relaxed': {'state': 'on'}, 'spinlocks': {'state': 'on', 'retries': '4096'}} :param vmxml: VMXML instance :param hyperv_attr: dict, hyperv features and attributes @@ -145,6 +146,22 @@ def assemble_hyperv_feature_list(feature_list, params, test): return hyperv_attr +def get_expected_hyperv_values_in_qemu_line(feature_name): + """ + Get expected hyperv feature values in qemu command line + + :param feature_name: str, the hyperv feature name + :return: str, expected qemu command line for given feature + """ + feature_name_value_mapping = {'hv-spinlocks': 'hv-spinlocks=0x1000', + 'hv-stimer': 'hv-stimer=on,hv-stimer-direct=on', + 'hv-vendor-id': 'hv-vendor-id=KVM Hv'} + if feature_name in feature_name_value_mapping: + return feature_name_value_mapping[feature_name] + else: + return "%s=on" % feature_name + + def run(test, params, env): """ Test vm features @@ -164,6 +181,7 @@ def run(test, params, env): pkgs = params.get('pkgs') features_from_domcap = params.get('features_from_domcap') status_error = params.get('status_error') == 'yes' + check_xml = params.get('check_xml') == 'yes' vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) bkxml = vmxml.copy() @@ -190,6 +208,9 @@ def run(test, params, env): try: ret = virsh.start(vm_name, debug=True) libvirt.check_exit_status(ret, status_error) + if check_xml: + vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) + libvirt_vmxml.check_guest_xml_by_xpaths(vmxml, eval(params.get("expected_xpaths"))) except exceptions.TestFail as details: if re.search(r"host doesn\'t support paravirtual spinlocks", str(details)): @@ -198,19 +219,27 @@ def run(test, params, env): test.fail('VM failed to start:\n%s' % details) vm_session = vm.wait_for_login() - if hyperv_attr and not features_from_domcap: + if hyperv_attr and features_from_domcap == 'in': # Check hyperv settings in qemu command line + expect_exist_list = [] + expect_nonexist_list = [] for attr in hyperv_attr: + new_attr = re.sub('_', '-', attr) if libvirt_version.version_compare(5, 6, 0): - exp_str = 'hv-' + attr + exp_str = 'hv-' + new_attr else: - exp_str = 'hv_' + attr + exp_str = 'hv_' + new_attr if hyperv_attr[attr] == 'off': - if libvirt.check_qemu_cmd_line(exp_str, True): - test.fail("Unexpected '%s' was found in " - "qemu command line" % exp_str) + expect_nonexist_list.append(exp_str) else: - libvirt.check_qemu_cmd_line(exp_str) + exp_str = get_expected_hyperv_values_in_qemu_line(exp_str) + expect_exist_list.append(exp_str) + if expect_nonexist_list: + test.log.debug("Not expected list:%s", expect_nonexist_list) + libvirt.check_qemu_cmd_line(expect_nonexist_list, expect_exist=False) + if expect_exist_list: + test.log.debug("Expected list:%s", expect_exist_list) + libvirt.check_qemu_cmd_line(expect_exist_list) if pmu_attr: libvirt.check_qemu_cmd_line('pmu=' + pmu_attr['pmu']) diff --git a/libvirt/tests/src/daemon/check_daemon_after_remove_pkgs.py b/libvirt/tests/src/daemon/check_daemon_after_remove_pkgs.py index 67f19df1f78..29bdefcd522 100644 --- a/libvirt/tests/src/daemon/check_daemon_after_remove_pkgs.py +++ b/libvirt/tests/src/daemon/check_daemon_after_remove_pkgs.py @@ -46,8 +46,9 @@ def run(test, params, env): test.error("Failed to remove libvirt packages on guest") for daemon in daemons: - cmd = "systemctl -a | grep %s | grep -v not-found" % daemon - if not session.cmd_status(cmd): + _, out = session.cmd_status_output("systemctl list-units| grep %s" % daemon) + LOGGER.debug(out) + if daemon in out and "not-found" not in out: test.fail("%s still exists after removing libvirt pkgs" % daemon) finally: diff --git a/libvirt/tests/src/daemon/check_socket_files_with_services.py b/libvirt/tests/src/daemon/check_socket_files_with_services.py new file mode 100644 index 00000000000..e3bc3837e30 --- /dev/null +++ b/libvirt/tests/src/daemon/check_socket_files_with_services.py @@ -0,0 +1,58 @@ +import logging +import os + +from virttest.staging import service + +LOG = logging.getLogger('avocado.' + __name__) + + +def run(test, params, env): + """ + Check the socket files are cleaned or created after stop/start + daemons' service. + """ + daemon_list = eval(params.get('service_list')) + other_socket_files = eval(params.get('other_socket_files')) + + try: + daemon_srv_list = [] + daemon_list = [f'virt{sub_daemon}d' for sub_daemon in daemon_list] + for daemon in daemon_list: + daemon_srv = service.Factory.create_service(daemon) + daemon_srv_list.append(daemon_srv) + daemon_srv.start() + + all_sock_files = os.listdir('/var/run/libvirt') + + daemons = daemon_list.copy() + daemons.remove('virtqemud') + daemons.remove('virtproxyd') + daemons.append('libvirt') + expect_s_files = [[f'{x}-admin-sock', + f'{x}-sock', + f'{x}-sock-ro'] for x in daemons] + expect_s_files = [x for y in expect_s_files for x in y] + expect_s_files.extend(other_socket_files) + LOG.debug(f'Expect socket files:\n{expect_s_files}') + diff = set(expect_s_files).difference(set(all_sock_files)) + if diff: + test.fail(f'Not found expected socket files: {diff}') + + for daemon in daemon_list: + daemon_sock_srv = service.Factory.create_service( + daemon + '.socket') + daemon_sock_srv.stop() + + all_sock_files = os.listdir('/var/run/libvirt') + LOG.debug(f'All files in /var/run/libvirt\n{all_sock_files}') + left_s_files = set(expect_s_files).intersection(set(all_sock_files)) + LOG.debug(f'Socket files left: {left_s_files}') + unexpect = left_s_files.difference(set(other_socket_files)) + if unexpect: + test.fail(f'Found unexpected socket files left: {unexpect}') + + finally: + for daemon in daemon_list: + daemon_sock_srv = service.Factory.create_service( + daemon + '.socket') + daemon_sock_srv.start() diff --git a/libvirt/tests/src/daemon/check_users.py b/libvirt/tests/src/daemon/check_users.py new file mode 100644 index 00000000000..010046eed84 --- /dev/null +++ b/libvirt/tests/src/daemon/check_users.py @@ -0,0 +1,29 @@ +import logging +import re +import ast + +from avocado.utils import process + +from virttest import libvirt_version + + +LOGGER = logging.getLogger('avocado.' + __name__) + + +def run(test, params, env): + """ + Check libvirt/qemu/kvm user/group are created via sysuser.d + """ + libvirt_version.is_libvirt_feature_supported(params) + users_list = ast.literal_eval(params.get("users_list", "[]")) + + users_match_list = [] + + sysuser_dir = '/usr/lib/sysusers.d/' + cmd = "grep -hr -E 'kvm|qemu|libvirt' %s" % sysuser_dir + output = process.getoutput(cmd, shell=True) + LOGGER.debug(output) + + for user in users_list: + if not re.search(user, output): + test.fail("%s not created by sysuser.d" % user) diff --git a/libvirt/tests/src/daemon/check_virsh_connection_switch_between_monolithic_and_modular.py b/libvirt/tests/src/daemon/check_virsh_connection_switch_between_monolithic_and_modular.py new file mode 100644 index 00000000000..3cebe243b3c --- /dev/null +++ b/libvirt/tests/src/daemon/check_virsh_connection_switch_between_monolithic_and_modular.py @@ -0,0 +1,33 @@ +import logging + +from virttest.staging import service + +from provider.libvirtd import libvirtd_base + +VIRSH_ARGS = {'ignore_status': False, 'debug': True} + +LOG = logging.getLogger('avocado.' + __name__) + + +def run(test, params, env): + """ + Verify virsh connection can work well after switching between the legacy + monolithic daemon and the modular daemon + """ + try: + libvirtd_srv = service.Factory.create_service('libvirtd') + virtqemud_srv = service.Factory.create_service('virtqemud') + libvirtd_base.check_virsh_connection('before test') + libvirtd_base.check_service_status('virtqemud', True) + libvirtd_srv.start() + libvirtd_base.check_service_status('libvirtd', True) + libvirtd_base.check_service_status('virtqemud', False) + libvirtd_base.check_virsh_connection( + 'after switch to legacy monolithic daemon mode') + virtqemud_srv.start() + libvirtd_base.check_service_status('libvirtd', False) + libvirtd_base.check_service_status('virtqemud', True) + libvirtd_base.check_virsh_connection( + 'after switch back to modular daemon mode') + finally: + virtqemud_srv.start() diff --git a/libvirt/tests/src/daemon/conf_file/libvirtd_conf/check_negative_parameter.py b/libvirt/tests/src/daemon/conf_file/libvirtd_conf/check_negative_parameter.py new file mode 100644 index 00000000000..7f59e457475 --- /dev/null +++ b/libvirt/tests/src/daemon/conf_file/libvirtd_conf/check_negative_parameter.py @@ -0,0 +1,49 @@ +import logging +import time + +from avocado.utils import process + +from virttest import utils_config +from virttest import utils_libvirtd +from virttest import utils_split_daemons + +from virttest.utils_test import libvirt + +LOG = logging.getLogger('avocado.' + __name__) + + +def run(test, params, env): + """ + Test libvirt should disallow negative value for options needed positive + integer etc in libvirtd.conf. + + """ + check_string_in_log = params.get("check_string_in_log") + daemon_name = params.get("daemon_name") + parameter_name = params.get("parameter_name") + parameter_value = params.get("parameter_value") + log_file = params.get("log_file") + require_modular_daemon = params.get('require_modular_daemon', "no") == "yes" + vm_name = params.get("main_vm", "avocado-vt-vm1") + vm = env.get_vm(vm_name) + + utils_split_daemons.daemon_mode_check(require_modular_daemon) + daemon = utils_libvirtd.Libvirtd(daemon_name) + daemon_conf = utils_config.get_conf_obj(daemon_name) + + try: + cmd = "echo ' ' > %s" % log_file + process.run(cmd, shell=True) + + daemon_conf[parameter_name] = parameter_value + if not daemon.restart(wait_for_start=False): + LOG.info("%s restart failed as expected.", daemon_name) + else: + test.fail("Expect %s restart failed, but successfully." % daemon_name) + + time.sleep(1) + libvirt.check_logfile(check_string_in_log, log_file, str_in_log=True) + + finally: + daemon_conf.restore() + daemon.restart() diff --git a/libvirt/tests/src/daemon/conf_file/libvirtd_conf/set_audit_logging.py b/libvirt/tests/src/daemon/conf_file/libvirtd_conf/set_audit_logging.py index f2d45800830..0add0138d9d 100644 --- a/libvirt/tests/src/daemon/conf_file/libvirtd_conf/set_audit_logging.py +++ b/libvirt/tests/src/daemon/conf_file/libvirtd_conf/set_audit_logging.py @@ -7,6 +7,7 @@ from virttest import data_dir from virttest import utils_libvirtd from virttest import utils_split_daemons +from virttest import virt_vm from virttest.utils_test import libvirt @@ -26,17 +27,25 @@ def run(test, params, env): """ # Here it needs manipulate libvird config as test step, so it doesn't use default config # enabled by avocado-vt framework at start - def config_libvirtd_log(enable_audit_logging=False): + def config_libvirtd_log(params): """ Configure audit log level" - :param enable_audit_logging: bool indicating enable/disable audit_logging + :param params: one dict wrapping parameters """ + # enable/disable audit_logging + enable_audit_logging = "yes" == params.get("enable_audit", "no") + # set audit level or not + set_audit_level = "yes" == params.get("set_audit_level", "yes") + log_filters = params.get('log_filters') libvirtd_config.log_outputs = "1:file:%s" % log_config_path libvirtd_config.log_level = 1 - libvirtd_config.audit_level = 1 + if set_audit_level: + libvirtd_config.audit_level = 1 if enable_audit_logging: libvirtd_config.audit_logging = 1 + if log_filters: + libvirtd_config.log_filters = log_filters utils_libvirtd.Libvirtd('virtqemud').restart() def ensure_auditd_started(): @@ -60,9 +69,9 @@ def check_virt_type_from_audit_log(): def clean_up_audit_log_file(): """ - Clean up audit message in log file. + Clean up audit message under /var/log/audit/. """ - cmd = "> /var/log/audit/audit.log; > %s" % log_config_path + cmd = "truncate -s 0 /var/log/audit/*" process.run(cmd, ignore_status=False, shell=True) @@ -75,28 +84,70 @@ def check_msg_in_libvirtd_log(str_to_grep): if not libvirt.check_logfile(str_to_grep, log_config_path, str_in_log=enable_audit_logging): test.fail("Check message log:%s failed in log file:%s" % (str_to_grep, log_config_path)) + def ausearch_audit_log(): + """ + Check ausearch output related to audit + + """ + ausearch_type_list = params.get("ausearch_type_list").split() + for type_item in ausearch_type_list: + cmd = "ausearch -m %s -ts recent" % type_item + type_message = "type=%s msg=audit" % type_item + cmd_result = process.run(cmd, shell=True).stdout_text.strip() + if type_message not in cmd_result: + test.fail("Check ausearch type:%s log failed in output:%s" % (type_item, cmd_result)) + + def check_concurrent_filters(): + """ + Check concurrent filters + + """ + log_for_util = params.get("log_for_util") + if not libvirt.check_logfile(log_for_util, log_config_path, + ignore_status=True, str_in_log=True): + test.fail("Can not find expected message :%s in log file:%s" % (log_for_util, log_config_path)) + log_for_filter_list = eval(params.get("log_for_filter_list")) + for filter in log_for_filter_list: + str_to_grep = "%s" % filter + if libvirt.check_logfile(str_to_grep, log_config_path, + ignore_status=True, str_in_log=True): + test.fail("Find unexpected message :%s in log file:%s" % (str_to_grep, log_config_path)) + vm_name = params.get("main_vm", "avocado-vt-vm1") vm = env.get_vm(vm_name) enable_audit_logging = "yes" == params.get("enable_audit", "no") + set_audit_level = "yes" == params.get("set_audit_level", "yes") # Get LibvirtdConfig or VirtQemuConfig log_config_path = os.path.join(data_dir.get_tmp_dir(), "libvirtd.log") libvirtd_config = VirtQemudConfig() if utils_split_daemons.is_modular_daemon() else LibvirtdConfig() + test_scenario = params.get("test_scenario") + try: # Need stop VM first if vm.is_alive(): vm.destroy() - config_libvirtd_log(enable_audit_logging) + config_libvirtd_log(params) # Clean up old audit message from log file clean_up_audit_log_file() - # Check and start audit daemon service if necessary ensure_auditd_started() - vm.start() - check_virt_type_from_audit_log() - check_msg_in_libvirtd_log("virDomainAudit") + except virt_vm.VMStartError as e: + test.fail("VM failed to start." + "Error: %s" % str(e)) + else: + if test_scenario in ["disable_audit_log", "enable_audit_log"]: + check_virt_type_from_audit_log() + check_msg_in_libvirtd_log("virDomainAudit") + elif test_scenario == "default_audit_log": + vm.wait_for_login().close() + ausearch_audit_log() + elif test_scenario == "concurrent_filters": + check_concurrent_filters() finally: libvirtd_config.restore() utils_libvirtd.Libvirtd('virtqemud').restart() + if log_config_path and os.path.exists(log_config_path): + os.remove(log_config_path) diff --git a/libvirt/tests/src/daemon/conf_file/libvirtd_conf/unix_sock.py b/libvirt/tests/src/daemon/conf_file/libvirtd_conf/unix_sock.py index 1ab0b1ee372..c0d65773acc 100644 --- a/libvirt/tests/src/daemon/conf_file/libvirtd_conf/unix_sock.py +++ b/libvirt/tests/src/daemon/conf_file/libvirtd_conf/unix_sock.py @@ -10,6 +10,7 @@ from virttest import data_dir from virttest import utils_config from virttest import utils_libvirtd +from virttest import utils_split_daemons from virttest import libvirt_version @@ -95,6 +96,7 @@ def check_unix_sock(group, perms, path, readonly=False): result = virsh.net_define(xml_path, uri=uri, ignore_status=True) logging.debug('Result of virsh test run is:\n %s' % result) + process.run("ls -lZ /run/libvirt/", shell=True, ignore_status=True) try: if result.exit_status and not readonly: logging.error('Error encountered when running virsh net-define ' @@ -123,12 +125,16 @@ def check_all_unix_sock(group, ro_perms, rw_perms, root_path): :param root_path: Absolute path of the directory that target file in. :return : True if success or False if any test fails. """ - rw_path = os.path.join(root_path, 'libvirt-sock') + if utils_split_daemons.is_modular_daemon(): + rw_path = os.path.join(root_path, 'virtqemud-sock') + ro_path = os.path.join(root_path, 'virtqemud-sock-ro') + else: + rw_path = os.path.join(root_path, 'libvirt-sock') + ro_path = os.path.join(root_path, 'libvirt-sock-ro') logging.debug("Checking read-write socket file %s" % rw_path) if not check_unix_sock(group, rw_perms, rw_path): return False - ro_path = os.path.join(root_path, 'libvirt-sock-ro') logging.debug("Checking read-only socket file %s" % ro_path) return check_unix_sock(group, ro_perms, ro_path, readonly=True) diff --git a/libvirt/tests/src/daemon/conf_file/libvirtd_conf/virt_admin_logging.py b/libvirt/tests/src/daemon/conf_file/libvirtd_conf/virt_admin_logging.py index 4341e872825..ccfaf32e1cb 100644 --- a/libvirt/tests/src/daemon/conf_file/libvirtd_conf/virt_admin_logging.py +++ b/libvirt/tests/src/daemon/conf_file/libvirtd_conf/virt_admin_logging.py @@ -11,15 +11,17 @@ import logging import os +import re from avocado.utils import process from virttest import utils_libvirtd -from virttest import virt_vm +from virttest import virt_vm, utils_misc from virttest import virt_admin from virttest.libvirt_xml import vm_xml from virttest.utils_libvirt import libvirt_disk +from virttest.utils_test import libvirt from virttest.staging import service @@ -60,7 +62,7 @@ def check_log_outputs(params, test): log_output = params.get("log_outputs") vp = virt_admin.VirtadminPersistent() virt_admin_log = vp.daemon_log_outputs(ignore_status=True, debug=True).stdout_text.strip() - if log_output not in virt_admin_log: + if not re.search(r'%s' % log_output, virt_admin_log): test.fail("Can not find expected log output: %s from virt admin command output: %s" % (log_output, virt_admin_log)) @@ -81,6 +83,10 @@ def create_customized_disk(params): source_dict.update({"file": source_file}) disk_src_dict = {"attrs": source_dict} + libvirt.create_local_disk("file", source_file, 1, disk_format="qcow2") + + cleanup_files.append(source_file) + customized_disk = libvirt_disk.create_primitive_disk_xml( type_name, disk_device, device_target, device_bus, @@ -116,8 +122,7 @@ def check_msg_in_var_log_message(params, test): log_config_path = params.get("log_file_path") str_to_grep = params.get("str_to_grep") cmd = "grep -E -l '%s' %s" % (str_to_grep, log_config_path) - if process.run(cmd, shell=True, ignore_status=True).exit_status != 0: - test.fail("Check message log:%s failed in log file:%s" % (str_to_grep, log_config_path)) + return process.run(cmd, shell=True, ignore_status=True).exit_status == 0 def run(test, params, env): @@ -131,6 +136,11 @@ def run(test, params, env): vm_name = params.get("main_vm") vm = env.get_vm(vm_name) + # Clear log file + log_config_path = params.get("log_file_path") + truncate_log = "truncate -s 0 %s" % log_config_path + process.run(truncate_log, ignore_status=True, shell=True, verbose=True) + # Back up xml file if vm.is_alive(): vm.destroy(gracefully=False) @@ -143,7 +153,11 @@ def run(test, params, env): except virt_vm.VMStartError as e: LOG.debug("VM failed to start as expected." "Error: %s", str(e)) - check_msg_in_var_log_message(params, test) + result = utils_misc.wait_for(lambda: check_msg_in_var_log_message(params, test), timeout=20) + if not result: + log_config_path = params.get("log_file_path") + str_to_grep = params.get("str_to_grep") + test.fail("Check message log:%s failed in log file:%s" % (str_to_grep, log_config_path)) finally: # Recover VM LOG.info("Restoring vm...") diff --git a/libvirt/tests/src/daemon/conf_file/qemu_conf/set_virtlogd.py b/libvirt/tests/src/daemon/conf_file/qemu_conf/set_virtlogd.py index b4eb55b1c20..c80f4de93a1 100644 --- a/libvirt/tests/src/daemon/conf_file/qemu_conf/set_virtlogd.py +++ b/libvirt/tests/src/daemon/conf_file/qemu_conf/set_virtlogd.py @@ -1,4 +1,5 @@ import logging as log +import glob import os import stat import time @@ -11,8 +12,13 @@ from virttest import utils_config from virttest import utils_libvirtd from virttest import utils_package +from virttest import utils_split_daemons +from virttest import utils_misc from virttest import virt_vm +from virttest import virsh + from virttest.staging import service +from virttest.utils_test import libvirt from virttest.libvirt_xml.vm_xml import VMXML from virttest.libvirt_xml.devices.console import Console from virttest.libvirt_xml.devices.graphics import Graphics @@ -222,6 +228,642 @@ def configure_spice(vm_name): vm_spice_xml.add_device(graphic) vm_spice_xml.sync() + def enable_virtlogd_specific_config_file(): + """ + Configure virtlogd using specific config file. + + """ + virtlogd_config_file = params.get("virtlogd_config_file") + virtlogd_config_bak_file = params.get("virtlogd_config_bak_file") + if os.path.exists(virtlogd_config_file): + # backup config file + os.rename(virtlogd_config_file, virtlogd_config_bak_file) + virtlogd_config_file_new = params.get("virtlogd_config_file_new") + with open(virtlogd_config_file, "w") as fd: + fd.write('VIRTLOGD_ARGS="--config /etc/libvirt/virtlogd-new.conf"') + fd.write('\n') + + with open(virtlogd_config_file_new, "w") as fd: + fd.write('log_level = 2') + fd.write('\n') + fd.write('log_outputs="1:file:/var/log/libvirt/virtlogd-new.log"') + fd.write('\n') + # Modify the selinux context + cmd = "chcon system_u:object_r:virtlogd_etc_t:s0 %s" % virtlogd_config_file_new + process.run(cmd, ignore_status=True, shell=True) + # restart virtlogd + service.Factory.create_service("virtlogd").restart() + check_service_status("virtlogd", service_start=False) + + def check_virtlogd_started_with_config(): + """ + Check if virtlogd is started with --config argument + + """ + cmd = "ps -fC 'virtlogd'" + cmd_result = process.run(cmd, shell=True).stdout_text.strip() + virtlogd_config_file_new = params.get("virtlogd_config_file_new") + matched_message = "--config %s" % virtlogd_config_file_new + if matched_message not in cmd_result: + test.fail("Check virtlogd is started with config :%s failed in output:%s" + % (matched_message, cmd_result)) + new_virtlogd_log_file = params.get("virtlogd_config_file_alternative_new") + if not os.path.exists(new_virtlogd_log_file): + test.fail("Failed to create new virtlogd log:%s" % new_virtlogd_log_file) + str_to_grep = "virObject" + if not libvirt.check_logfile(str_to_grep, new_virtlogd_log_file): + test.fail("Check message log:%s failed in log file:%s" + % (str_to_grep, new_virtlogd_log_file)) + + def enable_virtlogd_timeout(): + """ + Configure virtlogd using timeout parameter. + + """ + virtlogd_config_file = params.get("virtlogd_config_file") + virtlogd_config_bak_file = params.get("virtlogd_config_bak_file") + if os.path.exists(virtlogd_config_file): + # backup config file + os.rename(virtlogd_config_file, virtlogd_config_bak_file) + + with open(virtlogd_config_file, "w") as fd: + fd.write('VIRTLOGD_ARGS="--timeout=30"') + fd.write('\n') + # restart virtlogd + service.Factory.create_service("virtlogd").restart() + check_service_status("virtlogd", service_start=False) + + def check_virtlogd_started_with_timeout(): + """ + Check if virtlogd is started with timeout=30 + + """ + cmd = "ps -fC 'virtlogd'" + cmd_result = process.run(cmd, shell=True).stdout_text.strip() + matched_message = "--timeout=30" + if matched_message not in cmd_result: + test.fail("Check virtlogd is started with config :%s failed in output:%s" + % (matched_message, cmd_result)) + # nothing to do in 40 seconds to make virtlogd timeout + time.sleep(40) + cmd = "ps aux|grep virtlogd" + if process.run(cmd, shell=True).exit_status == 0: + test.fail("Find unexpected virtlogd") + + def check_virtlogd_failed_invalid_config(): + """ + Check if virtlogd is failed status + + """ + virtlogd_config.max_clients = params.get("max_clients") + cmd = ("systemctl status virtlogd | grep 'Active: active'") + ret = process.run(cmd, ignore_status=True, shell=True, verbose=True) + if ret.exit_status != 0: + test.fail("virtlogd is not in active from log:%s" % ret.stdout_text.strip()) + + action = params.get("action") + process.run("systemctl %s virtlogd" % action, ignore_status=True, shell=True) + time.sleep(4) + cmd = ("systemctl status virtlogd | grep 'Active: failed'") + result = process.run(cmd, ignore_status=True, shell=True, verbose=True) + if result.exit_status != 0: + test.fail("virtlogd is not in failed state from output: %s" % result.stdout_text.strip()) + + def create_crash_vm(): + """ + create one VM which will crash when starting + + """ + # disable huge pages + cmd_hugepage = " sysctl vm.nr_hugepages=0" + process.run(cmd_hugepage, ignore_status=True, shell=True, verbose=True) + VMXML.set_memoryBacking_tag(vm_name) + + def check_record_qenu_crash_log(): + """ + check recorded qemu crash log + """ + # Start VM + try: + vm.start() + except virt_vm.VMStartError as detail: + logging.info("VM failed to start." + "Error: %s" % str(detail)) + crash_information = params.get("crash_information") + if not libvirt.check_logfile(crash_information, guest_log_file): + test.fail("Check expected message log:%s failed in log file:%s" + % (crash_information, guest_log_file)) + + def lsof_qemu_log_file(): + """ + use lsof command to check qemu log file + + :return: lsof command return value + """ + cmd_lsof = "lsof %s" % guest_log_file + lsof_output = process.run(cmd_lsof, ignore_status=True, shell=True, verbose=True).stdout_text.strip() + return lsof_output + + def stop_virtlogd(): + """ + Stop virtlogd service + + """ + # truncate qemu log file in order to avoid making later checking complex + truncate_log_file(guest_log_file, '0') + vm.start() + vm.wait_for_login().close() + lsof_output = lsof_qemu_log_file() + if "virtlogd" not in lsof_output: + test.fail("virtlogd does not open qemu log file:%s" + % guest_log_file) + + def check_stop_virtlogd(): + """ + Check something happen after stop virtlogd service + + """ + virtlogd_service = service.Factory.create_service("virtlogd") + virtlogd_service.stop() + vm.wait_for_login().close() + lsof_output = lsof_qemu_log_file() + if "virtlogd" in lsof_output: + test.fail("guest log still write into qemu log file:%s after virtlogd stop" + % guest_log_file) + vm.destroy() + shut_down_msg = "shutting down, reason=shutdown" + if not libvirt.check_logfile(shut_down_msg, guest_log_file): + test.fail("Check VM destroy message log:%s failed in log file:%s" + % (shut_down_msg, guest_log_file)) + qemu_msg = "qemu-kvm: terminating on signal" + if not libvirt.check_logfile(qemu_msg, guest_log_file, str_in_log=False): + test.fail("Find unexpected:%s failed in log file:%s" + % (qemu_msg, guest_log_file)) + + virtlogd_service.start() + + def check_file_exist(log_file): + """ + check whether specified file exist or not + + :param log_file: specified log file name. + """ + if not os.path.exists(log_file): + test.fail("failed to find qemu log file: %s" % log_file) + + def truncate_log_file(file_path, size_in_unit="2M"): + """ + truncate guest log file to default 2M + + :param file_path: specified file name. + :param size_in_unit: expected size after being truncated. + """ + truncate_2m_cmd = "truncate -s %s %s" % (size_in_unit, file_path) + process.run(truncate_2m_cmd, ignore_status=True, shell=True, verbose=True) + + def enable_default_max_size_max_backups(): + """ + Enable default qemu log file max size and max backups + + """ + def _start_stop_vm(): + """ + start and stop to generate large logs + """ + vm.start() + vm.wait_for_login().close() + vm.destroy() + + if vm.is_alive(): + vm.destroy(gracefully=False) + # clean up log file exclude /var/log/libvirt/qemu/$guest_name.log + file_list = glob.glob('%s/%s.log.*' % (QEMU_LOG_PATH, vm_name)) + for file_name in file_list: + if os.path.exists(file_name): + os.remove(file_name) + # increase log file size to 2M to trigger generating new log file + for i in range(0, 4): + truncate_log_file(guest_log_file) + _start_stop_vm() + # check /var/log/libvirt/qemu/$guest_name.log.1 is generated + if i < 3: + guest_log_file_index = os.path.join(QEMU_LOG_PATH, "%s.log.%s" % (vm_name, i)) + check_file_exist(guest_log_file_index) + + def check_default_max_size_max_backups(): + """ + check default qemu log file max size and max backups + + """ + max_backups = int(params.get("max_backups")) + # three are totally guest log file: max_backups + 1 + log_file_list = glob.glob('%s/%s.log*' % (QEMU_LOG_PATH, vm_name)) + if len(log_file_list) != (max_backups + 1): + test.fail("the total related log file is not expected, and actual are: %s" % log_file_list) + + def enable_recreate_qemu_log(): + """ + Enable create new qemu log file again + + """ + vm.start() + check_file_exist(guest_log_file) + os.remove(guest_log_file) + # trigger qemu log generation + virsh.qemu_monitor_command(name=vm.name, cmd="info block", options='--hmp', + **{'debug': True, 'ignore_status': True}) + if os.path.exists(guest_log_file): + test.fail("guest log file: %s is wrongly recreated" % guest_log_file) + + def check_recreate_qemu_log(): + """ + check default qemu log will be recreated after VM destroy + """ + # guest log file will be recreated once VM is destroyed, and log will be recorded accordingly + virsh.destroy(vm_name) + vm_destroy_msg = "shutting down, reason=destroyed" + if not libvirt.check_logfile(vm_destroy_msg, guest_log_file): + test.fail("Check VM destroy message log:%s failed in log file:%s" + % (vm_destroy_msg, guest_log_file)) + + def check_opened_fd_of_qemu_log_file(): + """ + Check whether qemu log file is opened by virtlogd correctly + + """ + vm.start() + vm.wait_for_login().close() + lsof_start_vm_output = lsof_qemu_log_file() + if "virtlogd" not in lsof_start_vm_output: + test.fail("virtlogd does not open qemu log file after VM start:%s" + % guest_log_file) + + vm.destroy(gracefully=False) + lsof_destroy_vm_output = lsof_qemu_log_file() + if "virtlogd" in lsof_destroy_vm_output: + test.fail("guest log still write into qemu log file:%s after VM stop" + % guest_log_file) + + def check_vm_destroy_log_into_qemu_log_file(): + """ + Check whether vm destroy log is written into qemu log file + + """ + # truncate qemu log file to size 0 in order to avoid making later checking complex + truncate_log_file(guest_log_file, '0') + vm.start() + vm.wait_for_login().close() + virsh.destroy(vm_name) + vm_destroy_msg = ".*qemu-kvm: terminating on signal.*\n.*shutting down, reason=destroyed.*" + if not libvirt.check_logfile(vm_destroy_msg, guest_log_file): + test.fail("Check VM destroy message log:%s failed in log file:%s" + % (vm_destroy_msg, guest_log_file)) + + def check_start_vm_twice_log_into_qemu_log_file(): + """ + Check whether vm start twice is written into qemu log file + + """ + vm.start() + vm.wait_for_login().close() + # truncate qemu log file to size 0 in order to avoid making later checking complex + truncate_log_file(guest_log_file, '0') + virsh.destroy(vm_name) + vm.start() + vm.wait_for_login().close() + vm_destroy_start_msg = ".*qemu-kvm: terminating on signal.*\n.*" + \ + "shutting down, reason=destroyed.*\n.*name guest=%s.*" % vm_name + if not libvirt.check_logfile(vm_destroy_start_msg, guest_log_file): + test.fail("Check VM destroy and start message log:%s failed in log file:%s" + % (vm_destroy_start_msg, guest_log_file)) + + def check_record_save_restore_guest_log(): + """ + Check whether vm save and restore is written into qemu log file + + """ + vm.start() + vm.wait_for_login().close() + # truncate qemu log file to size 0 in order to avoid making later checking complex + truncate_log_file(guest_log_file, '0') + save_path = params.get("save_vm_path") + virsh.save(vm_name, save_path) + virsh.restore(save_path) + vm.wait_for_login().close() + vm_save_restore_msg = ".*qemu-kvm: terminating on signal.*\n.*" + \ + "shutting down, reason=saved.*\n.*name guest=%s.*" % vm_name + if not libvirt.check_logfile(vm_save_restore_msg, guest_log_file): + test.fail("Check VM save and restore message log:%s failed in log file:%s" + % (vm_save_restore_msg, guest_log_file)) + + def set_valid_max_clients(max_clients, check_max_clients=True): + """ + set valid max clients in virtlogd config file + + :param max_clients: max clients in integer + :param check_max_clients: boolean value indicating whether need check max clients value + """ + virtlogd_log_file = params.get("virtlogd_log_file") + if os.path.exists(virtlogd_log_file): + truncate_log_file(virtlogd_log_file, '0') + virtlogd_config.log_level = 1 + virtlogd_config.log_outputs = f"1:file:{virtlogd_log_file}" + virtlogd_config.max_clients = max_clients + action = params.get("action") + process.run("systemctl %s virtlogd" % action, ignore_status=True, shell=True) + cmd = ("systemctl status virtlogd | grep 'Active: active'") + ret = process.run(cmd, **debug_param) + if ret.exit_status != 0: + test.fail("virtlogd is not in active from log:%s" % ret.stdout_text.strip()) + + if check_max_clients: + vm.start() + vm.wait_for_login().close() + nclients_max_msg = "nclients_max=%s" % max_clients + if not libvirt.check_logfile(nclients_max_msg, virtlogd_log_file): + test.fail("Check VM nclients max value :%s failed in log file:%s" + % (nclients_max_msg, virtlogd_log_file)) + + def check_valid_max_clients(): + """ + Check whether virtlogd can work normally when set valid max clients + + """ + max_clients = params.get("max_clients") + set_valid_max_clients(max_clients) + + def check_valid_boundary_max_clients(): + """ + Check whether virtlogd can work normally when set valid boundary max clients + + """ + max_clients = params.get("low_max_clients") + set_valid_max_clients(max_clients, check_max_clients=False) + max_clients = params.get("high_max_clients") + set_valid_max_clients(max_clients) + + def check_nclients_occupied_released(): + """ + Check connection clients value can be reflected when VM is different life cycle state + + """ + max_clients = params.get("max_clients") + set_valid_max_clients(max_clients) + + save_path = params.get("save_vm_path") + virsh.save(vm_name, save_path) + nclients_msg = params.get("nclients") + virtlogd_log_file = params.get("virtlogd_log_file") + if not libvirt.check_logfile(nclients_msg, virtlogd_log_file): + test.fail("Check nclients value after save :%s failed in log file:%s" + % (nclients_msg, virtlogd_log_file)) + + truncate_log_file(virtlogd_log_file, '0') + virsh.restore(save_path) + vm.wait_for_login().close() + if not libvirt.check_logfile(nclients_msg, virtlogd_log_file): + test.fail("Check nclients value after restore :%s failed in log file:%s" + % (nclients_msg, virtlogd_log_file)) + + def check_invalid_boundary_max_clients(): + """ + Check whether virtlogd can work normally when set invalid boundary max clients + + """ + virtlogd_config.max_clients = params.get("low_max_clients") + cmd = ("systemctl status virtlogd | grep 'Active: active'") + ret = process.run(cmd, **debug_param) + if ret.exit_status != 0: + test.fail("virtlogd is not in active from log:%s" % ret.stdout_text.strip()) + + def _restart_virtlogd(): + """ + restart virtlogd and check its state + """ + action = params.get("action") + process.run("systemctl %s virtlogd" % action, ignore_status=True, shell=True) + time.sleep(4) + cmd = ("systemctl status virtlogd | grep 'Active: failed'") + result = process.run(cmd, ignore_status=True, shell=True, verbose=True) + if result.exit_status != 0: + test.fail("virtlogd is not in failed state from output: %s" % result.stdout_text.strip()) + + _restart_virtlogd() + virtlogd_config.max_clients = params.get("high_max_clients") + _restart_virtlogd() + + def check_guest_runnning_after_virtlogd_crash(): + """ + Check whether guest still in running after virtlogd crash + + """ + vm.start() + vm.wait_for_login().close() + utils_package.package_install(['lsof']) + lsof_output = lsof_qemu_log_file() + if "virtlogd" not in lsof_output: + test.fail("virtlogd does not open qemu log file:%s" + % guest_log_file) + + before_pid_virtlogd = process.getoutput("pidof virtlogd") + process.run(f'kill -9 {before_pid_virtlogd}', **debug_param) + + after_pid_virtlogd = process.getoutput("pidof virtlogd") + if after_pid_virtlogd: + test.fail(f"virtlogd: {after_pid_virtlogd} is not killed as expected") + vm.wait_for_login().close() + + def check_reload_new_config(virtlogd_config): + """ + Check whether new virtlogd configuration can be reloaded + + :param virtlogd_config: virtlogd configuration file + """ + virtlogd_file_new = params.get("virtlogd_file_new") + virtlogd_log_file = params.get("virtlogd_log_file") + virtlogd_config.log_level = 2 + virtlogd_config.log_filters = "1:+rpc" + virtlogd_config.log_outputs = f"1:file:{virtlogd_file_new}" + + action = params.get("action") + process.run("systemctl %s virtlogd" % action, ignore_status=True, shell=True) + time.sleep(4) + + if not os.path.exists(virtlogd_file_new): + test.fail(f"Failed to reload new virtlogd file: {virtlogd_file_new} specified in config") + + vm.start() + vm.wait_for_login().close() + rpm_msg = "debug.*virNetSocketNew" + if not libvirt.check_logfile(rpm_msg, virtlogd_file_new): + test.fail("Check rpc message :%s failed in log file:%s" + % (rpm_msg, virtlogd_log_file)) + + def check_log_filters_not_same_with_loglevel(): + """ + Check whether new virtlogd filter configuration can work as expected + + """ + virtlogd_file = params.get("virtlogd_file") + virtlogd_service = service.Factory.create_service("virtlogd") + virtlogd_service.stop() + if os.path.exists(virtlogd_file): + truncate_log_file(virtlogd_file, '0') + + virtlogd_config.log_level = params.get("log_level") + virtlogd_config.log_filters = params.get("log_filters") + virtlogd_config.log_outputs = f"1:file:{virtlogd_file}" + + action = params.get("action") + process.run("systemctl %s virtlogd" % action, ignore_status=True, shell=True) + time.sleep(4) + + vm.start() + vm.wait_for_login().close() + + filter_loglevel_1 = params.get("filter_loglevel_1") + filter_loglevel_2 = params.get("filter_loglevel_2") + filter_loglevel_4 = params.get("filter_loglevel_4") + process.run("virtlogd", ignore_status=True, shell=True) + for log_level in [filter_loglevel_1, filter_loglevel_2, filter_loglevel_4]: + if not libvirt.check_logfile(log_level, virtlogd_file): + test.fail("Check related message :%s failed in log file:%s" + % (log_level, virtlogd_file)) + + filter_loglevel_3 = params.get("filter_loglevel_3") + if not libvirt.check_logfile(filter_loglevel_3, virtlogd_file, str_in_log=False): + test.fail("Find unexpected event message:%s in log file:%s" + % (filter_loglevel_3, virtlogd_file)) + + def remove_backup_logfiles(): + """ + Clean up backup log files + + """ + file_list = glob.glob('%s/%s.log.*' % (QEMU_LOG_PATH, vm_name)) + for file_name in file_list: + if os.path.exists(file_name): + os.remove(file_name) + + def set_max_size_in_virtlogd_config(): + """ + set max_size in virtlogd config + + """ + max_size = params.get("max_size") + max_backups = params.get("max_backups", 3) + virtlogd_config.__option_types__.update({'max_size': 'int'}) + virtlogd_config.__option_types__.update({'max_backups': 'int'}) + if max_size: + virtlogd_config.max_size = max_size + virtlogd_config.max_backups = max_backups + + logging.info("take actions to make new virtlogd config effective") + action = params.get("action") + process.run("systemctl %s virtlogd" % action, **debug_param) + + def wait_until_file_present(file_path): + """ + wait for certain time until file is present + + :param file_path: file path + """ + def _file_present(): + vm.start() + vm.wait_for_login().close() + vm.destroy() + return os.path.exists(file_path) + + utils_misc.wait_for(lambda: _file_present(), timeout=300) + + def check_reload_max_size_config(): + """ + Check whether new max size configuration can take effect after reload + + """ + vm.start() + vm.wait_for_login().close() + vm.destroy() + + remove_backup_logfiles() + truncate_log_file(guest_log_file, '180K') + + set_max_size_in_virtlogd_config() + + guest_log = "%s/%s.log.0" % (QEMU_LOG_PATH, vm_name) + wait_until_file_present(guest_log) + + ls_file_size_cmd = "ls -lh %s/%s.log*" % (QEMU_LOG_PATH, vm_name) + output = process.run(ls_file_size_cmd, **debug_param).stdout_text + if "200K" not in output: + test.fail(f"max size not take effect after reload") + + def check_set_max_size_config(): + """ + Check whether new max size configuration can take effect after set + + """ + check_reload_max_size_config() + + def ls_log_files(): + """ + ls all logs files,and check total numbers + + """ + max_backups = int(params.get("max_backups")) + time_start = 0 + time_end = 60 + max_backup_plus_one = max_backups + 1 + while time_start <= time_end: + ls_logfile_number_cmd = "ls -lh %s/%s.log* | wc -l" % (QEMU_LOG_PATH, vm_name) + number = process.run(ls_logfile_number_cmd, **debug_param).stdout_text.strip() + if max_backup_plus_one != int(number): + test.fail(f"actual logs files number: {number} is not equals to expected:{max_backup_plus_one}") + time.sleep(10) + time_start += 20 + + def check_set_max_backups(): + """ + Check whether backup files has exact numbers as described in max_backup + + """ + vm.start() + vm.wait_for_login().close() + vm.destroy() + + remove_backup_logfiles() + truncate_log_file(guest_log_file, '3M') + + set_max_size_in_virtlogd_config() + + max_backups = int(params.get("max_backups")) + for index in range(max_backups): + guest_log = "%s/%s.log.%d" % (QEMU_LOG_PATH, vm_name, index) + wait_until_file_present(guest_log) + truncate_log_file(guest_log_file, '3M') + ls_log_files() + + def check_reload_max_backups(): + """ + Check whether backup files has exact numbers as reloading configuration + + """ + vm.start() + vm.wait_for_login().close() + vm.destroy() + + remove_backup_logfiles() + truncate_log_file(guest_log_file, '180K') + + set_max_size_in_virtlogd_config() + + max_backups = int(params.get("max_backups")) + for index in range(max_backups): + guest_log = "%s/%s.log.%d" % (QEMU_LOG_PATH, vm_name, index) + wait_until_file_present(guest_log) + truncate_log_file(guest_log_file, '180K') + ls_log_files() + vm_name = params.get("main_vm", "avocado-vt-vm1") expected_result = params.get("expected_result", "virtlogd_disabled") stdio_handler = params.get("stdio_handler", "not_set") @@ -232,6 +874,8 @@ def configure_spice(vm_name): stop_libvirtd = "yes" == params.get("stop_libvirtd", "no") with_spice = "yes" == params.get("with_spice", "no") with_console_log = "yes" == params.get("with_console_log", "no") + pipe_node = None + debug_param = {'ignore_status': True, 'shell': True, 'verbose': True} vm = env.get_vm(vm_name) vm_xml = VMXML.new_from_inactive_dumpxml(vm_name) @@ -245,13 +889,15 @@ def configure_spice(vm_name): config = utils_config.LibvirtQemuConfig() libvirtd = utils_libvirtd.Libvirtd() + virtlogd_config = utils_config.VirtLogdConfig() try: if stdio_handler != 'not_set': config['stdio_handler'] = "'%s'" % stdio_handler if restart_libvirtd or stop_libvirtd: virtlogd_pid = check_service_status("virtlogd", service_start=True) logging.info("virtlogd pid: %s", virtlogd_pid) - check_service_status("libvirtd", service_start=True) + service_name = "virtqemud" if utils_split_daemons.is_modular_daemon() else "libvirtd" + check_service_status(service_name, service_start=True) # Restart libvirtd to make change valid. if not libvirtd.restart(): @@ -264,15 +910,17 @@ def configure_spice(vm_name): 'with stdio_handler=%s' % stdio_handler) if not start_vm: + if vm.is_alive(): + vm.destroy(gracefully=False) if reload_virtlogd: reload_and_check_virtlogd() - if expected_result == 'virtlogd_restart': + elif expected_result == 'virtlogd_restart': # check virtlogd status virtlogd_pid = check_service_status("virtlogd", service_start=True) logging.info("virtlogd PID: %s", virtlogd_pid) # restart virtlogd - ret = process.run("systemctl restart virtlogd", ignore_status=True, shell=True) - if ret.exit_status: + ret = service.Factory.create_service("virtlogd").restart() + if ret is False: test.fail("failed to restart virtlogd.") # check virtlogd status new_virtlogd_pid = check_service_status("virtlogd", service_start=False) @@ -283,7 +931,7 @@ def configure_spice(vm_name): ret = process.run(cmd, ignore_status=True, shell=True) if ret.exit_status: test.fail("virtlogd don't exist.") - if expected_result == 'virtlogd_disabled': + elif expected_result == 'virtlogd_disabled': # check virtlogd status virtlogd_pid = check_service_status("virtlogd", service_start=True) logging.info("virtlogd PID: %s", virtlogd_pid) @@ -297,6 +945,42 @@ def configure_spice(vm_name): ret = process.run(cmd, ignore_status=True, shell=True) if not ret.exit_status: test.fail("virtlogd still exist.") + elif expected_result == 'virtlogd_specific_config_file_enable': + enable_virtlogd_specific_config_file() + check_virtlogd_started_with_config() + elif expected_result == 'specific_timeout': + enable_virtlogd_timeout() + check_virtlogd_started_with_timeout() + elif expected_result == "invalid_virtlogd_conf": + check_virtlogd_failed_invalid_config() + elif expected_result == "record_qenu_crash_log": + create_crash_vm() + check_record_qenu_crash_log() + elif expected_result == "stop_virtlogd": + stop_virtlogd() + check_stop_virtlogd() + elif expected_result == "default_max_size_max_backups": + enable_default_max_size_max_backups() + check_default_max_size_max_backups() + elif expected_result == "recreate_qemu_log": + enable_recreate_qemu_log() + check_recreate_qemu_log() + elif expected_result == "opened_fd_of_qemu_log_file": + check_opened_fd_of_qemu_log_file() + elif expected_result == "vm_destroy_log_into_qemu_log_file": + check_vm_destroy_log_into_qemu_log_file() + elif expected_result == "start_vm_twice_log_into_qemu_log_file": + check_start_vm_twice_log_into_qemu_log_file() + elif expected_result == "record_save_restore_guest_log": + check_record_save_restore_guest_log() + elif expected_result in ["valid_max_clients", "valid_boundary_max_clients", "nclients_occupied_released", + "invalid_boundary_max_clients", "guest_runnning_after_virtlogd_crash" + "log_filters_not_same_with_loglevel", "reload_max_size_config", "set_max_size_config", + "set_max_backups", "reload_max_backups"]: + check_test = eval("check_%s" % expected_result) + check_test() + elif expected_result == "reload_new_config": + check_reload_new_config(virtlogd_config) else: # Stop all VMs if VMs are already started. for tmp_vm in env.get_all_vms(): @@ -418,10 +1102,32 @@ def configure_spice(vm_name): "Error: %s" % str(detail)) # Check the new VM start log is appended to the end of the VM log file. if not with_console_log: - check_info_in_vm_log_file(vm_name, guest_log_file, cmd="tail -n 5", + check_info_in_vm_log_file(vm_name, guest_log_file, matchedMsg="char device redirected to /dev/pts") finally: config.restore() libvirtd.restart() + if vm.is_alive(): + vm.destroy(gracefully=False) vm_xml_backup.sync() + if expected_result in ['virtlogd_specific_config_file_enable', 'specific_timeout']: + virtlogd_config_file = params.get("virtlogd_config_file") + virtlogd_config_bak_file = params.get("virtlogd_config_bak_file") + virtlogd_config_file_new = params.get("virtlogd_config_file_new") + if os.path.exists(virtlogd_config_file): + os.remove(virtlogd_config_file) + if os.path.exists(virtlogd_config_file_new): + os.remove(virtlogd_config_file_new) + if virtlogd_config_bak_file: + if os.path.exists(virtlogd_config_file): + os.rename(virtlogd_config_bak_file, virtlogd_config_file) + service.Factory.create_service("virtlogd").restart() + if expected_result in ["invalid_virtlogd_conf", "valid_max_clients", + "valid_boundary_max_clients", "nclients_occupied_released", + "invalid_boundary_max_clients", "reload_new_config", + "log_filters_not_same_with_loglevel", "reload_max_size_config", + "set_max_size_config", + "set_max_backups", "reload_max_backups"]: + virtlogd_config.restore() + service.Factory.create_service("virtlogd").restart() diff --git a/libvirt/tests/src/daemon/conf_file/sysconfig_libvirt_guests/libvirt_guests.py b/libvirt/tests/src/daemon/conf_file/sysconfig_libvirt_guests/libvirt_guests.py index 6d87b7985c5..058d53ffa73 100644 --- a/libvirt/tests/src/daemon/conf_file/sysconfig_libvirt_guests/libvirt_guests.py +++ b/libvirt/tests/src/daemon/conf_file/sysconfig_libvirt_guests/libvirt_guests.py @@ -8,12 +8,14 @@ from avocado.utils import path as utils_path from avocado.utils import process +from virttest import libvirt_version from virttest import utils_libguestfs from virttest import utils_misc from virttest import virsh from virttest import utils_config from virttest.libvirt_xml import vm_xml from virttest.utils_test import libvirt +from virttest.utils_libvirt import libvirt_disk from virttest.staging import service @@ -65,13 +67,22 @@ def chk_on_shutdown(status_error, on_shutdown, parallel_shutdown, output): expect_msg = expect_shutdown_msg(status_error, on_shutdown) logging.debug("The expected messages when host shutdown is: %s ", expect_msg) for dom in vms: - if not re.search(expect_msg[dom.name], output): - logging.debug("expect_mesg is: %s", expect_msg[dom.name]) - if status_error == "no": - test.fail("guest should be %s on shutdown" % on_shutdown) - else: - test.fail("Shutdown of guest should be failed to " - "complete in time") + check_res = re.search(expect_msg[dom.name], output) + no_operation = (transient_vm_operation == "nothing" and not dom.is_persistent()) + if no_operation: + if check_res: + test.fail("Expect msg '%s' does not exist." % expect_msg) + test.log.debug("Check transient guest:%s did nothing successfully", dom.name) + else: + if not check_res: + logging.debug("expect_mesg is: %s", expect_msg[dom.name]) + if status_error == "no": + test.fail("guest:%s should be %s on shutdown" % (dom.name, on_shutdown)) + else: + test.fail("Shutdown of guest should be failed to " + "complete in time") + test.log.debug("Check guest:%s did '%s' successfully", + dom.name, expect_msg[dom.name]) if (on_shutdown == "shutdown") and int(parallel_shutdown) > 0: chk_parallel_shutdown(output, parallel_shutdown) @@ -82,15 +93,14 @@ def chk_on_boot(status_error, on_boot): :param status_error: positive test if status_error is "no", otherwise negative test - :param on_boot: action taking on host booting + :param on_boot: action taking on host booting which set in the conf file """ if status_error == "no": - if on_boot == "start": - for dom in vms: + if on_boot != "ignore": + for dom in active_persistent_vms: if not dom.is_alive(): - test.fail("Since on_boot is setting to 'start', " - "guest should be running after " - "restarting libvirt-guests.") + test.fail("guest:%s should be running after " + "restarting libvirt-guests." % dom.name) else: for dom in vms: if dom.is_alive(): @@ -98,6 +108,7 @@ def chk_on_boot(status_error, on_boot): "unless guests are autostart, " "guest should be shut off after " "restarting libvirt-guests, ") + test.log.debug("Check all guests state successfully") def check_on_shutdown_vm_status(): for dom in vms: @@ -190,12 +201,13 @@ def chk_save_files(status_error, on_shutdown, on_boot): if os.path.exists(save_files[dom]): test.fail("There should be no save files since " "guests are restored on host shutdown.") - else: + elif on_boot == "ignore": for dom in vms: if not os.path.exists(save_files[dom]): test.fail("Guests are suspended on host shutdown, " "and been ignored on host boot, there " "should be save files for the guests.") + test.log.debug("Check all guests file successfully") def boot_time(): booting_time = [] @@ -242,11 +254,28 @@ def cleanup_nfs_backend_guest(vmxml_backup): nfs_server = libvirt.setup_or_cleanup_nfs(False) + def transfer_to_transient(per_guest_name): + """ + Transfer one persistent vm to transient guest. + + :param per_guest_name: persistent guest name. + """ + virsh.start(per_guest_name, ignore_status=False) + vmxml = vm_xml.VMXML.new_from_dumpxml(per_guest_name) + virsh.undefine(per_guest_name, options='--nvram', debug=True, ignore_status=False) + virsh.create(vmxml.xml, debug=True) + test.log.debug("Transfer guest %s to be transient type", per_guest_name) + main_vm_name = params.get("main_vm") main_vm = env.get_vm(main_vm_name) on_boot = params.get("on_boot") on_shutdown = params.get("on_shutdown") + persistent_only = params.get("persistent_only", "") + transient_vm = "yes" == params.get("transient_vm", "no") + if transient_vm: + libvirt_version.is_libvirt_feature_supported(params) + transient_vm_operation = params.get("transient_vm_operation") nfs_vol = params.get("nfs_vol") == "yes" virt_use_nfs = params.get("virt_use_nfs") == "on" parallel_shutdown = params.get("parallel_shutdown") @@ -287,9 +316,10 @@ def cleanup_nfs_backend_guest(vmxml_backup): utils_libguestfs.virt_clone_cmd(main_vm_name, guest_name, True, timeout=360, ignore_status=False) + if transient_vm: + transfer_to_transient(guest_name) vms.append(main_vm.clone(guest_name)) logging.debug("Now the vms is: %s", [dom.name for dom in vms]) - if nfs_vol: # info collected for clear env finally vmxml_backup = [] @@ -299,7 +329,7 @@ def cleanup_nfs_backend_guest(vmxml_backup): if not dom.is_alive(): dom.start() for dom in vms: - dom.wait_for_login() + dom.wait_for_login().close() first_boot_time = [] if on_shutdown == "shutdown" and on_boot == "start": first_boot_time = boot_time() @@ -307,15 +337,27 @@ def cleanup_nfs_backend_guest(vmxml_backup): try: # Config the libvirt-guests file - config.ON_BOOT = on_boot - config.ON_SHUTDOWN = on_shutdown - config.PARALLEL_SHUTDOWN = parallel_shutdown - config.SHUTDOWN_TIMEOUT = shutdown_timeout + if on_boot: + config.ON_BOOT = on_boot + if on_shutdown: + config.ON_SHUTDOWN = on_shutdown + if persistent_only: + config.PERSISTENT_ONLY = persistent_only + if parallel_shutdown: + config.PARALLEL_SHUTDOWN = parallel_shutdown + if shutdown_timeout: + config.SHUTDOWN_TIMEOUT = shutdown_timeout process.run("sed -i -e 's/ = /=/g' " "/etc/sysconfig/libvirt-guests", shell=True) + process.run("cat /etc/sysconfig/libvirt-guests", shell=True) tail_messages = get_log() + # Before restart libvirt-guests, check the status of all VMs + active_persistent_vms = [] + for dom in vms: + if dom.is_alive and dom.is_persistent: + active_persistent_vms.append(dom) # Even though libvirt-guests was designed to operate guests when # host shutdown. The purpose can also be fulfilled by restart the # libvirt-guests service. @@ -325,11 +367,13 @@ def cleanup_nfs_backend_guest(vmxml_backup): time.sleep(30) output = tail_messages.get_output() logging.debug("Get messages in /var/log/messages: %s" % output) - + virsh.dom_list("--all", debug=True) # check the guests state when host shutdown chk_on_shutdown(status_error, on_shutdown, parallel_shutdown, output) - # check the guests state when host rebooted - chk_on_boot(status_error, on_boot) + virsh.dom_list("--all", debug=True) + if not (transient_vm and on_shutdown == "shutdown"): + # check the guests state when host rebooted + chk_on_boot(status_error, on_boot) # check the guests save files chk_save_files(status_error, on_shutdown, on_boot) @@ -353,3 +397,6 @@ def cleanup_nfs_backend_guest(vmxml_backup): if libvirt_guests_service.status(): libvirt_guests_service.stop() + + source_path = os.path.dirname(libvirt_disk.get_first_disk_source(vms[0])) + process.run("cd %s; rm -rf *-clone*" % source_path, shell=True) diff --git a/libvirt/tests/src/daemon/crash_regression.py b/libvirt/tests/src/daemon/crash_regression.py index 9a4dd99c9d4..c2f7cd79723 100644 --- a/libvirt/tests/src/daemon/crash_regression.py +++ b/libvirt/tests/src/daemon/crash_regression.py @@ -83,7 +83,7 @@ def run_mix_boot_order_os_boot(params, libvirtd, vm): try: if not vm_xml.os.boots: os_xml = vm_xml.os - os_xml.boots = {'dev': 'hd'} + os_xml.boots = ['hd'] vm_xml.os = os_xml else: logging.debug(vm_xml.os.boots) diff --git a/libvirt/tests/src/daemon/daemon_functional.py b/libvirt/tests/src/daemon/daemon_functional.py index 950f170472e..8a57fa34d99 100644 --- a/libvirt/tests/src/daemon/daemon_functional.py +++ b/libvirt/tests/src/daemon/daemon_functional.py @@ -172,6 +172,11 @@ def check_config_file(): finally: libvirtd.exit() Libvirtd(daemon_name).stop() + # Remove pid file under /run dir + default_pid_path = "/run/" + daemon_name + ".pid" + if os.path.exists(default_pid_path): + os.remove(default_pid_path) + Libvirtd(daemon_name).stop() socket_name = daemon_name + ".socket" Libvirtd(socket_name).restart() Libvirtd(daemon_name).start() diff --git a/libvirt/tests/src/daemon/enable_disable_daemon_socket_services.py b/libvirt/tests/src/daemon/enable_disable_daemon_socket_services.py new file mode 100644 index 00000000000..c06e4b16eee --- /dev/null +++ b/libvirt/tests/src/daemon/enable_disable_daemon_socket_services.py @@ -0,0 +1,52 @@ +import logging + +from virttest.staging import service + +from provider.libvirtd import libvirtd_base + +VIRSH_ARGS = {'ignore_status': False, 'debug': True} + +LOG = logging.getLogger('avocado.' + __name__) + + +def run(test, params, env): + """ + Verify socket services will be in expected status after enable/disable + """ + service_list = eval(params.get('service_list')) + sock_type = params.get('sock_type') + '.socket' + daemon_list = [f'virt{ser}d' for ser in service_list] + + # Disable main socket before test + for daemon in daemon_list: + socket_srv = service.Factory.create_service(daemon + '.socket') + socket_srv.disable() + + try: + LOG.info('Test enable socket services') + for daemon in daemon_list: + socket_srv = service.Factory.create_service(daemon + sock_type) + LOG.debug(f'Enable service [{socket_srv}]') + socket_srv.enable() + libvirtd_base.check_service_status(daemon + '.socket', + expect_enabled=True) + libvirtd_base.check_service_status(daemon + '-ro.socket', + expect_enabled=True) + libvirtd_base.check_service_status(daemon + '-admin.socket', + expect_enabled=True) + + LOG.info('Test disable socket services') + for daemon in daemon_list: + socket_srv = service.Factory.create_service(daemon + sock_type) + LOG.debug(f'Disable service [{socket_srv}]') + socket_srv.disable() + libvirtd_base.check_service_status(daemon + '.socket', + expect_enabled=False) + libvirtd_base.check_service_status(daemon + '-ro.socket', + expect_enabled=False) + libvirtd_base.check_service_status(daemon + '-admin.socket', + expect_enabled=False) + finally: + for daemon in daemon_list: + socket_srv = service.Factory.create_service(daemon + '.socket') + socket_srv.enable() diff --git a/libvirt/tests/src/daemon/kill_starting.py b/libvirt/tests/src/daemon/kill_starting.py index fc9327a8e28..5aaedb9eb64 100644 --- a/libvirt/tests/src/daemon/kill_starting.py +++ b/libvirt/tests/src/daemon/kill_starting.py @@ -1,3 +1,4 @@ +import os import logging as log from virttest import utils_misc @@ -60,9 +61,14 @@ def get_service(send_signal_at): libvirtd.start(wait_for_working=False) - if not utils_misc.wait_for(lambda: bundle['recieved'], 20, 0.5): + if not utils_misc.wait_for(lambda: bundle['recieved'], 60, 0.5): test.fail("Expect receive signal, but not.") finally: libvirtd.exit() + # Remove pid file under /run + if serv_name: + default_pid_path = "/run/" + serv_name + ".pid" + if os.path.exists(default_pid_path): + os.remove(default_pid_path) # Need to restart libvirtd.socket after starting libvirtd in the foreground Libvirtd("libvirtd.socket").restart() diff --git a/libvirt/tests/src/daemon/libvirtd/libvirtd.py b/libvirt/tests/src/daemon/libvirtd/libvirtd.py index 84848f5d805..cc7540f4940 100644 --- a/libvirt/tests/src/daemon/libvirtd/libvirtd.py +++ b/libvirt/tests/src/daemon/libvirtd/libvirtd.py @@ -5,14 +5,13 @@ import re import threading -try: - import queue as Queue -except ImportError: - import Queue +import queue from avocado.utils import process +from virttest import utils_config from virttest import utils_libvirtd +from virttest import utils_split_daemons from virttest import utils_misc from virttest import utils_package from virttest import virsh @@ -21,8 +20,9 @@ from virttest.utils_test import libvirt -msg_queue = Queue.Queue() - +msg_queue = queue.Queue() +daemon_conf = None +daemon = None # Using as lower capital is not the best way to do, but this is just a # workaround to avoid changing the entire file. @@ -291,6 +291,63 @@ def teardown_default(params, test): pass +def test_check_max_anonymous_clients(params, test): + """ + Test the default value of max_anonymous_clients. + + :param params: dict, test parameters + :param test: test object + """ + check_string_in_log = params.get("check_string_in_log") + daemon_name = params.get("daemon_name") + conf_list = eval(params.get("conf_list")) + log_level = params.get("log_level") + log_file = params.get("log_file") + log_filters = params.get("log_filters") + virsh_uri = params.get("virsh_uri") + require_modular_daemon = params.get('require_modular_daemon', "no") == "yes" + vm_name = params.get("main_vm", "avocado-vt-vm1") + + utils_split_daemons.daemon_mode_check(require_modular_daemon) + global daemon + global daemon_conf + daemon = utils_libvirtd.Libvirtd(daemon_name) + daemon_conf = utils_config.get_conf_obj(daemon_name) + + for item in conf_list: + try: + del daemon_conf[item] + except utils_config.ConfigNoOptionError: + test.log.info("No '%s' in config file.", item) + + daemon_conf.log_level = log_level + daemon_conf.log_outputs = "1:file:%s" % log_file + daemon_conf.log_filters = log_filters + daemon.restart() + + if daemon_name == "virtproxyd": + virtproxy_tcp = utils_libvirtd.DaemonSocket("virtproxyd-tcp.socket") + virtproxy_tcp.restart() + + virsh.start(vm_name, uri=virsh_uri, debug=True, ignore_status=True) + libvirt.check_logfile(check_string_in_log, log_file, str_in_log=True) + + +def teardown_check_max_anonymous_clients(params, test): + """ + Teardown for test the default value of max_anonymous_clients. + + :param params: dict, test parameters + :param test: test object + """ + global daemon + global daemon_conf + if daemon_conf: + daemon_conf.restore() + if daemon: + daemon.restart() + + def run(test, params, env): """ libvirtd daemon related tests. diff --git a/libvirt/tests/src/daemon/qemu_monitor_socket_creation_delay.py b/libvirt/tests/src/daemon/qemu_monitor_socket_creation_delay.py new file mode 100644 index 00000000000..99c8c440f59 --- /dev/null +++ b/libvirt/tests/src/daemon/qemu_monitor_socket_creation_delay.py @@ -0,0 +1,42 @@ +import os +import shutil + +from avocado.utils import process + +from virttest import virt_vm + +from virttest.libvirt_xml import vm_xml +from virttest.utils_libvirt import libvirt_vmxml + + +def run(test, params, env): + """ + Write a wrapper for qemu to wait several seconds (>3) before starts. + + """ + vm_name = params.get('main_vm') + vm = env.get_vm(vm_name) + emulator_dict = eval(params.get("emulator_dict")) + qemu_wrapper_path = params.get("qemu_wrapper_path") + tmp_qemu_wrapper_path = params.get("tmp_qemu_wrapper_path") + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + xml_backup = vmxml.copy() + + try: + qemu_wrapper_path = os.path.join(os.path.dirname(__file__), qemu_wrapper_path) + shutil.copyfile(qemu_wrapper_path, tmp_qemu_wrapper_path) + os.chown(tmp_qemu_wrapper_path, 107, 107) + os.chmod(tmp_qemu_wrapper_path, 0o755) + process.run("chcon system_u:object_r:qemu_exec_t:s0 %s" % tmp_qemu_wrapper_path, shell=True) + + libvirt_vmxml.modify_vm_device(vmxml, "emulator", emulator_dict) + vm.start() + except virt_vm.VMStartError as e: + test.fail("Fail to Start vm with qemu monitor socket creation delay: %s" % e) + + finally: + if vm.is_alive(): + vm.destroy(gracefully=False) + if os.path.exists(tmp_qemu_wrapper_path): + os.remove(tmp_qemu_wrapper_path) + xml_backup.sync() diff --git a/libvirt/tests/src/event/virsh_event.py b/libvirt/tests/src/event/virsh_event.py index 3b4ccef1a63..eabe5c69a93 100644 --- a/libvirt/tests/src/event/virsh_event.py +++ b/libvirt/tests/src/event/virsh_event.py @@ -21,6 +21,7 @@ from virttest.libvirt_xml.devices.interface import Interface from virttest.libvirt_xml.devices.panic import Panic from virttest.libvirt_xml.devices.watchdog import Watchdog +from virttest.utils_libvirt.libvirt_disk import get_non_root_disk_name from xml.dom.minidom import parseString @@ -86,6 +87,7 @@ def run(test, params, env): mount_point = tmpdir + "/smalldiskmountpoint" os.mkdir(mount_point) small_part = os.path.join(tmpdir, params.get("part_name", "io-error_part")) + mount_device = None def create_iface_xml(): """ @@ -152,6 +154,7 @@ def prepare_vmxml_mem(vmxml): vmxml.max_mem_rt_slots = int(params.get("maxmem_slots")) mem_unit = params.get("mem_unit") vmxml.max_mem_rt_unit = mem_unit + cpu_mode = params.get("cpu_mode") current_mem = int(params.get("current_mem")) vmxml.current_mem = current_mem vmxml.current_mem_unit = mem_unit @@ -176,10 +179,10 @@ def prepare_vmxml_mem(vmxml): if vmxml.xmltreefile.find('cpu'): vmxml_cpu = vmxml.cpu logging.debug("Existing cpu configuration in guest xml:\n%s", vmxml_cpu) - vmxml_cpu.mode = 'host-model' + vmxml_cpu.mode = cpu_mode else: vmxml_cpu = vm_xml.VMCPUXML() - vmxml_cpu.xml = "" + vmxml_cpu.xml = "" % cpu_mode vmxml.vcpu = numa_nodes * 2 vmxml_cpu.numa_cell = vmxml_cpu.dicts_to_cells(numa_dict_list) logging.debug(vmxml_cpu.numa_cell) @@ -378,8 +381,10 @@ def _check_disk(target): logging.debug(process.run('qemu-img info %s -U' % new_disk)) virsh.domblkthreshold(vm_name, 'vdb', '100M') session = dom.wait_for_login() - session.cmd("mkfs.ext4 /dev/vdb && mount /dev/vdb /mnt && ls /mnt && " - "dd if=/dev/urandom of=/mnt/bigfile bs=1M count=300 && sync", timeout=90) + disk_name, _ = get_non_root_disk_name(session) + session.cmd("mkfs.ext4 /dev/%s && mount /dev/%s /mnt && ls /mnt && " + "dd if=/dev/urandom of=/mnt/bigfile bs=1M count=300 && sync" + % (disk_name, disk_name), timeout=90) time.sleep(5) session.close() expected_events_list.append("'block-threshold' for %s:" @@ -539,7 +544,7 @@ def _check_disk(target): test.fail("Failed to trigger watchdog: %s" % details) session.close() # watchdog acts slowly, waiting for it. - time.sleep(30) + time.sleep(60) expected_events_list.append("'watchdog' for %s: " + "%s" % action) if action == 'pause': expected_events_list.append("'lifecycle' for %s: Suspended Watchdog") @@ -554,12 +559,21 @@ def _check_disk(target): process.run("truncate -s %s %s" % (part_size, small_part), shell=True) utlv.mkfs(small_part, part_format) utils_misc.mount(small_part, mount_point, None) + + def _get_mount_device(): + with open("/proc/mounts") as f: + last_line = f.readlines()[-1] + mount_device = last_line.split()[0] + return mount_device + mount_device = _get_mount_device() new_disk = mount_point + "/%s_new_disk.img" % dom.name add_disk(dom.name, new_disk, 'vdb', '--subdriver qcow2 --config', 'qcow2') dom.start() session = dom.wait_for_login() - session.cmd("mkfs.ext4 /dev/vdb && mount /dev/vdb /mnt && ls /mnt && " - "dd if=/dev/zero of=/mnt/test.img bs=1M count=50", ignore_all_errors=True) + disk_name, _ = get_non_root_disk_name(session) + session.cmd("mkfs.ext4 /dev/%s && mount /dev/%s /mnt && ls /mnt && " + "dd if=/dev/zero of=/mnt/test.img bs=1M count=50" + % (disk_name, disk_name), ignore_all_errors=True) time.sleep(5) session.close() expected_events_list.append("'io-error' for %s: " + "%s" % new_disk + r" \(virtio-disk1\) pause") @@ -710,8 +724,8 @@ def check_output(output, expected_events_list): if os.path.exists(dump_path): shutil.rmtree(dump_path) os.mkdir(dump_path) - if utils_misc.is_mounted("/dev/loop0", mount_point, part_format): - utils_misc.umount("/dev/loop0", mount_point, part_format) + if utils_misc.is_mounted(mount_device, mount_point, part_format): + utils_misc.umount(mount_device, mount_point, part_format) if os.path.exists(small_part): os.unlink(small_part) if os.path.exists(mount_point): diff --git a/libvirt/tests/src/features/ras.py b/libvirt/tests/src/features/ras.py new file mode 100644 index 00000000000..ed9af4a8502 --- /dev/null +++ b/libvirt/tests/src/features/ras.py @@ -0,0 +1,62 @@ +import logging + +from virttest import virsh +from virttest import libvirt_version +from virttest.libvirt_xml.vm_xml import VMXML +from virttest.utils_libvirt import libvirt_vmxml +from virttest.utils_test import libvirt + +LOG = logging.getLogger('avocado.' + __name__) + + +def run(test, params, env): + """ + Test the ras feature + 1. Enable 'ras=on/off' in a guest + 2. check the xml and qemu cmd line + """ + # Ras feature supported since 10.4.0. + libvirt_version.is_libvirt_feature_supported(params) + + ras_state = params.get("ras_state") + + def check_dumpxml(): + """ + Check whether the added devices are shown in the guest xml + """ + xpath = [{'element_attrs': [".//ras[@state='%s']" % ras_state]}] + # Check ras state + vm_xml = VMXML.new_from_dumpxml(vm_name) + libvirt_vmxml.check_guest_xml_by_xpaths(vm_xml, xpath) + + def check_qemu_cmd_line(): + """ + Check whether the ras feature is shown in the qemu cmd line + """ + pattern = r"-machine.*ras=%s" % ras_state + libvirt.check_qemu_cmd_line(pattern) + + vm_name = params.get("main_vm", "avocado-vt-vm1") + vm = env.get_vm(vm_name) + + vm_xml = VMXML.new_from_dumpxml(vm_name) + vm_xml_backup = vm_xml.copy() + LOG.debug("vm xml is %s", vm_xml_backup) + + if vm.is_alive(): + vm.destroy() + + try: + features_xml = vm_xml.features + if features_xml.has_feature('ras'): + features_xml.remove_feature('ras') + features_xml.ras = ras_state + vm_xml.features = features_xml + vm_xml.sync() + virsh.start(vm_name, ignore_status=False) + check_dumpxml() + check_qemu_cmd_line() + finally: + if vm.is_alive(): + virsh.destroy(vm_name) + vm_xml_backup.sync() diff --git a/libvirt/tests/src/gpu/hotplug_gpu.py b/libvirt/tests/src/gpu/hotplug_gpu.py new file mode 100644 index 00000000000..399ce693cde --- /dev/null +++ b/libvirt/tests/src/gpu/hotplug_gpu.py @@ -0,0 +1,56 @@ +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.gpu import gpu_base + + +def run(test, params, env): + """ + Hotplug/unplug GPU device + """ + vm_name = params.get("main_vm", "avocado-vt-vm1") + vm = env.get_vm(vm_name) + virsh_args = {'ignore_status': False, 'debug': True} + + gpu_test = gpu_base.GPUTest(vm, test, params) + hostdev_dict = gpu_test.parse_hostdev_dict() + + try: + gpu_test.setup_default() + test.log.info("TEST_STEP: Start the VM") + vm.start() + vm_session = vm.wait_for_login() + + test.log.info("TEST_STEP: Hotplug a gpu device to vm") + gpu_dev = libvirt_vmxml.create_vm_device_by_type("hostdev", hostdev_dict) + virsh.attach_device(vm.name, gpu_dev.xml, **virsh_args) + gpu_test.check_gpu_dev(vm) + test.log.debug(f'VMXML of {vm_name}:\n{virsh.dumpxml(vm_name).stdout_text}') + + gpu_test.install_latest_driver(vm_session) + gpu_test.nvidia_smi_check(vm_session) + + test.log.info("TEST_STEP: Unplug a gpu device from vm") + vm_hostdev = vm_xml.VMXML.new_from_dumpxml(vm.name)\ + .devices.by_device_tag("hostdev")[0] + virsh.detach_device(vm.name, vm_hostdev.xml, + wait_for_event=True, event_timeout=30, + **virsh_args) + gpu_test.check_gpu_dev(vm, True) + + test.log.info("TEST_STEP: Hotplug back the gpu device") + virsh.attach_device(vm.name, gpu_dev.xml, **virsh_args) + gpu_test.check_gpu_dev(vm) + gpu_test.nvidia_smi_check(vm_session) + + test.log.info("TEST_STEP: Check gpu device exclusivity") + res = virsh.attach_device(vm.name, gpu_dev.xml, debug=True) + libvirt.check_result(res, "in use") + gpu_test.check_gpu_dev(vm) + gpu_test.nvidia_smi_check(vm_session) + vm_session.close() + finally: + gpu_test.teardown_default() diff --git a/libvirt/tests/src/gpu/lifecycle_vm_with_gpu.py b/libvirt/tests/src/gpu/lifecycle_vm_with_gpu.py new file mode 100644 index 00000000000..5da774c641d --- /dev/null +++ b/libvirt/tests/src/gpu/lifecycle_vm_with_gpu.py @@ -0,0 +1,76 @@ +import os + +from virttest import data_dir +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.gpu import gpu_base + + +def run(test, params, env): + """ + Lifecycle test on vm with GPU device + """ + vm_name = params.get("main_vm", "avocado-vt-vm1") + vm = env.get_vm(vm_name) + virsh_args = {'ignore_status': False, 'debug': True} + unsupported_error = params.get("unsupported_error") + gpu_test = gpu_base.GPUTest(vm, test, params) + hostdev_dict = gpu_test.parse_hostdev_dict() + + try: + gpu_test.setup_default() + libvirt_vmxml.modify_vm_device( + vm_xml.VMXML.new_from_dumpxml(vm.name), "hostdev", + hostdev_dict) + test.log.info("TEST_STEP: Start the VM") + vm.start() + test.log.debug(f'VMXML of {vm_name}:\n{virsh.dumpxml(vm_name).stdout_text}') + gpu_test.check_gpu_dev(vm) + vm_session = vm.wait_for_login() + gpu_test.install_latest_driver(vm_session) + gpu_test.nvidia_smi_check(vm_session) + vm_session.close() + + test.log.info("TEST_STEP: Shudown and start VM") + virsh.shutdown(vm.name, **virsh_args, wait_for_event=True) + if not vm.wait_for_shutdown(): + test.error('VM failed to shutdown in 60s') + virsh.start(vm.name, **virsh_args) + gpu_test.check_gpu_dev(vm) + + test.log.info("TEST_STEP: Reboot VM") + virsh.reboot(vm.name, **virsh_args) + gpu_test.check_gpu_dev(vm) + + test.log.info("TEST_STEP: Reset VM") + virsh.reset(vm.name, **virsh_args) + gpu_test.check_gpu_dev(vm) + vm_session = vm.wait_for_login() + gpu_test.nvidia_smi_check(vm_session) + vm_session.close() + + test.log.info("TEST_STEP: Save the VM.") + save_path = os.path.join(data_dir.get_tmp_dir(), vm.name + '.save') + res = virsh.save(vm.name, save_path, debug=True) + libvirt.check_result(res, unsupported_error) + res = virsh.managedsave(vm.name, debug=True) + libvirt.check_result(res, unsupported_error) + res = virsh.snapshot_create(vm.name, debug=True) + libvirt.check_result(res, unsupported_error) + gpu_test.check_gpu_dev(vm) + + test.log.info("TEST_STEP: Suspend and resume the vm.") + virsh.suspend(vm.name, **virsh_args) + if not libvirt.check_vm_state(vm_name, "paused"): + test.fail("VM should be paused!") + virsh.resume(vm.name, **virsh_args) + if not libvirt.check_vm_state(vm_name, "running"): + test.fail("VM should be running!") + gpu_test.check_gpu_dev(vm) + + finally: + gpu_test.teardown_default() diff --git a/libvirt/tests/src/gpu/start_vm_with_gpu.py b/libvirt/tests/src/gpu/start_vm_with_gpu.py new file mode 100644 index 00000000000..4484615dc82 --- /dev/null +++ b/libvirt/tests/src/gpu/start_vm_with_gpu.py @@ -0,0 +1,49 @@ +from virttest import utils_misc +from virttest import virsh + +from virttest.libvirt_xml import vm_xml +from virttest.utils_libvirt import libvirt_vmxml +from virttest.utils_libvirt import libvirt_vfio + +from provider.gpu import gpu_base + + +def run(test, params, env): + """ + Start vm with GPU device + """ + + vm_name = params.get("main_vm", "avocado-vt-vm1") + vm = env.get_vm(vm_name) + gpu_test = gpu_base.GPUTest(vm, test, params) + dev_name = gpu_test.gpu_dev_name + dev_pci = gpu_test.gpu_pci + hostdev_dict = gpu_test.parse_hostdev_dict() + managed_disabled = hostdev_dict.get('managed') != "yes" + + try: + gpu_test.setup_default(dev_name=dev_name, + managed_disabled=managed_disabled) + libvirt_vmxml.modify_vm_device( + vm_xml.VMXML.new_from_dumpxml(vm.name), "hostdev", + hostdev_dict) + test.log.info("TEST_STEP: Start the VM") + vm.start() + test.log.debug(f'VMXML of {vm_name}:\n{virsh.dumpxml(vm_name).stdout_text}') + gpu_test.check_gpu_dev(vm) + libvirt_vfio.check_vfio_pci(dev_pci) + + test.log.info("TEST_STEP: Destroy VM") + vm.destroy(gracefully=False) + + if not utils_misc.wait_for( + lambda: libvirt_vfio.check_vfio_pci( + dev_pci, not managed_disabled, True), 10, 5): + test.fail("Got incorrect driver!") + if managed_disabled: + virsh.nodedev_reattach(dev_name, debug=True, ignore_status=False) + libvirt_vfio.check_vfio_pci(dev_pci, True) + finally: + gpu_test.teardown_default( + managed_disabled=managed_disabled, + dev_name=dev_name) diff --git a/libvirt/tests/src/gpu/start_vm_with_gpu_managed_disabled.py b/libvirt/tests/src/gpu/start_vm_with_gpu_managed_disabled.py new file mode 100644 index 00000000000..ff222b27a5b --- /dev/null +++ b/libvirt/tests/src/gpu/start_vm_with_gpu_managed_disabled.py @@ -0,0 +1,38 @@ +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.gpu import gpu_base + + +def run(test, params, env): + """ + Start vm with GPU device with managed=no or ignored + """ + error_msg = params.get("error_msg", "Unmanaged") + test_scenario = params.get("test_scenario") + vm_name = params.get("main_vm", "avocado-vt-vm1") + vm = env.get_vm(vm_name) + gpu_test = gpu_base.GPUTest(vm, test, params) + hostdev_dict = gpu_test.parse_hostdev_dict() + + try: + gpu_test.setup_default() + if test_scenario == "define_start": + test.log.info("TEST_STEP: Start the VM") + libvirt_vmxml.modify_vm_device( + vm_xml.VMXML.new_from_dumpxml(vm.name), "hostdev", + hostdev_dict) + res = virsh.start(vm.name, debug=True) + else: + test.log.info("TEST_STEP: Hotplug a gpu device") + vm.start() + vm.wait_for_login().close() + gpu_dev = libvirt_vmxml.create_vm_device_by_type("hostdev", hostdev_dict) + res = virsh.attach_device(vm.name, gpu_dev.xml, debug=True) + libvirt.check_result(res, error_msg) + + finally: + gpu_test.teardown_default() diff --git a/libvirt/tests/src/gpu/vm_cuda_sanity.py b/libvirt/tests/src/gpu/vm_cuda_sanity.py new file mode 100644 index 00000000000..e1269e84e17 --- /dev/null +++ b/libvirt/tests/src/gpu/vm_cuda_sanity.py @@ -0,0 +1,50 @@ +import os + +from virttest import virsh + +from virttest.libvirt_xml import vm_xml +from virttest.utils_libvirt import libvirt_vmxml + +from provider.gpu import gpu_base + + +def run(test, params, env): + """ + cuda sanity tests in guest + """ + vm_name = params.get("main_vm", "avocado-vt-vm1") + vm = env.get_vm(vm_name) + cuda_tests = eval(params.get("cuda_tests", "[]")) + gpu_test = gpu_base.GPUTest(vm, test, params) + hostdev_dict = gpu_test.parse_hostdev_dict() + + try: + gpu_test.setup_default() + libvirt_vmxml.modify_vm_device( + vm_xml.VMXML.new_from_dumpxml(vm.name), "hostdev", + hostdev_dict) + test.log.info("TEST_STEP: Start the VM") + vm.start() + vm_session = vm.wait_for_login() + test.log.debug(f'VMXML of {vm_name}:\n{virsh.dumpxml(vm_name).stdout_text}') + cuda_samples_path = params.get("cuda_samples_path") + cuda_sample_guest_path = os.path.join("/tmp", os.path.basename(cuda_samples_path)) + vm_session.cmd(f"wget {cuda_samples_path} -O {cuda_sample_guest_path}") + vm_session.cmd(f"tar -xf {cuda_sample_guest_path} -C /root") + vm_session.cmd(f"rm -rf {cuda_sample_guest_path}") + + test.log.info("TEST_STEP: Install the driver") + gpu_test.install_latest_driver(vm_session) + gpu_test.install_cuda_toolkit(vm_session) + gpu_test.nvidia_smi_check(vm_session) + + test.log.info("TEST_STEP: Run cuda sanity tests") + for s_test in cuda_tests: + test.log.debug(f"TEST_STEP: Run {s_test}") + s, o = vm_session.cmd_status_output(s_test, timeout=600) + test.log.debug(f"output: {o}") + if s: + test.fail("Failed to run cuda sanity - %s" % s_test) + + finally: + gpu_test.teardown_default() diff --git a/libvirt/tests/src/gpu/vm_mig_sanity.py b/libvirt/tests/src/gpu/vm_mig_sanity.py new file mode 100644 index 00000000000..6d02e4eb25d --- /dev/null +++ b/libvirt/tests/src/gpu/vm_mig_sanity.py @@ -0,0 +1,77 @@ +import os +import re + +from virttest import virsh + +from virttest.libvirt_xml import vm_xml +from virttest.utils_libvirt import libvirt_vmxml + +from provider.gpu import gpu_base + + +def run(test, params, env): + """ + MIG sanity test in vm with GPU device + """ + vm_name = params.get("main_vm", "avocado-vt-vm1") + vm = env.get_vm(vm_name) + cuda_test = params.get("cuda_test") + + gpu_test = gpu_base.GPUTest(vm, test, params) + hostdev_dict = gpu_test.parse_hostdev_dict() + + try: + gpu_test.setup_default() + libvirt_vmxml.modify_vm_device( + vm_xml.VMXML.new_from_dumpxml(vm.name), "hostdev", + hostdev_dict) + test.log.info("TEST_STEP: Start the VM") + vm.start() + vm_session = vm.wait_for_login() + test.log.debug(f'VMXML of {vm_name}:\n{virsh.dumpxml(vm_name).stdout_text}') + + test.log.info("TEST_STEP: Copy the sample") + guest_gpu_pci = gpu_base.get_gpu_pci(vm_session) + cuda_samples_path = params.get("cuda_samples_path") + cuda_sample_guest_path = os.path.join("/tmp", os.path.basename(cuda_samples_path)) + vm_session.cmd(f"wget {cuda_samples_path} -O {cuda_sample_guest_path}") + vm_session.cmd(f"tar -xf {cuda_sample_guest_path} -C /root") + vm_session.cmd(f"rm -rf {cuda_sample_guest_path}") + + test.log.info("TEST_STEP: Install the driver") + gpu_test.install_latest_driver(vm_session, True) + gpu_test.install_cuda_toolkit(vm_session, True) + + test.log.info("TEST_STEP: Enable MIG mode") + vm_session.cmd(f"nvidia-smi -i {guest_gpu_pci} -mig 1") + output = vm_session.cmd_output(f"nvidia-smi -i {guest_gpu_pci} --query-gpu=pci.bus_id,mig.mode.current --format=csv,noheader") + if "Enabled" not in output: + test.fail("Failed to enable MIG mode!") + + test.log.info("TEST_STEP: Create GPU instances ") + vm_session.cmd(f"nvidia-smi mig -cgi 4g.20gb,2g.10gb,1g.5gb -C") + res = vm_session.cmd_output_safe("nvidia-smi -L") + compute_instances = re.findall(r"Device .(\d).*UUID: (.*)\)", res) + if not compute_instances: + test.fail("Failed to get compute instances!") + for dev in compute_instances: + s, o = vm_session.cmd_status_output(f"CUDA_VISIBLE_DEVICES={dev[1]} {cuda_test}") + test.log.debug(f"dev: {dev[1]}, output of BlackScholes: {o}") + if s: + test.fail("Failed to run BlackScholes test!") + + test.log.info("TEST_STEP: Destroy the GPU instances") + res = vm_session.cmd_output_safe("nvidia-smi mig -lci | awk '/MIG/ {print $2, $3}'") + for line in res.splitlines(): + if line: + ids = line.split() + test.log.debug(f"Destroy instance - {ids}") + vm_session.cmd(f"nvidia-smi mig -dci -ci {ids[0]} -gi {ids[1]}") + + test.log.info("TEST_STEP: Disable MIG mode") + vm_session.cmd(f"nvidia-smi -i {guest_gpu_pci} -mig 0") + output = vm_session.cmd_output(f"nvidia-smi -i {guest_gpu_pci} --query-gpu=pci.bus_id,mig.mode.current --format=csv,noheader") + if "Disabled" not in output: + test.fail("Failed to disable MIG mode!") + finally: + gpu_test.teardown_default() diff --git a/libvirt/tests/src/gpu/vm_nvidia_gpu_driver.py b/libvirt/tests/src/gpu/vm_nvidia_gpu_driver.py new file mode 100644 index 00000000000..f1f7dd78e12 --- /dev/null +++ b/libvirt/tests/src/gpu/vm_nvidia_gpu_driver.py @@ -0,0 +1,40 @@ +from virttest import virsh + +from virttest.libvirt_xml import vm_xml +from virttest.utils_libvirt import libvirt_vmxml + +from provider.gpu import gpu_base + + +def run(test, params, env): + """ + GPU driver installation/uninstallation/re-installation on vm with GPU device + """ + vm_name = params.get("main_vm", "avocado-vt-vm1") + vm = env.get_vm(vm_name) + gpu_test = gpu_base.GPUTest(vm, test, params) + + hostdev_dict = gpu_test.parse_hostdev_dict() + + try: + gpu_test.setup_default() + libvirt_vmxml.modify_vm_device( + vm_xml.VMXML.new_from_dumpxml(vm.name), "hostdev", + hostdev_dict) + test.log.info("TEST_STEP: Start the VM") + vm.start() + vm_session = vm.wait_for_login() + test.log.debug(f'VMXML of {vm_name}:\n{virsh.dumpxml(vm_name).stdout_text}') + + test.log.info("TEST_STEP: Install the driver") + gpu_test.install_latest_driver(vm_session) + gpu_test.nvidia_smi_check(vm_session) + + test.log.info("TEST_STEP: Uninstall the driver") + vm_session.cmd("dnf module -y remove --all nvidia-driver", timeout=600) + + test.log.info("TEST_STEP: Re-install the driver") + gpu_test.install_latest_driver(vm_session) + gpu_test.nvidia_smi_check(vm_session) + finally: + gpu_test.teardown_default() diff --git a/libvirt/tests/src/graphics/graphics_functional.py b/libvirt/tests/src/graphics/graphics_functional.py index 4248179e0dd..7e81cdaf013 100644 --- a/libvirt/tests/src/graphics/graphics_functional.py +++ b/libvirt/tests/src/graphics/graphics_functional.py @@ -13,10 +13,7 @@ import locale import base64 import ipaddress -try: - import queue as Queue -except ImportError: - import Queue +import queue import stat @@ -39,7 +36,7 @@ from virttest.utils_test import libvirt -q = Queue.Queue() +q = queue.Queue() # Using as lower capital is not the best way to do, but this is just a @@ -209,7 +206,7 @@ def __init__(self, params, expected_result): self.qemu_config.vnc_tls_x509_verify = tls_x509_verify if vnc_tls_x509_secret_uuid == "not_set": - del self.qemu_config.vnc_tls_x509_verify + del self.qemu_config.vnc_tls_x509_secret_uuid else: self.qemu_config.vnc_tls = "1" if vnc_secret_uuid == "invalid": @@ -989,10 +986,11 @@ def check_qemu_command_line(params): :param params: dict for parameters """ check_qemu_pattern = params.get('check_qemu_pattern') + expect_exist = eval(params.get('expect_exist', 'True')) if check_qemu_pattern: logging.debug("Checking qemu command line with " "pattern:%s", check_qemu_pattern) - libvirt.check_qemu_cmd_line(check_qemu_pattern) + libvirt.check_qemu_cmd_line(check_qemu_pattern, expect_exist=expect_exist) def handle_auto_filled_items(given_graphic_attrs, vm, params): @@ -1006,6 +1004,8 @@ def handle_auto_filled_items(given_graphic_attrs, vm, params): """ vnc_listen_address = params.get("vnc_listen_address") vnc_listen_type = params.get("vnc_listen_type") + vnc_port = params.get("vnc_port") + if vnc_listen_address == '': given_graphic_attrs['listen_attrs'].update({'address': '127.0.0.1'}) elif vnc_listen_address == 'none': @@ -1018,6 +1018,14 @@ def handle_auto_filled_items(given_graphic_attrs, vm, params): given_graphic_attrs['listen_attrs'].update({'address': utils_net.get_host_ip_address()}) elif vnc_network_type == 'vnet': given_graphic_attrs['listen_attrs'].update({'address': params.get('vnet_address')}) + elif vnc_listen_type == 'not_exist': + given_graphic_attrs.update({'listen_attrs': {'type': 'address'}}) + + if vnc_port and vnc_port == '0': + del given_graphic_attrs['port'] + given_graphic_attrs.update({'listen_attrs': {'type': 'address'}}) + if vnc_port and vnc_port == '65536': + given_graphic_attrs.update({'listen_attrs': {'type': 'address'}}) return given_graphic_attrs @@ -1452,7 +1460,7 @@ def check_xml(vm_name, filetransfer, test): test.fail('The attribute of filetransfer error.') -def check_domdisplay_result(graphic_type, vm_name, expected_result, test): +def check_domdisplay_result(graphic_type, vm_name, expected_result, test, options="", passwd=None): """ Check domdisplay result @@ -1460,8 +1468,10 @@ def check_domdisplay_result(graphic_type, vm_name, expected_result, test): :param vm_name: name of the VM domain :param expected_result: expected result :param test: test object + :param options: domdisplay options + :param passwd: graphic password """ - domdisplay_out = virsh.domdisplay(vm_name, debug=True) + domdisplay_out = virsh.domdisplay(vm_name, options=options, debug=True) if domdisplay_out.exit_status: test.fail("Fail to get domain display info. Error:" "%s." % domdisplay_out.stderr.strip()) @@ -1472,8 +1482,10 @@ def check_domdisplay_result(graphic_type, vm_name, expected_result, test): if expected_result['spice_tls_port'] != 'not_set': expected_uri += "?tls-port=%s" % expected_result['spice_tls_port'] if graphic_type == 'vnc': + if "include-password" in options: + expected_uri += ":%s@" % passwd expected_uri += "%s:" % expected_result['vnc_options']['addr'] - expected_uri += "%s" % expected_result['vnc_port'] + expected_uri += "%s" % str(int(expected_result['vnc_port']) - 5900) if domdisplay_out.stdout.strip() != expected_uri: test.fail("Use domdisplay to check URI failed. Expected uri: %s" % expected_uri) @@ -1580,6 +1592,17 @@ def cleanup(params): libvirtd.restart() +def is_enable_fips(): + """ + Check FIPS status + + :param return: True or False, True for enable FIPS + """ + cmd = "cat /proc/sys/crypto/fips_enabled" + ret = process.run(cmd, shell=True) + return True if ret.stdout_text.strip() else False + + def run(test, params, env): """ Test of libvirt SPICE related features. @@ -1637,6 +1660,12 @@ def run(test, params, env): insecure_channels = params.get("insecure_channels", "not_set") autoport = params.get("spice_autoport", "yes") spice_tls = params.get("spice_tls", "not_set") + check_fips = params.get("check_fips", "no") == 'yes' + check_with_domdisplay = params.get("check_with_domdisplay", "no") == 'yes' + + if check_fips: + if not is_enable_fips(): + test.cancel("This test need to disable FIPS.") sockets = block_ports(params) networks = setup_networks(params, test) @@ -1700,25 +1729,28 @@ def run(test, params, env): if spice_listen_type == "network" or vnc_listen_type == "network": for ip in all_ips: ip.addr = ipaddress.ip_address(ip.addr).compressed - try: - logging.debug("Before starting, vm xml:\n%s", VMXML.new_from_dumpxml(vm_name)) - vm.start() - logging.debug("After starting, vm xml:\n%s", VMXML.new_from_dumpxml(vm_name)) - except virt_vm.VMStartError as detail: - if not fail_patts: - test.fail( - "Expect VM can be started, but failed with: %s" % detail) - for patt in fail_patts: - if re.search(patt, str(detail)): - return - test.fail( - "Expect fail with error in %s, but failed with: %s" - % (fail_patts, detail)) - else: - if fail_patts: + + logging.debug("Before starting, vm xml:\n%s", VMXML.new_from_dumpxml(vm_name)) + if vnc_listen_type != "not_exist": + try: + vm.start() + logging.debug("After starting, vm xml:\n%s", VMXML.new_from_dumpxml(vm_name)) + except virt_vm.VMStartError as detail: + compare_guest_xml(vnc_graphic, vm, params, test) + if not fail_patts: + test.fail( + "Expect VM can be started, but failed with: %s" % detail) + for patt in fail_patts: + if re.search(patt, str(detail)): + return test.fail( - "Expect VM can't be started with %s, but started." - % fail_patts) + "Expect fail with error in %s, but failed with: %s" + % (fail_patts, detail)) + else: + if fail_patts: + test.fail( + "Expect VM can't be started with %s, but started." + % fail_patts) if spice_xml: spice_opts, plaintext_channels, tls_channels = qemu_spice_options(vm) @@ -1746,6 +1778,10 @@ def run(test, params, env): check_qemu_command_line(params) vnc_opts = qemu_vnc_options(vm, params) check_vnc_result(vnc_opts, expected_result, all_ips, test) + if check_with_domdisplay: + domdisplay_options = params.get("domdisplay_options", "") + check_domdisplay_result('vnc', vm_name, expected_result, test, + options=domdisplay_options, passwd=graphic_passwd) if params.get("hook_path"): test_passwd_hook(params, vm, test) diff --git a/libvirt/tests/src/guest_agent/guest_agent.py b/libvirt/tests/src/guest_agent/guest_agent.py index 6246ca03339..83c43545455 100644 --- a/libvirt/tests/src/guest_agent/guest_agent.py +++ b/libvirt/tests/src/guest_agent/guest_agent.py @@ -91,10 +91,12 @@ def run(test, params, env): label = params.get("con_label") vm = env.get_vm(vm_name) + socket_file_dir_created = False if src_path: socket_file_dir = os.path.dirname(src_path) if not os.path.exists(socket_file_dir): os.mkdir(socket_file_dir) + socket_file_dir_created = True shutil.chown(socket_file_dir, "qemu", "qemu") utils_selinux.set_context_of_file(filename=socket_file_dir, context=label) @@ -142,3 +144,5 @@ def run(test, params, env): finally: vm.destroy() backup_xml.sync() + if socket_file_dir_created and os.path.exists(socket_file_dir): + os.rmdir(socket_file_dir) diff --git a/libvirt/tests/src/guest_agent/unix_source_path/agent_auto_generated_unix_source_path_session_mode.py b/libvirt/tests/src/guest_agent/unix_source_path/agent_auto_generated_unix_source_path_session_mode.py new file mode 100644 index 00000000000..5f2890f4f01 --- /dev/null +++ b/libvirt/tests/src/guest_agent/unix_source_path/agent_auto_generated_unix_source_path_session_mode.py @@ -0,0 +1,110 @@ +import pwd +import os + +from virttest import libvirt_version +from virttest import remote +from virttest import utils_misc +from virttest import virsh + +from virttest.libvirt_xml import vm_xml +from virttest.utils_libvirt import libvirt_unprivileged + + +def run(test, params, env): + """ + This case is to verify that if the source path of guest agent is not + specified in session mode, it will be set automatically by libvirt, + and the path matches certain pattern. + """ + def check_src_path(domid, vm_name, dir_name, chn_dir, tgt_name, + max_dir_length, cmp_path=None): + """Check the source path + + :param domid: domain id + :param vm_name: vm name + :param dir_name: directory name + :param chn_dir: libvirt dir for channel + :param tgt_name: target name + :param max_dir_length: max directory length + :param cmp_path: the path to compare, defaults to None + """ + vm_info = f"{domid}-{vm_name}" + tmp_path = os.path.join(dir_name, chn_dir, vm_info, tgt_name) + if cmp_path and tmp_path != cmp_path: + test.fail(f"The channel device's source path should be {tmp_path} " + f"but got {cmp_path}") + if len(tmp_path) > max_dir_length: + test.fail(f"The length of source path '{tmp_path}' should not " + f"exceed {max_dir_length}.") + + libvirt_version.is_libvirt_feature_supported(params) + + chn_dir = params.get("chn_dir", "libvirt/qemu/run/channel") + kube_dir = params.get("kube_dir", "/var/run/kubevirt-private") + max_dir_length = int(params.get("max_dir_length", "107")) + new_vm_name = 'vm' + utils_misc.generate_random_string(22) + test_passwd = params.get('test_passwd', '') + test_user = params.get('test_user', '') + tgt_name = params.get("tgt_name", "org.qemu.guest_agent.0") + up_domid = params.get("up_domid", "2147483647") + vm_name = params.get('unpr_vm_name') + + runtime_dir = remote.RemoteRunner( + username=test_user, password=test_passwd, host='localhost').run( + 'echo $XDG_RUNTIME_DIR').stdout_text.strip() + if not runtime_dir: + runtime_dir = os.path.join(pwd.getpwnam(test_user).pw_dir, '.cache') + + unpr_vm_args = {'username': params.get('username'), + 'password': params.get('password')} + vm = libvirt_unprivileged.get_unprivileged_vm(vm_name, test_user, + test_passwd, + **unpr_vm_args) + virsh_ins = virsh.Virsh(uri=vm.connect_uri) + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml( + vm_name, virsh_instance=virsh_ins) + backup_xml = vmxml.copy() + try: + test.log.info("TEST_STEP: Create a vm in session mode.") + if vm.is_alive(): + vm.destroy() + virsh_ins.domrename( + vm.name, new_vm_name, debug=True, ignore_status=False) + vm_new = libvirt_unprivileged.get_unprivileged_vm( + new_vm_name, test_user, test_passwd, **unpr_vm_args) + + test.log.info("TEST_STEP: Prepare guest agent.") + vm_new.prepare_guest_agent(serial=True) + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml( + new_vm_name, virsh_instance=virsh_ins) + test.log.debug(f"vmxml after updating: {vmxml}") + inactive_src = vmxml.devices.by_device_tag( + "channel")[0].fetch_attrs().get('sources') + if inactive_src and inactive_src[0]['attrs'].get('path'): + test.fail( + "There should be no specified path in inactive domain xml.") + + test.log.info("TEST_STEP: Execute a guest agent command.") + virsh_ins.domtime(new_vm_name, debug=True, ignore_status=False) + + test.log.info("TEST_STEP: Execute a guest agent command.") + vmxml = vm_xml.VMXML.new_from_dumpxml( + new_vm_name, virsh_instance=virsh_ins) + + test.log.info("TEST_STEP: Check the guest agent socket path.") + chn_obj = vmxml.devices.by_device_tag("channel")[0] + test.log.debug(f"channel xml: {chn_obj}") + src_path = chn_obj.fetch_attrs()['sources'][0]['attrs']['path'] + check_src_path(virsh_ins.domid(new_vm_name).stdout_text.strip(), + vm_new.name[:20], runtime_dir, chn_dir, tgt_name, + max_dir_length, cmp_path=src_path) + + test.log.info("TEST_STEP: Check the length of the socket path " + "which will be used in cnv.") + check_src_path(up_domid, vm_new.name[:20], kube_dir, chn_dir, tgt_name, + max_dir_length) + + finally: + vm_new.destroy() + virsh_ins.domrename(vm_new.name, vm.name, debug=True) + backup_xml.sync(virsh_instance=virsh_ins) diff --git a/libvirt/tests/src/guest_kernel_debugging/guest_kdump.py b/libvirt/tests/src/guest_kernel_debugging/guest_kdump.py new file mode 100644 index 00000000000..c64e5a8e9b6 --- /dev/null +++ b/libvirt/tests/src/guest_kernel_debugging/guest_kdump.py @@ -0,0 +1,306 @@ +import time +import threading +import logging as log + +from virttest import utils_test +from virttest import virsh +from virttest.libvirt_xml import vm_xml +from aexpect.exceptions import ShellProcessTerminatedError +from aexpect.exceptions import ShellTimeoutError + + +# Using as lower capital is not the best way to do, but this is just a +# workaround to avoid changing the entire file. +logging = log.getLogger('avocado.' + __name__) + + +def run(test, params, env): + """ + Test: Kdump of guest + + param test: kvm test object + param params: Dictionary with the test parameters + param env: Dictionary with test environment. + + This script is used to test the kdump functionality of the guest(s). + 1. Check if kdump.service is operational + 2. Get the vm-cores present in the guest + 3. Load the stress app if specified + 4. Trigger crash simultaneously in all guests + 5. Debug vm-core using crash utility if specified + """ + vms = env.get_all_vms() + guest_stress = params.get("guest_stress", "no") == "yes" + guest_upstream_kernel = params.get("guest_upstream_kernel", "no") == "yes" + crash_utility = params.get("crash_utility", "no") == "yes" + stress_time = params.get("stress_time", "30") + crash_dir = params.get("crash_dir", "/var/crash/") + debug_dir = params.get("debug_dir", "/home/") + dump_options = params.get("dump_options", "--memory-only --bypass-cache") + trigger_crash_cmd = "echo c > /proc/sysrq-trigger" + + def check_kdump_service(vm): + """ + Check if kdump.service is running + Current supported Distros: rhel, fedora, ubuntu + + param vm: vm object + returns: None + """ + # Set command based on different distros + logging.info("Checking for kdump.service in guest %s" % vm.name) + session = vm.wait_for_login(timeout=240) + distro_details = session.cmd("cat /etc/os-release").lower() + check_kdump_cmd = "" + if "fedora" in distro_details or "rhel" in distro_details: + check_kdump_cmd = "kdumpctl status" + elif "ubuntu" in distro_details: + check_kdump_cmd = "kdump-config status" + else: + test.cancel("Guest distro not supported") + + # Check the kdump.service status + check_kdump_status, check_kdump = session.cmd_status_output(check_kdump_cmd) + if check_kdump_status: + logging.debug("Kdump service status: %s" % check_kdump) + test.error("Kdump service is not running in guest %s" % vm.name) + logging.info("Kdump service is up and running:\n%s" % check_kdump) + session.close() + + def get_vmcores(vm): + """ + Get vm-cores present in the crash directory + + param vm: vm object + returns: list of vm-cores + """ + logging.info("Getting vmcores in the guest %s" % vm.name) + session = vm.wait_for_login(timeout=100) + get_vmcores_cmd = "ls " + crash_dir + vmcores = session.cmd(get_vmcores_cmd).split() + session.close() + return vmcores + + def check_guest_status(vm): + """ + Check guest domstate. Guest should be running at all times. + + param vm: vm object + returns: + 1. 0 if guest is running + 2. 1 if guest is not running + """ + logging.info("Checking domstate of guest %s" % vm.name) + if vm.state() != "running": + logging.debug("Domain is not running: %s" % vm.state()) + return 1 + return 0 + + def trigger_crash(vm, session): + """ + Trigger sysrq triggered crash in guest + + param vm: vm object + param session: session object + returns: None + """ + logging.info("Triggering sysrq crash in guest %s" % vm.name) + try: + session.cmd(trigger_crash_cmd) + except ShellProcessTerminatedError: + time.sleep(120) + session.close() + + def load_guest_stress(vms): + """ + Load stress app in all the vms + + param vms: all vm objects + returns: None + """ + logging.info("Starting stress app in guest(s)") + try: + utils_test.load_stress("stress_in_vms", params=params, vms=vms) + except Exception as err: + test.fail("Error running stress in vms: %s" % str(err)) + + def unload_guest_stress(vms): + """ + Unload stress app in all the vms + + param vms: all vm objects + returns: None + """ + logging.info("Stopping stress app in guest(s)") + utils_test.unload_stress("stress_in_vms", params=params, vms=vms) + + def virsh_dump(failed_vms): + """ + Take virsh dump of guest in case of guest failure + + param failed_vms: vm objects which are failed/broken + returns: None + """ + logging.info("Dumping failed vms to directory %s" % debug_dir) + for vm in failed_vms: + if vm.state() != "shut off": + logging.debug("Dumping %s to debug_dir %s" % (vm.name, debug_dir)) + virsh.dump(vm.name, debug_dir+vm.name+"-core", + dump_options, ignore_status=False, + debug=True) + logging.debug("Successfully dumped %s as %s-core" % (vm.name, vm.name)) + else: + logging.debug("Cannot dump %s as it is in shut off state" % vm.name) + + def crash_utility_tool(vm, vmcore): + """ + Check the working of crash utility tool to analyse the guest dump + Current supported Distros: rhel, fedora, ubuntu + + param vm: vm object + param vm-core: guest vm-core file + returns: None + """ + logging.info("Debugging %s vmcore using crash utility" % vm.name) + session = vm.wait_for_login(timeout=100) + debug_libraries = [] + vmcore_file = crash_dir + vmcore + "/vmcore" + distro_details = session.cmd("cat /etc/os-release").lower() + guest_kernel = session.cmd("uname -r").strip() + + # Get required debug libraries based on distros + if "fedora" in distro_details or "rhel" in distro_details: + debug_libraries = ["*kexec-tools*", "*elfutils*", "*crash*", "*kdump-utils*"] + if not guest_upstream_kernel: + debug_libraries.append("*kernel-debuginfo*") + elif "ubuntu" in distro_details: + debug_libraries = ["*linux-crashdump*", "*kdump-tools*", "*crash*", "*elfutils*"] + else: + test.cancel("Guest distro not supported") + + # Check if required debug libraries are installed + not_installed_libs = set() + for library in debug_libraries: + get_library_cmd = "rpm -qa " + library + output = session.cmd(get_library_cmd).split() + if not output: + not_installed_libs.add(library) + if not_installed_libs: + test.error("Debug libraries not installed in %s: %s" % (vm.name, not_installed_libs)) + session.close() + + # Get debug kernel location based on distros + if "fedora" in distro_details or "rhel" in distro_details: + vmlinux = "/usr/lib/debug/lib/modules/" + guest_kernel + "/vmlinux" + elif "ubuntu" in distro_details: + vmlinux = "/usr/lib/debug/boot/vmlinux-" + guest_kernel + else: + test.cancel("Guest distro not supported") + if guest_upstream_kernel: + vmlinux = params.get("upstream_kernel_vmlinux", vmlinux) + + # Run the crash utility tool + session = vm.wait_for_login(timeout=100) + crash_cmd = f"crash {vmlinux} {vmcore_file}" + crash_log = "" + logging.debug("Crash command: %s", crash_cmd) + try: + session.cmd(crash_cmd) + except ShellTimeoutError: + crash_log = session.get_output() + session.close() + + logging.debug("Crash utility output: %s" % crash_log) + if "PID" not in crash_log or "crash>" not in crash_log: + test.fail("Failed to debug %s vmcore using crash utiility" % vm.name) + + # Declaring variables before starting test + failed_vms = set() + virsh_dump_vms = set() + + # Set on_crash value to preserve in guests + for vm in vms: + logging.info("Setting on_crash to preserve in %s" % vm.name) + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm.name) + if vm.is_alive(): + vm.destroy(gracefully=False) + vmxml.on_crash = "restart" + vmxml.sync() + vm.start() + + # Check for kdump service if it is operational + for vm in vms: + check_kdump_service(vm) + + # Check for the present vm-cores in guests + pre_vmcores = {} + for vm in vms: + pre_vmcores[vm.name] = get_vmcores(vm) + logging.info("%s vmcores before crash: %s" % (vm.name, pre_vmcores[vm.name])) + + # Load the stress app + if guest_stress: + load_guest_stress(vms) + logging.info("Started running stress app") + logging.info("Sleeping for %s seconds" % stress_time) + time.sleep(int(stress_time)) + + for vm in vms: + if check_guest_status(vm): + failed_vms.add(vm.name) + virsh_dump_vms.add(vm) + if failed_vms: + virsh_dump(virsh_dump_vms) + test.fail("Guest %s not running after running stress" % failed_vms) + + # Trigger crash in guests in parallel + kdump_threads = [] + for vm in vms: + kdump_threads.append( + threading.Thread(target=trigger_crash, args=(vm, vm.wait_for_login(timeout=100))) + ) + time.sleep(20) + for kdump_thread in kdump_threads: + kdump_thread.start() + for kdump_thread in kdump_threads: + kdump_thread.join() + + # Check guest status after crash + for vm in vms: + try: + if check_guest_status(vm): + raise Exception("Guest %s not running after triggering crash" % vm.name) + session = vm.wait_for_login(timeout=240) + logging.info("Able to login into %s" % vm.name) + session.close() + except Exception as err: + logging.debug("Error occured %s" % str(err)) + failed_vms.add(vm.name) + virsh_dump_vms.add(vm) + if failed_vms: + virsh_dump(virsh_dump_vms) + test.fail("Unable to login into %s after triggering crash" % failed_vms) + + # Check for the vm-cores in guests after crash + post_vmcores = {} + for vm in vms: + post_vmcores[vm.name] = get_vmcores(vm) + logging.info("%s vmcores after crash: %s" % (vm.name, post_vmcores[vm.name])) + + # Check if vm-core got generated after crash in guests + for vm in vms: + if len(post_vmcores[vm.name]) <= len(pre_vmcores[vm.name]): + failed_vms.add(vm.name) + if failed_vms: + test.fail("vmcore not generated in %s" % failed_vms) + + # Debug vm-core using crash utility tool + if crash_utility: + for vm in vms: + for vmcore_file in pre_vmcores[vm.name]: + post_vmcores[vm.name].remove(vmcore_file) + crash_utility_tool(vm, post_vmcores[vm.name][-1]) + + # Unload the stress app in guests + if guest_stress: + unload_guest_stress(vms) diff --git a/libvirt/tests/src/guest_kernel_debugging/nmi_test.py b/libvirt/tests/src/guest_kernel_debugging/nmi_test.py index 1727689d787..95644515306 100644 --- a/libvirt/tests/src/guest_kernel_debugging/nmi_test.py +++ b/libvirt/tests/src/guest_kernel_debugging/nmi_test.py @@ -77,6 +77,7 @@ def run(test, params, env): expected_nmi_times = params.get("expected_nmi_times", '0') kernel_params = params.get("kernel_params", "") unprivileged_user = params.get('unprivileged_user') + check_qemu_monitor = "yes" == params.get("check_qemu_monitor", "yes") if unprivileged_user: if unprivileged_user.count('EXAMPLE'): unprivileged_user = 'testacl' @@ -115,8 +116,9 @@ def run(test, params, env): logging.info("Inject NMI to the guest via virsh inject_nmi") virsh.inject_nmi(vm_name, debug=True, ignore_status=False) - logging.info("Inject NMI to the guest via virsh qemu_monitor_command") - virsh.qemu_monitor_command(vm_name, '{"execute":"inject-nmi"}') + if check_qemu_monitor: + logging.info("Inject NMI to the guest via virsh qemu_monitor_command") + virsh.qemu_monitor_command(vm_name, '{"execute":"inject-nmi"}') # injects a Non-Maskable Interrupt into the default CPU (x86/s390) # or all CPUs (ppc64), as usual, the default CPU index is 0 diff --git a/libvirt/tests/src/virsh_cmd/domain/virsh_dump.py b/libvirt/tests/src/guest_kernel_debugging/virsh_dump.py similarity index 56% rename from libvirt/tests/src/virsh_cmd/domain/virsh_dump.py rename to libvirt/tests/src/guest_kernel_debugging/virsh_dump.py index dedc78ef2c7..a381735f56c 100644 --- a/libvirt/tests/src/virsh_cmd/domain/virsh_dump.py +++ b/libvirt/tests/src/guest_kernel_debugging/virsh_dump.py @@ -4,15 +4,21 @@ import time import platform import re +import pexpect from avocado.utils import process +from avocado.utils.software_manager.manager import SoftwareManager +from avocado.utils import distro from virttest import virsh from virttest import utils_libvirtd from virttest import utils_config from virttest import data_dir +from virttest import utils_misc from virttest import utils_package from virttest.libvirt_xml import vm_xml +from virttest.utils_libvirt import libvirt_disk +from virttest.utils_test import libvirt from provider import libvirt_version @@ -36,6 +42,7 @@ def run(test, params, env): 2.1 Dump domain to a non-exist directory. 2.2 Dump domain with invalid option. 2.3 Dump a shut-off domain. + 2.4 Dump onto directory that's too small. """ vm_name = params.get("main_vm", "vm1") @@ -46,6 +53,7 @@ def run(test, params, env): if os.path.dirname(dump_file) is "": dump_file = os.path.join(dump_dir, dump_file) dump_image_format = params.get("dump_image_format") + small_img = os.path.join(data_dir.get_tmp_dir(), "small.img") start_vm = params.get("start_vm") == "yes" paused_after_start_vm = params.get("paused_after_start_vm") == "yes" status_error = params.get("status_error", "no") == "yes" @@ -132,6 +140,7 @@ def check_domstate(actual, options): Check the domain status according to dump options. """ + logging.debug("Actual VM status is %s", actual) if options.find('live') >= 0: domstate = "running" if options.find('crash') >= 0 or options.find('reset') > 0: @@ -183,13 +192,138 @@ def check_dump_format(dump_image_format, dump_file): return False logging.debug("Run file %s output: %s", dump_file, output) actual_format = output.split(" ")[1] - if actual_format.lower() != dump_image_format.lower(): + if actual_format.lower() not in (dump_image_format.lower(), "flattened"): logging.error("Compress dumped file to %s fail: %s" % (dump_image_format, actual_format)) return False else: return True + def crash_utility(dump_file, vm): + """ + Check the working of crash utility tool to analyse the guest dump + + In order for the function to work, both the guest and the host must + have the same kernel + If crash tool or kernel debug libraries are not installed, the function + returns error + If crash tool cannot read into the vm-core, the function returns fail + If crash tool can read the vm-core, the function returns true + + Returns: + 0: Success + 1: Crash command failed + 2: Dependency installation failed or debug kernel not found + 3: Kernel mismatch between host and guest + 4: Guest kernel retrieval failed + 5: Unsupported distribution + 6: virsh dump unsuccessful + """ + def get_guest_kernel(vm): + """ + Login into the guest and get guest kernel + """ + try: + session = vm.wait_for_login(timeout=240) + except: + logging.error("Error Logging into the guest") + return "" + guest_kernel = session.cmd("uname -r") + session.close() + return guest_kernel + + logging.debug("Crash Utility to Analyse Dump") + + # Get guest and host kernel to verify if it is same + guest_kernel = get_guest_kernel(vm).strip() + host_kernel = platform.release().strip() + if not guest_kernel: + return 4 + if guest_kernel != host_kernel: + logging.error("Kernel mismatch") + logging.error("Host Kernel: %s", host_kernel) + logging.error("Guest Kernel: %s", guest_kernel) + return 3 + + # Get distro version to check for respective libraries + smm = SoftwareManager() + detected_distro = distro.detect() + distro_name = detected_distro.name.lower() + upstream_kernel = params.get("upstream_kernel", "no") == "yes" + + # Check for required debug tools and libraries + if distro_name in ("fedora", "rhel"): + deps = ["kexec-tools", "elfutils", "crash"] + if not upstream_kernel: + deps.append("kernel-debuginfo") + elif distro_name in ("ubuntu"): + deps = ["linux-crashdump", "kdump-tools", "crash", "elfutils"] + if not upstream_kernel: + deps.append("linux-image-debug") + elif distro_name in ("suse", "sles"): + deps = ["elfutils", "crash"] + if not upstream_kernel: + deps.append("linux-image-debug") + else: + return 5 + for package in deps: + if not smm.check_installed(package) and not smm.install(package): + logging.error("Failed to install dependency: %s", package) + return 2 + + # Check if debug kernel is present + if distro_name in ("fedora", "rhel"): + vmlinux = "/usr/lib/debug/lib/modules/" + host_kernel + "/vmlinux" + elif distro_name in ("ubuntu", "suse", "sles"): + vmlinux = "/usr/lib/debug/boot/vmlinux-" + host_kernel + else: + return 5 + if upstream_kernel: + vmlinux = params.get("upstream_kernel_vmlinux", vmlinux) + if not os.path.isfile(vmlinux): + logging.error("vmlinux not found") + return 2 + + # Collect guest vm-core + try: + virsh.dump(vm_name, dump_file, options, + ignore_status=True, debug=True) + except: + return 6 + + # Run Crash Utility + crash_cmd = f"crash {vmlinux} {dump_file}" + logging.debug("Crash command: %s", crash_cmd) + try: + # Spawn the crash command + child = pexpect.spawn(crash_cmd, timeout=100) + child.expect("crash> ") + stdout = child.before.decode('utf-8') + logging.debug("Crash tool output: %s", stdout.strip()) + + # Send the back-trace command and capture output + child.sendline("bt | head") + child.expect("crash> ") + stdout = child.before.decode('utf-8') + + # Check if the back-trace produced output + if "PID" in stdout or "TASK" in stdout: + logging.info("Crash tool is working correctly.") + logging.debug("Crash tool bt output: %s", stdout.strip()) + return 0 + else: + logging.error("Crash tool did not produce expected output.") + logging.debug("Crash tool output: %s", stdout.strip()) + return 1 + + except pexpect.TIMEOUT: + logging.error("Crash command timed out.") + return 1 + + except Exception as e: + logging.error("An error occurred while running the crash command: %s", e) + return 1 + # Configure dump_image_format in /etc/libvirt/qemu.conf. qemu_config = utils_config.LibvirtQemuConfig() libvirtd = utils_libvirtd.Libvirtd() @@ -268,36 +402,74 @@ def check_dump_format(dump_image_format, dump_file): args=(dump_file, result_dict)) child_process.start() - # Run virsh command - cmd_result = virsh.dump(vm_name, dump_file, options, - unprivileged_user=unprivileged_user, - uri=uri, - ignore_status=True, debug=True) - status = cmd_result.exit_status - if 'child_process' in locals(): - child_process.join(timeout=check_bypass_timeout) - params['bypass'] = result_dict['bypass'] - - logging.info("Start check result") - if not check_domstate(vm.state(), options): - test.fail("Domain status check fail.") - if status_error: - if not status: - test.fail("Expect fail, but run successfully") + # Create too small a directory + if "too_small" in dump_dir: + libvirt_disk.create_disk("file", + small_img, + "100M", + "raw") + libvirt.mkfs(small_img, "ext3") + os.mkdir(dump_dir) + utils_misc.mount(small_img, dump_dir, None) + + # Check for Crash Utility test + crash_utility_test = params.get("crash_utility", "no") == "yes" + + if not crash_utility_test: + # Run virsh command + cmd_result = virsh.dump(vm_name, dump_file, options, + unprivileged_user=unprivileged_user, + uri=uri, + ignore_status=True, debug=True) + status = cmd_result.exit_status + if 'child_process' in locals(): + child_process.join(timeout=check_bypass_timeout) + params['bypass'] = result_dict['bypass'] + + logging.info("Start check result") + time.sleep(5) + if not check_domstate(vm.state(), options): + test.fail("Domain status check fail.") + if status_error: + if not status: + test.fail("Expect fail, but run successfully") + else: + if status: + test.fail("Expect succeed, but run fail") + if not os.path.exists(dump_file): + test.fail("Fail to find domain dumped file.") + if check_dump_format(dump_image_format, dump_file): + logging.info("Successfully dump domain to %s", dump_file) + else: + test.fail("The format of dumped file is wrong.") + if params.get('bypass'): + test.fail(params['bypass']) + else: - if status: - test.fail("Expect succeed, but run fail") - if not os.path.exists(dump_file): - test.fail("Fail to find domain dumped file.") - if check_dump_format(dump_image_format, dump_file): - logging.info("Successfully dump domain to %s", dump_file) + crash_tool = crash_utility(dump_file, vm) + if crash_tool == 6: + test.fail("Unable to collect guest vmcore") + if crash_tool == 5: + test.cancel("Test unsupported for distro") + if crash_tool == 4: + test.error("Guest login issue. Unable to get guest kernel version") + if crash_tool == 3: + test.cancel("Guest and Host kernel are different") + elif crash_tool == 2: + test.error("Required debug libraries/tools not installed") + elif crash_tool == 1: + test.fail("Unable to analyse guest vmcore using crash") else: - test.fail("The format of dumped file is wrong.") - if params.get('bypass'): - test.fail(params['bypass']) + logging.info("Able to analyse guest vmcore using crash") + finally: backup_xml.sync() qemu_config.restore() libvirtd.restart() + if os.path.isfile(small_img): + # small_img is a file and will show as /dev/loop0 in /proc/mounts + utils_misc.umount("/dev/loop0", dump_dir, None, verbose=True) + os.rmdir(dump_dir) + os.remove(small_img) if os.path.isfile(dump_file): os.remove(dump_file) diff --git a/libvirt/tests/src/guest_os_booting/boot_order/boot_from_cdrom_device.py b/libvirt/tests/src/guest_os_booting/boot_order/boot_from_cdrom_device.py index 3ae748bcb5e..0162cd8af1d 100644 --- a/libvirt/tests/src/guest_os_booting/boot_order/boot_from_cdrom_device.py +++ b/libvirt/tests/src/guest_os_booting/boot_order/boot_from_cdrom_device.py @@ -1,20 +1,22 @@ import os +import platform -from avocado.utils import download from avocado.utils import process from virttest import data_dir from virttest import remote +from virttest import utils_misc from virttest.libvirt_xml import vm_xml from virttest.libvirt_xml.devices import disk -from provider.guest_os_booting import guest_os_booting_base +from provider.guest_os_booting import guest_os_booting_base as guest_os -def parse_cdroms_attrs(params): +def parse_cdroms_attrs(test, params): """ Parse cdrom devices' attrs + :param test: test object :param params: Dictionary with the test parameters :return: (boot image path, list of cdrom devices' attrs) """ @@ -29,12 +31,13 @@ def parse_cdroms_attrs(params): cdrom_attrs_list.append(cdrom2_attrs) if cdrom1_attrs.get('source') or cdrom2_attrs.get('source'): - cmd = "dnf repolist -v enabled |awk '/Repo-baseurl.*composes.*BaseOS.*os/ {print $NF}'" + cmd = "dnf repolist -v enabled |awk '/Repo-baseurl.*composes.*BaseOS.*os/ {res=$NF} END{print res}'" repo_url = process.run(cmd, shell=True).stdout_text.strip() boot_img_url = os.path.join(repo_url, 'images', 'boot.iso') if os.path.exists(boot_img_path): os.remove(boot_img_path) - download.get_file(boot_img_url, boot_img_path) + if not utils_misc.wait_for(lambda: guest_os.test_file_download(boot_img_url, boot_img_path), 60): + test.fail('Unable to download boot image') return boot_img_path, cdrom_attrs_list @@ -53,13 +56,12 @@ def update_vm_xml(vm, params, cdrom_attrs_list): os_attrs = {'boots': os_attrs_boots} vmxml.setup_attrs(os=os_attrs) else: - vm_os = vmxml.os - vm_os.del_boots() - vmxml.os = vm_os + vmxml.remove_all_boots() if "yes" == params.get("check_bootable_iso", "no"): - os_attrs.update({'bios_useserial': 'yes', - 'bootmenu_enable': 'yes', + os_attrs.update({'bootmenu_enable': 'yes', 'bootmenu_timeout': '3000'}) + if platform.machine() == "x86_64": + os_attrs.update({'bios_useserial': 'yes'}) vmxml.setup_attrs(os=os_attrs) index = 0 @@ -80,7 +82,7 @@ def run(test, params, env): Boot VM from cdrom devices This case covers per-device(cdrom) boot elements and os/boot elements. """ - vm_name = guest_os_booting_base.get_vm(params) + vm_name = guest_os.get_vm(params) status_error = "yes" == params.get("status_error", "no") check_bootable_iso = "yes" == params.get("check_bootable_iso", "no") bootable_patterns = eval(params.get('bootable_patterns', '[]')) @@ -91,14 +93,14 @@ def run(test, params, env): boot_img_path = None try: - boot_img_path, cdrom_attrs_list = parse_cdroms_attrs(params) + boot_img_path, cdrom_attrs_list = parse_cdroms_attrs(test, params) update_vm_xml(vm, params, cdrom_attrs_list) test.log.debug(vm_xml.VMXML.new_from_dumpxml(vm.name)) vm.start() - if check_bootable_iso: + if bootable_patterns: vm.serial_console.read_until_output_matches( - bootable_patterns, timeout=60, internal_timeout=0.5) + bootable_patterns, timeout=360, internal_timeout=0.5) else: try: vm.wait_for_serial_login().close() diff --git a/libvirt/tests/src/guest_os_booting/boot_order/boot_from_disk_device.py b/libvirt/tests/src/guest_os_booting/boot_order/boot_from_disk_device.py index d6fecf2f7ac..66cf7a99d91 100644 --- a/libvirt/tests/src/guest_os_booting/boot_order/boot_from_disk_device.py +++ b/libvirt/tests/src/guest_os_booting/boot_order/boot_from_disk_device.py @@ -3,34 +3,43 @@ from virttest import data_dir from virttest import remote +from virttest import utils_misc from virttest.libvirt_xml import vm_xml from virttest.libvirt_xml.devices import disk from virttest.utils_libvirt import libvirt_disk from virttest.utils_libvirt import libvirt_vmxml -from provider.guest_os_booting import guest_os_booting_base +from provider.guest_os_booting import guest_os_booting_base as guest_os -def parse_disks_attrs(vmxml, params): +def parse_disks_attrs(vmxml, test, params): """ Parse disk devices' attrs :param vmxml: The vmxml object :param params: Dictionary with the test parameters + :param test: test instance for error reporting :return: (Newly created disk image path, list of disk devices' attrs) """ - disk1_img = params.get('disk1_img') + disk1_img = params.get("disk1_img") disk_attrs_list = [] disk1_img_path = "" - disk_org_attrs = vmxml.devices.by_device_tag('disk')[0].fetch_attrs() - del disk_org_attrs['address'] + disk_org_attrs = vmxml.devices.by_device_tag("disk")[0].fetch_attrs() + del disk_org_attrs["address"] + disk1_img_url = params.get("disk1_img_url", "") + download_disk1_img = "yes" == params.get("download_disk1_img", "no") if disk1_img: - disk1_img_path = os.path.join(data_dir.get_data_dir(), 'images', - disk1_img) - libvirt_disk.create_disk('file', disk1_img_path, disk_format='qcow2') + disk1_img_path = os.path.join(data_dir.get_data_dir(), "images", disk1_img) + if download_disk1_img: + if not disk1_img_url or not utils_misc.wait_for( + lambda: guest_os.test_file_download(disk1_img_url, disk1_img_path), 60 + ): + test.fail("Unable to download boot image") + else: + libvirt_disk.create_disk("file", disk1_img_path, disk_format="qcow2") disk1_attrs = copy.deepcopy(disk_org_attrs) - disk1_attrs['source'] = {'attrs': {'file': disk1_img_path}} + disk1_attrs["source"] = {"attrs": {"file": disk1_img_path}} disk_attrs_list.append(disk1_attrs) disk_org_attrs.update(eval(params.get("disk2_attrs", "{}"))) @@ -48,11 +57,11 @@ def update_vm_xml(vm, params, disk_attrs_list): :param params: Dictionary with the test parameters :param disk_attrs_list: List of disk devices' attrs """ - os_attrs_boots = eval(params.get('os_attrs_boots', '[]')) - libvirt_vmxml.remove_vm_devices_by_type(vm, 'disk') + os_attrs_boots = eval(params.get("os_attrs_boots", "[]")) + libvirt_vmxml.remove_vm_devices_by_type(vm, "disk") vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm.name) if os_attrs_boots: - os_attrs = {'boots': os_attrs_boots} + os_attrs = {"boots": os_attrs_boots} vmxml.setup_attrs(os=os_attrs) else: vm_os = vmxml.os @@ -65,9 +74,8 @@ def update_vm_xml(vm, params, disk_attrs_list): disk_obj.setup_attrs(**disk_attrs) vmxml.add_device(disk_obj) index += 1 - if 'disk_boot_order' in params.get("shortname"): - vmxml.set_boot_order_by_target_dev( - disk_attrs['target']['dev'], index) + if "disk_boot_order" in params.get("shortname"): + vmxml.set_boot_order_by_target_dev(disk_attrs["target"]["dev"], index) vmxml.xmltreefile.write() vmxml.sync() @@ -77,7 +85,7 @@ def run(test, params, env): Boot VM from disk devices This case covers per-device(disk) boot elements and os/boot elements. """ - vm_name = guest_os_booting_base.get_vm(params) + vm_name = guest_os.get_vm(params) status_error = "yes" == params.get("status_error", "no") disk1_img_path = "" @@ -86,7 +94,7 @@ def run(test, params, env): bkxml = vmxml.copy() try: - disk1_img_path, disk_attrs_list = parse_disks_attrs(vmxml, params) + disk1_img_path, disk_attrs_list = parse_disks_attrs(vmxml, test, params) update_vm_xml(vm, params, disk_attrs_list) test.log.debug(vm_xml.VMXML.new_from_dumpxml(vm.name)) diff --git a/libvirt/tests/src/guest_os_booting/boot_order/boot_from_usb_device.py b/libvirt/tests/src/guest_os_booting/boot_order/boot_from_usb_device.py new file mode 100644 index 00000000000..4222ec00a58 --- /dev/null +++ b/libvirt/tests/src/guest_os_booting/boot_order/boot_from_usb_device.py @@ -0,0 +1,115 @@ +# Copyright Red Hat +# SPDX-License-Identifier: GPL-2.0 +# Author: Meina Li + +import re +import shutil + +from avocado.utils import process + +from virttest import virsh +from virttest.libvirt_xml import vm_xml +from virttest.libvirt_xml.devices import hostdev +from virttest.libvirt_xml.devices import redirdev +from virttest.utils_test import libvirt + +from provider.guest_os_booting import guest_os_booting_base as guest_os +from provider.backingchain import blockcommand_base +from provider.usb import usb_base +from provider.virtual_disk import disk_base + + +def run(test, params, env): + """ + This case is to verify the boot order of usb device. + 1) Prepare a guest with use device. + 2) Start the guest. + 3) Check the boot order of guest. + """ + def get_usb_source(): + """ + Get the usb list in host based on the output from command lsusb + + :return tuple: (vendor_id, product_id) for the usb device + """ + lsusb_list = process.run("lsusb").stdout_text.splitlines() + test.log.info("The lsusb command result: {}".format(lsusb_list)) + found_device = False + for line in lsusb_list: + if re.search('hub|Controller|Keyboard|Mouse|Cdrom|Floppy', line, re.IGNORECASE): + continue + if len(line.split()[5].split(':')) == 2: + vendor_id, product_id = line.split()[5].split(':') + if not (vendor_id and product_id): + test.fail("vendor/product id is not available") + found_device = True + break + if not found_device: + test.fail("There's no avaiable usb device.") + return vendor_id, product_id + + def check_boot_order(): + """ + Check the boot order of guest + """ + current_xml = vm_xml.VMXML.new_from_dumpxml(vm_name) + vm.create_serial_console() + vm.resume() + if not any([current_xml.os.fetch_attrs().get("os_firmware") == "efi", + current_xml.os.fetch_attrs().get('nvram')]): + for _ in range(3): + vm.serial_console.sendcontrol('[') + vm.serial_console.read_until_any_line_matches( + [check_prompt], timeout=100, internal_timeout=5.0) + + vm_name = params.get("main_vm") + disk_type = params.get("disk_type") + usb_device = params.get("usb_device") + bootmenu_dict = eval(params.get("bootmenu_dict", "{}")) + device_attrs = eval(params.get("device_attrs", "{}")) + check_prompt = params.get("check_prompt") + + vm = env.get_vm(vm_name) + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + bkxml = vmxml.copy() + + test_obj = blockcommand_base.BlockCommand(test, vm, params) + disk_obj = disk_base.DiskBase(test, vm, params) + extra_usb_cmd = usb_base.get_host_pkg_and_cmd()[1] + required_cmds = eval(params.get("required_cmds", "[]")) + [extra_usb_cmd] + + try: + for cmd in required_cmds: + if not (shutil.which(cmd)): + test.fail("Command '{}' is not available. Please install the relevant package(s)".format(cmd)) + vmxml = guest_os.prepare_os_xml(vm_name, bootmenu_dict) + vmxml.remove_all_boots() + + if usb_device == "block_device": + device_xml, new_image_path = disk_obj.prepare_disk_obj(disk_type, device_attrs) + if usb_device == "redirdev_device": + vendor_id, product_id = get_usb_source() + device_xml = redirdev.Redirdev() + device_xml.setup_attrs(**device_attrs) + usb_base.start_redirect_server(params, extra_usb_cmd, vendor_id, product_id) + if usb_device == "hostdev_device": + vendor_id, product_id = get_usb_source() + vendor_id = "0x" + vendor_id + product_id = "0x" + product_id + device_attrs = eval(params.get("device_attrs") % (vendor_id, product_id)) + device_xml = hostdev.Hostdev() + device_xml.setup_attrs(**device_attrs) + + libvirt.add_vm_device(vmxml, device_xml) + test.log.info("The current xml is {}".format(vmxml)) + + if not vm.is_alive(): + virsh.start(vm_name, "--paused", debug=True, ignore_status=False) + test.log.info("Check the boot order of guest after starting") + check_boot_order() + finally: + if vm.is_alive(): + virsh.destroy(vm_name) + disk_obj.cleanup_disk_preparation(disk_type) + bkxml.sync() + usb_base.kill_redirect_server(extra_usb_cmd) diff --git a/libvirt/tests/src/guest_os_booting/boot_order/boot_from_virtiofs_device.py b/libvirt/tests/src/guest_os_booting/boot_order/boot_from_virtiofs_device.py new file mode 100644 index 00000000000..91fe6082638 --- /dev/null +++ b/libvirt/tests/src/guest_os_booting/boot_order/boot_from_virtiofs_device.py @@ -0,0 +1,123 @@ +# Copyright Red Hat +# SPDX-License-Identifier: GPL-2.0 +# Author: Meina Li + +import os +import re +import shutil + +from avocado.utils import process + +from virttest import data_dir +from virttest import utils_selinux +from virttest import virsh +from virttest.libvirt_xml import vm_xml +from virttest.libvirt_xml.devices import filesystem +from virttest.utils_libvirt import libvirt_vmxml +from virttest.utils_test import libvirt + +from provider.guest_os_booting import guest_os_booting_base as guest_os + +BOOT_PATH = data_dir.get_data_dir() + + +def run(test, params, env): + """ + This case is to verify to boot from virtiofs device. + 1) Prepare a virtiofs boot environment. + 2) Start a guest with virtiofs related xml. + 3) Login guest to check. + """ + def prepare_virtiofs_bootable_system(): + """ + Prepare a basic linux root file system. + """ + cmd1 = f"mkdir {install_root}" + cmd2 = f"dnf --installroot={install_root} --releasever=9 install "\ + "system-release vim-minimal systemd passwd dnf rootfiles sudo "\ + "kernel kernel-modules net-tools yum -y >/dev/null" + # Create the initramfs. + cmd3 = f"dracut {initrams_file} --early-microcode "\ + "--add virtiofs --filesystem virtiofs" + multi_cmd = f"{cmd1}; {cmd2}; {cmd3}" + process.run(multi_cmd, shell=True, ignore_status=False) + change_virtiofs_root_passwd() + # Copy vmlinuz from host to use in guest. + cmd5 = f"cp $(ls /boot/vmlinuz* | tail -n 1) {vmlinuz_file}" + process.run(cmd5, shell=True) + + def change_virtiofs_root_passwd(): + """ + After install virtiofs related linux root file system, the password of root + need to be changed + """ + selinux_mode = utils_selinux.get_status() + utils_selinux.set_status("permissive") + fd = os.open('/', os.R_OK, os.X_OK) + os.chroot(install_root) + os.chdir('/') + set_passwd_cmd = f"echo {passwd} | passwd --stdin {username} &>/dev/null; exit" + os.system(set_passwd_cmd) + os.fchdir(fd) + os.chroot('.') + test.log.info("The passwd has been changed and exit the chroot env.") + utils_selinux.set_status(selinux_mode) + + vm_name = params.get("main_vm") + install_root = os.path.join(BOOT_PATH, "virtio-fs-root") + initrams_file = os.path.join(BOOT_PATH, "initramfs-virtiofs.img") + vmlinuz_file = os.path.join(BOOT_PATH, "vmlinuz-virtiofs.img") + boot_img = os.path.join(data_dir.get_data_dir(), "test.img") + guest_cmd = params.get("guest_cmd") + target_dir = params.get("target_dir") + vm_memory = int(params.get("vm_memory")) + username = params.get("username") + passwd = params.get("password") + disk_dict = {} + + vm = env.get_vm(vm_name) + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + bkxml = vmxml.copy() + + try: + test.log.info("SETUP: Prepare a virtiofs bootable environment.") + prepare_virtiofs_bootable_system() + os_dict = eval(params.get("os_dict") % (initrams_file, vmlinuz_file)) + virtiofs_dict = eval(params.get("virtiofs_dict") % install_root) + + test.log.info("STEP1: Prepare a guest xml with memory and virtiofs.") + vm_xml.VMXML.set_memoryBacking_tag(vm_name, access_mode="shared", hpgs=False) + vmxml = guest_os.prepare_os_xml(vm_name, os_dict) + test.log.info("Better to use big enough memory size, for example 15728640.") + vmxml.memory = vm_memory + vmxml.remove_all_boots() + virtiofs_dev = filesystem.Filesystem() + virtiofs_dev.setup_attrs(**virtiofs_dict) + test.log.debug(f"The filesystem device xml is {virtiofs_dev}") + vmxml.add_device(virtiofs_dev) + + test.log.info("STEP2: Start the guest with non-bootable disk image.") + libvirt.create_local_disk("file", path=boot_img, size="10G", disk_format="qcow2") + disk_dict.update({'source': {'attrs': {'file': boot_img}}}) + libvirt_vmxml.modify_vm_device(vmxml, 'disk', disk_dict) + if not vm.is_alive(): + vm.start() + test.log.info("STEP3: Login the guest") + vm_session = vm.wait_for_serial_login() + result = vm_session.cmd_output(guest_cmd) + test.log.debug("Send cmd: '%s' in console", guest_cmd) + if not re.search(target_dir, result): + test.fail(f"Expect {target_dir} in {result}, but not found") + else: + test.log.debug(f"Got {target_dir} in {result} as expected") + + finally: + if vm.is_alive(): + virsh.destroy(vm_name, debug=True, ignore_status=False) + test.log.info("Remove the linux root file system directory.") + if os.path.exists(install_root): + shutil.rmtree(install_root) + for file_path in [initrams_file, vmlinuz_file, boot_img]: + if os.path.exists(file_path): + os.remove(file_path) + bkxml.sync() diff --git a/libvirt/tests/src/guest_os_booting/boot_order/boot_with_multiple_boot_dev.py b/libvirt/tests/src/guest_os_booting/boot_order/boot_with_multiple_boot_dev.py new file mode 100644 index 00000000000..cf5c3f96d93 --- /dev/null +++ b/libvirt/tests/src/guest_os_booting/boot_order/boot_with_multiple_boot_dev.py @@ -0,0 +1,101 @@ +# Copyright Red Hat +# SPDX-License-Identifier: GPL-2.0 +# Author: Meina Li + +import os + +from avocado.utils import process + +from virttest import data_dir +from virttest import utils_misc +from virttest.libvirt_xml import vm_xml +from virttest.utils_libvirt import libvirt_vmxml +from virttest.utils_test import libvirt + +from provider.guest_os_booting import guest_os_booting_base as guest_os + + +def get_vmxml_with_multiple_boot(params, vm_name): + """ + Prepare the os attributes with two boot dev attributes. + + :params params: wrapped dict with all parameters + :params vm_name: the guest name + :return: the guest xml + """ + first_dev = params.get("first_dev") + second_dev = params.get("second_dev") + os_dict = eval(params.get("os_dict") % (first_dev, second_dev)) + vmxml = guest_os.prepare_os_xml(vm_name, os_dict) + return vmxml + + +def prepare_device(test, params, vm_name, bootable_device): + """ + Prepare the device xml based on different test matrix. + + :params test: test object + :params params: wrapped dict with all parameters + :params vm_name: the guest name + :params bootable_device: the device expected to boot from + :return: a tuple including the vmxml, disk_image and cdrom_path + """ + vmxml = get_vmxml_with_multiple_boot(params, vm_name) + disk_image = os.path.join(data_dir.get_data_dir(), 'images', 'test.img') + if bootable_device != "hd_bootable": + libvirt.create_local_disk("file", path=disk_image, size="500M", disk_format="qcow2") + disk_dict = {'source': {'attrs': {'file': disk_image}}} + libvirt_vmxml.modify_vm_device(vmxml, 'disk', disk_dict) + if bootable_device == "cdrom_bootable": + cdrom_path = os.path.join(data_dir.get_data_dir(), 'images', 'boot.iso') + cmd = "dnf repolist -v enabled |awk '/Repo-baseurl.*composes.*BaseOS.*os/ {res=$NF} END{print res}'" + repo_url = process.run(cmd, shell=True).stdout_text.strip() + boot_img_url = os.path.join(repo_url, 'images', 'boot.iso') + if not utils_misc.wait_for(lambda: guest_os.test_file_download(boot_img_url, cdrom_path), 60): + test.fail('Unable to download boot image') + else: + cdrom_path = os.path.join(data_dir.get_data_dir(), 'images', 'test.iso') + libvirt.create_local_disk("file", path=cdrom_path, size="500M", disk_format="raw") + cdrom_dict = eval(params.get("cdrom_dict") % cdrom_path) + cdrom_xml = libvirt_vmxml.create_vm_device_by_type("disk", cdrom_dict) + vmxml.add_device(cdrom_xml) + vmxml.sync() + return vmxml, disk_image, cdrom_path + + +def run(test, params, env): + """ + This case is to verify the boot order when more than one boot dev elements in guest. + 1) Start a guest with the necessary device xml. + 2) Check the guest boot status. + """ + vm_name = guest_os.get_vm(params) + check_prompt = eval(params.get("check_prompt", "[]")) + bootable_device = params.get("bootable_device") + disk_image = "" + cdrom_path = "" + + vm = env.get_vm(vm_name) + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm.name) + bkxml = vmxml.copy() + + try: + test.log.info("TEST_SETUP: prepare a guest with necessary attributes.") + vmxml, disk_image, cdrom_path = prepare_device(test, params, vm_name, bootable_device) + test.log.info("TEST_STEP1: start the guest.") + if not vm.is_alive(): + vm.start() + vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) + test.log.debug(f"The current guest xml is: {vmxml}") + test.log.info("TEST_STEP2: check the guest boot from expected device.") + if bootable_device == "hd_bootable": + vm.wait_for_login(timeout=360).close() + test.log.debug("Succeed to boot %s", vm_name) + else: + vm.serial_console.read_until_output_matches(check_prompt, timeout=600, + internal_timeout=0.5) + finally: + bkxml.sync() + for file in [disk_image, cdrom_path]: + if os.path.exists(file): + os.remove(file) diff --git a/libvirt/tests/src/guest_os_booting/boot_order/boot_with_multiple_boot_order.py b/libvirt/tests/src/guest_os_booting/boot_order/boot_with_multiple_boot_order.py new file mode 100644 index 00000000000..10ee8f04a55 --- /dev/null +++ b/libvirt/tests/src/guest_os_booting/boot_order/boot_with_multiple_boot_order.py @@ -0,0 +1,126 @@ +# Copyright Red Hat +# SPDX-License-Identifier: GPL-2.0 +# Author: Meina Li +import platform +import os +import re + +from avocado.utils import process + +from virttest import data_dir +from virttest import utils_misc +from virttest.libvirt_xml import vm_xml +from virttest.utils_libvirt import libvirt_vmxml +from virttest.utils_test import libvirt + +from provider.guest_os_booting import guest_os_booting_base as guest_os +from provider.virtual_network import tftpboot + +# Prepare a list to record the file path which need to be removed +file_list = [] + + +def prepare_device_attrs(test, params, vm_name, bootable_device): + """ + Prepare the device xml based on different test matrix. + + :params test: test object + :params params: wrapped dict with all parameters + :params vm_name: the guest name + :params bootable_device: the bootable device + """ + os_dict = eval(params.get("os_dict")) + first_dev = params.get("first_dev") + second_dev = params.get("second_dev") + disk_order = eval(params.get("disk_order", "{}")) + cdrom_order = eval(params.get("cdrom_order", "{}")) + network_order = eval(params.get("network_order", "{}")) + set_up_tftp = "yes" == params.get("set_up_tftp", "no") + memory = params.get("vm_memory", "") + disk_image = os.path.join(data_dir.get_data_dir(), 'images', 'test.img') + vmxml = guest_os.prepare_os_xml(vm_name, os_dict) + vmxml.remove_all_boots() + if bootable_device != "hd_bootable": + libvirt.create_local_disk("file", path=disk_image, size="500M", disk_format="qcow2") + disk_dict = {'source': {'attrs': {'file': disk_image}}} + libvirt_vmxml.modify_vm_device(vmxml, 'disk', disk_dict) + file_list.append(disk_image) + if bootable_device == "cdrom_bootable": + cdrom_path = os.path.join(data_dir.get_data_dir(), 'images', 'boot.iso') + cmd = "dnf repolist -v enabled |awk '/Repo-baseurl.*composes.*BaseOS.*os/ {res=$NF} END{print res}'" + repo_url = process.run(cmd, shell=True).stdout_text.strip() + boot_img_url = os.path.join(repo_url, 'images', 'boot.iso') + if not utils_misc.wait_for(lambda: guest_os.test_file_download(boot_img_url, cdrom_path), 60): + test.fail('Unable to download boot image') + else: + cdrom_path = os.path.join(data_dir.get_data_dir(), 'images', 'test.iso') + libvirt.create_local_disk("file", path=cdrom_path, size="500M", disk_format="raw") + if bootable_device == "network_bootable" and set_up_tftp: + install_tree_url = params.get("install_tree_url") + tftpboot.create_tftp_content(install_tree_url, + None, + arch=platform.machine()) + tftpboot.create_tftp_network() + file_list.append(cdrom_path) + cdrom_dict = eval(params.get("cdrom_dict") % cdrom_path) + cdrom_dict.update(cdrom_order) + cdrom_xml = libvirt_vmxml.create_vm_device_by_type("disk", cdrom_dict) + vmxml.add_device(cdrom_xml) + if memory: + vmxml.memory = int(memory) + vmxml.current_mem = int(memory) + vmxml.sync() + # Update boot order attributes + if "hd" in (first_dev, second_dev): + libvirt_vmxml.modify_vm_device(vmxml, 'disk', disk_order) + if "network" in (first_dev, second_dev): + libvirt_vmxml.modify_vm_device(vmxml, 'interface', network_order) + + +def run(test, params, env): + """ + This case is to verify the boot order when more than one boot dev elements in guest. + 1) Start a guest with the necessary device xml. + 2) Check the guest boot status. + """ + vm_name = guest_os.get_vm(params) + check_prompt = eval(params.get("check_prompt", "[]")) + bootable_device = params.get("bootable_device") + os_dict = eval(params.get("os_dict")) + test_cmd = params.get("test_cmd", None) + expected_output = params.get("expected_output", None) + + vm = env.get_vm(vm_name) + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm.name) + bkxml = vmxml.copy() + session = None + + try: + test.log.info("TEST_SETUP: prepare a guest with necessary attributes.") + prepare_device_attrs(test, params, vm_name, bootable_device) + test.log.info("TEST_STEP1: start the guest.") + if not vm.is_alive(): + vm.start() + vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) + test.log.debug(f"The current guest xml is: {vmxml}") + test.log.info("TEST_STEP2: check the guest boot from expected device.") + if bootable_device == "hd_bootable": + session = vm.wait_for_login(timeout=360) + test.log.debug("Succeed to boot %s", vm_name) + if test_cmd is not None: + output = session.cmd(test_cmd) + if not re.search(expected_output, output): + test.fail(f"Couldn't get {expected_output}, got instead {output}") + test.log.debug("Succeed to set %s", expected_output) + session.close() + else: + vm.serial_console.read_until_output_matches(check_prompt, timeout=600, + internal_timeout=0.5) + finally: + if session: + session.close() + bkxml.sync() + tftpboot.cleanup() + for file in file_list: + if os.path.exists(file): + os.remove(file) diff --git a/libvirt/tests/src/guest_os_booting/boot_order/hotplug_device_with_boot_order.py b/libvirt/tests/src/guest_os_booting/boot_order/hotplug_device_with_boot_order.py new file mode 100644 index 00000000000..e3320c3be25 --- /dev/null +++ b/libvirt/tests/src/guest_os_booting/boot_order/hotplug_device_with_boot_order.py @@ -0,0 +1,113 @@ +# Copyright Red Hat +# SPDX-License-Identifier: GPL-2.0 +# Author: Meina Li + +import os + +from virttest import virsh +from virttest.libvirt_xml import vm_xml +from virttest.libvirt_xml.devices.filesystem import Filesystem +from virttest.utils_libvirt import libvirt_vmxml +from virttest.utils_test import libvirt + +from provider.virtual_disk import disk_base + + +def run(test, params, env): + """ + This case is to verify hotplugging device with boot order element. + 1) Prepare a running guest. + 2) Hotplug the device with boot order element. + 3) Check the dumpxml. + 4) Hot-unplug the device. + """ + + def prepare_device_xml(vm_xml, device_type): + """ + Prepare the hot-plugged device xml. + + :params vm_xml: the instance of VMXML class + :params device_type: the device type + :return: tuple, (device_xml, image_path) for the attached device + """ + image_path = "" + # Need to use shared memory for filesystem device + if device_type == "filesystem_device": + vm_xml.VMXML.set_memoryBacking_tag( + vm_name, access_mode="shared", hpgs=False + ) + device_xml = Filesystem() + device_xml.setup_attrs(**device_dict) + else: + device_xml, image_path = disk_obj.prepare_disk_obj("file", device_dict) + return device_xml, image_path + + def check_dumpxml(device_type, image_path, exist): + """ + Check if the device is existed and included the boot order element. + + :params device_type: the device type + :params image_path: the disk path + :params exist: whether the device is existed + """ + vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) + test.log.debug(f"The current guest xml is: {vmxml}") + if device_type == "filesystem_device": + device_status = vmxml.devices.by_device_tag("filesystem") + else: + device_status = vm_xml.VMXML.check_disk_exist(vm_name, image_path) + if exist: + if not device_status: + test.fail(f"No {device_type} in guest xml after hotplug.") + # To make sure the boot order is also in device xml + libvirt_vmxml.check_guest_xml_by_xpaths( + vmxml, order_xpath, ignore_status=False + ) + else: + if device_status: + test.fail(f"The {device_type} isn't detached successfully.") + + vm_name = params.get("main_vm") + device_type = params.get("device_type") + target_dev = params.get("target_dev") + boot_order = params.get("boot_order", "1") + expected_error = params.get("expected_error", None) + device_dict = eval(params.get("device_dict")) + order_xpath = eval(params.get("order_xpath")) + virsh_dargs = {"debug": True, "ignore_status": False} + + vm = env.get_vm(vm_name) + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + bkxml = vmxml.copy() + disk_obj = disk_base.DiskBase(test, vm, params) + + try: + test.log.info("STEP1: Prepare a guest with boot order.") + vmxml.remove_all_boots() + vmxml.set_boot_order_by_target_dev(target_dev, order=boot_order) + vmxml.sync() + + test.log.info(f"STEP2: Hotplug the {device_type}.") + device_xml, image_path = prepare_device_xml(vm_xml, device_type) + if not vm.is_alive(): + virsh.start(vm_name, **virsh_dargs) + + vm.wait_for_login() + ret = virsh.attach_device( + vm_name, device_xml.xml, debug=True, ignore_status=True + ) + libvirt.check_result(ret, expected_fails=expected_error) + if expected_error: + return + + check_dumpxml(device_type, image_path, exist=True) + + test.log.info(f"STEP3: Hot-unplug the {device_type}.") + virsh.detach_device(vm_name, device_xml.xml, wait_for_event=True, **virsh_dargs) + check_dumpxml(device_type, image_path, exist=False) + finally: + if vm.is_alive(): + virsh.destroy(vm_name, **virsh_dargs) + if image_path and os.path.exists(image_path): + os.remove(image_path) + bkxml.sync() diff --git a/libvirt/tests/src/guest_os_booting/direct_kernel_boot/direct_kernel_boot.py b/libvirt/tests/src/guest_os_booting/direct_kernel_boot/direct_kernel_boot.py index 90124677cd2..f20d43b82b5 100644 --- a/libvirt/tests/src/guest_os_booting/direct_kernel_boot/direct_kernel_boot.py +++ b/libvirt/tests/src/guest_os_booting/direct_kernel_boot/direct_kernel_boot.py @@ -35,8 +35,8 @@ def run(test, params, env): bkxml = vmxml.copy() try: - boot_initrd = os.path.join(data_dir.get_data_dir(), "initrd.img") - boot_vmlinuz = os.path.join(data_dir.get_data_dir(), "vmlinuz") + boot_initrd = os.path.join(data_dir.get_data_dir(), initrd_url.split("/")[-1]) + boot_vmlinuz = os.path.join(data_dir.get_data_dir(), vmlinuz_url.split("/")[-1]) url_download(initrd_url, boot_initrd) url_download(vmlinuz_url, boot_vmlinuz) direct_kernel_dict = eval(params.get("direct_kernel_dict") @@ -48,7 +48,7 @@ def run(test, params, env): test.log.debug("The final guest xml is %s", vmxml) if not vm.is_alive(): vm.start() - vm.serial_console.read_until_any_line_matches([check_prompt], timeout=360) + vm.serial_console.read_until_any_line_matches([check_prompt], timeout=600) finally: bkxml.sync() for file_path in [boot_initrd, boot_vmlinuz]: diff --git a/libvirt/tests/src/guest_os_booting/firmware_configuration/smbios_mode.py b/libvirt/tests/src/guest_os_booting/firmware_configuration/smbios_mode.py new file mode 100644 index 00000000000..d8f567af33e --- /dev/null +++ b/libvirt/tests/src/guest_os_booting/firmware_configuration/smbios_mode.py @@ -0,0 +1,167 @@ +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Copyright Red Hat +# +# SPDX-License-Identifier: GPL-2.0 + +# Author: Meina Li +import re + +from avocado.utils import process + +from virttest import virsh +from virttest.libvirt_xml import vm_xml +from virttest.libvirt_xml import xcepts + +from provider.guest_os_booting import guest_os_booting_base as guest_os + + +def run(test, params, env): + """ + This case is to verity the smbios feature of os. + 1) Prepare a guest xml with smbios features. + 2) Start the guest and login it. + 3) Check smbios data in guest and compare it with expected one. + """ + def check_sysinfo_mode_result(): + """ + Get the expected smbios data + """ + sysinfo_elements = [bios_entry, system_entry, baseBoard_entry, + chassis_entry, oemStrings_entry] + for item in sysinfo_elements: + item_key = list(item)[0] + item_value = item[item_key] + expected_smbios_data = {} + for i in range(len(item_value)): + if item_key == "oemStrings_entry": + expected_smbios_data.update({i: item_value[i]['entry']}) + else: + expected_smbios_data.update({item_value[i]['entry_name']: item_value[i]['entry']}) + # Check sysinfo in guest + entry_type = item_key.split('_')[0] + compare_smbios_data(entry_type, expected_smbios_data) + + def get_smbios_data(entry_type, smbios_output): + """ + Get the smbios data for host or guest. + + :params entry_type: the entry type of smbios data + :params smbios_output: the output of dmidecode smbios data + :return: return the smbios data for from guest + """ + smbios_data = {} + for line in str(smbios_output).splitlines(): + line = line.strip() + # Exclude lines that cannot be parsed into dict + pattern = re.compile(r'^(.*?):\s+(.*)$') + match = pattern.match(line) + if match: + key, value = match.groups() + smbios_data[key] = value + return smbios_data + + def get_expected_smbios_data(vmxml, smbios_mode): + """ + Check the hardware and firmware info in guest by dmidecode. + + :params vmxml: the xml of guest + :params smbios_mode: the testing smbios mode + :return: a tuple with entry_type and expected_smbios_data + """ + entry_type = "system" + if smbios_mode == "emulate": + expected_smbios_data = eval(params.get("expected_system_info") % vmxml.uuid) + else: + dmidecode_cmd = "dmidecode -t %s" % entry_type + host_system = process.run(dmidecode_cmd).stdout_text + system_info = get_smbios_data(entry_type, host_system) + expected_smbios_data = eval(params.get("expected_system_info") % + (system_info["Manufacturer"], system_info["Product Name"], + system_info["SKU Number"], system_info["Family"])) + return entry_type, expected_smbios_data + + def compare_smbios_data(entry_type, expected_smbios_data): + """ + Compare the smbios data for from guest with the guest xml + + :params entry_type: the entry type of smbios data + :params expected_smbios_data: the expected smbios data got from guest xml + """ + if entry_type == "oemStrings": + dmidecode_cmd = "dmidecode -t 11" + else: + dmidecode_cmd = "dmidecode -t %s" % entry_type + session = vm.wait_for_login() + smbios_output = session.cmd_status_output(dmidecode_cmd) + smbios_data = get_smbios_data(entry_type, smbios_output[1]) + session.close() + test.log.debug(f"The smbios data of guest for {smbios_mode} mode is:" + f"{smbios_data}") + # The keys are not same for sysinfo smbios mode. For example, "date" and "Release Date". + # So here use length to check the matched status. + match_values = {} + test.log.debug(f"The expected smbios data for {smbios_mode} is: {expected_smbios_data}") + for key, value in expected_smbios_data.items(): + for actual_value in smbios_data.values(): + if value == actual_value: + match_values[key] = actual_value + if len(match_values) != len(expected_smbios_data): + test.fail(f"The {smbios_data} is not matched with the expected data {expected_smbios_data}.") + else: + test.log.debug(f"The smbios data of {entry_type} in guest is expected.") + + vm_name = params.get("main_vm") + os_dict = eval(params.get("os_dict", "{}")) + smbios_mode = params.get("smbios_mode") + error_msg = params.get("error_msg", "") + with_sysinfo = "yes" == params.get("with_sysinfo", "no") + type_entry = eval(params.get("sysinfo_type", "{}")) + bios_entry = eval(params.get("sysinfo_bios", "{}")) + baseBoard_entry = eval(params.get("sysinfo_baseBoard", "{}")) + chassis_entry = eval(params.get("sysinfo_chassis", "{}")) + oemStrings_entry = eval(params.get("sysinfo_oemStrings", "{}")) + + vm = env.get_vm(vm_name) + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + bkxml = vmxml.copy() + + try: + # Prepare sysinfo xml if necessary + sysinfo_dict = {} + if smbios_mode == "sysinfo": + system_entry = eval(params.get("sysinfo_system") % vmxml.uuid) + else: + system_entry = eval(params.get("sysinfo_system", "{}")) + if with_sysinfo: + sysinfo_dict = {**type_entry, **bios_entry, **system_entry, + **baseBoard_entry, **chassis_entry, **oemStrings_entry} + sysinfo_xml = vm_xml.VMSysinfoXML() + sysinfo_xml.setup_attrs(**sysinfo_dict) + vmxml.sysinfo = sysinfo_xml + # Prepare os xml with smbios + try: + vmxml.setup_attrs(os=os_dict) + vmxml.sync() + virsh.dumpxml(vm_name, debug=True) + except xcepts.LibvirtXMLError as details: + if error_msg and error_msg in str(details): + test.log.info("Get expected error message: %s.", error_msg) + return + else: + test.fail("Failed to define the guest because error:%s" % str(details)) + if error_msg: + guest_os.check_vm_startup(vm, vm_name, error_msg) + return + else: + guest_os.check_vm_startup(vm, vm_name) + test.log.debug(f"The current dumpxml is {vmxml}") + if smbios_mode == "sysinfo": + check_sysinfo_mode_result() + else: + entry_type, expected_smbios_data = get_expected_smbios_data(vmxml, smbios_mode) + compare_smbios_data(entry_type, expected_smbios_data) + finally: + if vm.is_alive(): + vm.destroy() + bkxml.sync() diff --git a/libvirt/tests/src/guest_os_booting/firmware_configuration/sysinfo_fwcfg.py b/libvirt/tests/src/guest_os_booting/firmware_configuration/sysinfo_fwcfg.py new file mode 100644 index 00000000000..bb17ffa2baf --- /dev/null +++ b/libvirt/tests/src/guest_os_booting/firmware_configuration/sysinfo_fwcfg.py @@ -0,0 +1,77 @@ +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Copyright Red Hat +# +# SPDX-License-Identifier: GPL-2.0 + +# Author: Meina Li +# +import os + +from virttest import data_dir +from virttest.libvirt_xml import vm_xml +from virttest.libvirt_xml import xcepts + +from provider.guest_os_booting import guest_os_booting_base as guest_os + + +def run(test, params, env): + """ + This case is to verify the sysinfo fwcfg feature. + 1) Prepare a guest with sysinfo fwcfg xml. + 2) Start the guest. + 3) Check the config in guest. + """ + + def result_check(): + """ + Check the firmware config in guest + """ + session = vm.wait_for_login() + test_cmd = ("grep \"%s\" /sys/firmware/qemu_fw_cfg/by_name/%s/raw" + % (entry_value, entry_name)) + status, output = session.cmd_status_output(test_cmd) + if status != 0: + test.fail("Failed due to: %s" % output) + session.close() + + vm_name = params.get("main_vm") + entry_name = params.get("entry_name") + entry_value = params.get("entry_value") + file_name = params.get("file_name") + entry_file = "yes" == params.get("entry_file", "no") + error_msg = params.get("error_msg") + + vm = env.get_vm(vm_name) + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + bkxml = vmxml.copy() + + try: + if entry_file: + file_path = os.path.join(data_dir.get_data_dir(), file_name) + entry_value = "This is a new feature" + with open(file_path, 'w') as file: + file.write(entry_value) + fwcfg_dict = eval(params.get("fwcfg_dict") % (entry_name, file_path)) + else: + fwcfg_dict = eval(params.get("fwcfg_dict") % entry_name) + + vmxml.setup_attrs(sysinfo=fwcfg_dict) + vmxml.sync() + guest_os.check_vm_startup(vm, vm_name) + test.log.info("The current dumpxml is %s.", vmxml) + result_check() + # Except condition for the vmxml.sync() step. + except xcepts.LibvirtXMLError as xml_error: + if error_msg and error_msg in str(xml_error): + test.log.info("Get expected error message: %s.", error_msg) + else: + test.fail("Failed to define the guest because error:%s" % xml_error) + + finally: + if vm.is_alive(): + vm.destroy(vm_name) + if entry_file and os.path.exists(file_path): + os.remove(file_path) + bkxml.sync() diff --git a/libvirt/tests/src/guest_os_booting/migration/migration_boot.py b/libvirt/tests/src/guest_os_booting/migration/migration_boot.py index e8362e95683..4cd0818270a 100644 --- a/libvirt/tests/src/guest_os_booting/migration/migration_boot.py +++ b/libvirt/tests/src/guest_os_booting/migration/migration_boot.py @@ -49,6 +49,17 @@ def setup_test(): update_vm_xml(vm, params) migration_obj.setup_default() + def verify_test_again(): + """ + Test verify + """ + migrate_vm_back = "yes" == params.get("migrate_vm_back", "yes") + if not migrate_vm_back: + return + test.log.info("Verify test again.") + dargs = {"check_disk_on_dest": "no"} + migration_obj.migration_test.post_migration_check([vm], dargs) + vm_name = guest_os_booting_base.get_vm(params) vm = env.get_vm(vm_name) @@ -62,8 +73,7 @@ def setup_test(): test.log.info("TEST_STEP: Migrate back the VM to the source host.") migration_obj.run_migration_back() - dargs = {"check_disk_on_dest": "no"} - migration_obj.migration_test.post_migration_check([vm], dargs) + verify_test_again() finally: migration_obj.cleanup_default() diff --git a/libvirt/tests/src/guest_os_booting/os_configuration/without_default_os_attributes.py b/libvirt/tests/src/guest_os_booting/os_configuration/without_default_os_attributes.py index 65f766bae7b..2f288839db2 100644 --- a/libvirt/tests/src/guest_os_booting/os_configuration/without_default_os_attributes.py +++ b/libvirt/tests/src/guest_os_booting/os_configuration/without_default_os_attributes.py @@ -2,6 +2,8 @@ # SPDX-License-Identifier: GPL-2.0 # Author: Meina Li +import platform + from virttest import virsh from virttest.libvirt_xml import vm_xml @@ -20,6 +22,7 @@ def run(test, params, env): vm_name = guest_os.get_vm(params) firmware_type = params.get("firmware_type") os_dict = eval(params.get("os_dict")) + host_arch = platform.machine() os_xpath = eval(params.get("os_xpath")) vm = env.get_vm(vm_name) diff --git a/libvirt/tests/src/guest_os_booting/ovmf_firmware/ovmf_backed_nvram.py b/libvirt/tests/src/guest_os_booting/ovmf_firmware/ovmf_backed_nvram.py index 9159e9370aa..d5431475966 100644 --- a/libvirt/tests/src/guest_os_booting/ovmf_firmware/ovmf_backed_nvram.py +++ b/libvirt/tests/src/guest_os_booting/ovmf_firmware/ovmf_backed_nvram.py @@ -9,7 +9,9 @@ from virttest import virsh from virttest.data_dir import get_data_dir from virttest.libvirt_xml import vm_xml +from virttest import utils_misc from provider.guest_os_booting import guest_os_booting_base as guest_os +from provider.virtual_disk import disk_base def run(test, params, env): @@ -30,6 +32,10 @@ def compare_guest_xml(vmxml, os_attrs): current_os_attrs = os_xml.fetch_attrs() for key in os_attrs: if key in current_os_attrs: + if key == "nvram_attrs": + current_os_attrs[key].pop("templateFormat") + if "format" not in os_attrs[key]: + os_attrs[key]["format"] = "raw" if os_attrs[key] != current_os_attrs[key]: test.fail("Configured os xml value {} doesn't match the" " entry {} in guest xml".format(os_attrs[key], current_os_attrs[key])) @@ -37,16 +43,34 @@ def compare_guest_xml(vmxml, os_attrs): test.fail("Configured os attributes {} don't existed in guest.".format(key)) test.log.debug("Get expected os xml of guest.") + def create_block_device(): + """ + Setup one scsi_debug block device + + :return: device name + """ + name_term = utils_misc.generate_random_string(4) + disk_obj.lv_name = 'lv_' + name_term + disk_obj.vg_name = 'vg_' + name_term + _, new_image_path = disk_obj.prepare_disk_obj(disk_type='block', disk_dict={}, size='8M', convert_format='qcow2') + return new_image_path + vm_name = guest_os.get_vm(params) firmware_type = params.get("firmware_type") source_type = params.get("source_type") nvram_file = os.path.join(get_data_dir(), "test.fd") - nvram_attrs = eval(params.get("nvram_attrs") % source_type) + nvram_attrs = eval(params.get("nvram_attrs")) os_dict = eval(params.get("os_dict")) - nvram_source = eval(params.get("nvram_source") % nvram_file) - libvirt_version.is_libvirt_feature_supported(params) - vm = env.get_vm(vm_name) + if source_type == 'file': + nvram_source = eval(params.get("nvram_source") % nvram_file) + elif source_type == 'block': + disk_obj = disk_base.DiskBase(test, vm, params) + disk_obj.disk_size = '8M' + image_path = create_block_device() + nvram_source = eval(params.get("nvram_source") % image_path) + test.log.info('the path of nvram:' + image_path) + libvirt_version.is_libvirt_feature_supported(params) vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) bkxml = vmxml.copy() @@ -63,4 +87,6 @@ def compare_guest_xml(vmxml, os_attrs): virsh.destroy(vm_name) if os.path.exists(nvram_file): os.remove(nvram_file) + if source_type == 'block': + disk_obj.cleanup_disk_preparation(disk_type='block') bkxml.sync() diff --git a/libvirt/tests/src/guest_os_booting/ovmf_firmware/ovmf_loader.py b/libvirt/tests/src/guest_os_booting/ovmf_firmware/ovmf_loader.py index 518c08a66a0..aec32bbf39f 100644 --- a/libvirt/tests/src/guest_os_booting/ovmf_firmware/ovmf_loader.py +++ b/libvirt/tests/src/guest_os_booting/ovmf_firmware/ovmf_loader.py @@ -28,7 +28,7 @@ def run(test, params, env): firmware_type = params.get("firmware_type") loader_dict = eval(params.get("loader_dict", "{}")) loader_xpath = eval(params.get("loader_xpath", "[]")) - smm_state = params.get("smm_state", "off") + smm_state = params.get("smm_state") error_msg = params.get("error_msg") incorrect_loader_path = params.get("incorrect_loader_path", "") use_file = "yes" == params.get("use_file", "no") @@ -40,7 +40,8 @@ def run(test, params, env): bkxml = vmxml.copy() try: - guest_os.prepare_smm_xml(vm_name, smm_state, "") + if smm_state: + guest_os.prepare_smm_xml(vm_name, smm_state, "") vmxml = guest_os.prepare_os_xml(vm_name, loader_dict, firmware_type) # stateless='yes' only use for AMD test, so here we only check the dumpxml for it to avoid the machine issue if stateless: diff --git a/libvirt/tests/src/guest_os_booting/ovmf_firmware/ovmf_nvram.py b/libvirt/tests/src/guest_os_booting/ovmf_firmware/ovmf_nvram.py index be711ae6af0..5d745be9e26 100644 --- a/libvirt/tests/src/guest_os_booting/ovmf_firmware/ovmf_nvram.py +++ b/libvirt/tests/src/guest_os_booting/ovmf_firmware/ovmf_nvram.py @@ -19,20 +19,23 @@ def run(test, params, env): """ vm_name = guest_os.get_vm(params) firmware_type = params.get("firmware_type") - smm_state = params.get("smm_state", "off") + smm_state = params.get("smm_state") error_msg = params.get("error_msg", "") template_path = params.get("template_path", "") - if template_path: - nvram_dict = eval(params.get("nvram_dict", "{}") % template_path) - else: - nvram_dict = eval(params.get("nvram_dict")) vm = env.get_vm(vm_name) vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) bkxml = vmxml.copy() try: - guest_os.prepare_smm_xml(vm_name, smm_state, smm_size=None) + if template_path: + nvram_dict = eval(params.get("nvram_dict", "{}") % template_path) + if template_path == "nonexist": + vmxml.sync("--nvram") + else: + nvram_dict = eval(params.get("nvram_dict")) + if smm_state: + guest_os.prepare_smm_xml(vm_name, smm_state, smm_size=None) guest_os.prepare_os_xml(vm_name, nvram_dict, firmware_type) guest_os.check_vm_startup(vm, vm_name, error_msg) finally: diff --git a/libvirt/tests/src/guest_os_booting/ovmf_firmware/ovmf_seclabel_in_nvram.py b/libvirt/tests/src/guest_os_booting/ovmf_firmware/ovmf_seclabel_in_nvram.py new file mode 100644 index 00000000000..56d10bc7b7e --- /dev/null +++ b/libvirt/tests/src/guest_os_booting/ovmf_firmware/ovmf_seclabel_in_nvram.py @@ -0,0 +1,85 @@ +# 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.data_dir import get_data_dir +from virttest.libvirt_xml import vm_xml +from provider.guest_os_booting import guest_os_booting_base as guest_os + + +def run(test, params, env): + """ + This case is to verify the ovmf backed nvram. + 1) Prepare a guest with related backed nvram elements. + 2) Start and boot the guest. + 3) Check the dumpxml and the label if necessary. + """ + def compare_guest_xml(vmxml, os_attrs): + """ + Compare current xml with the configured values + + :params vmxml: the guest xml + :params os_attrs: the os attributes dict + """ + os_xml = vmxml.os + current_os_attrs = os_xml.fetch_attrs() + for key in os_attrs: + if key in current_os_attrs: + if key == "nvram_attrs": + current_os_attrs[key].pop("templateFormat") + if "format" not in os_attrs[key]: + os_attrs[key]["format"] = "raw" + + if os_attrs[key] != current_os_attrs[key]: + test.fail("Configured os xml value {} doesn't match the" + " entry {} in guest xml".format(os_attrs[key], current_os_attrs[key])) + else: + test.fail("Configured os attributes {} don't existed in guest.".format(key)) + + vm_name = guest_os.get_vm(params) + firmware_type = params.get("firmware_type") + nvram_file = os.path.join(get_data_dir(), "test.fd") + nvram_attrs = eval(params.get("nvram_attrs")) + os_dict = eval(params.get("os_dict")) + seclabel_label = params.get("seclabel_label") + seclabel_model = params.get("seclabel_model") + error_msg = params.get("error_msg", "") + without_label = "yes" == params.get("without_label", "no") + 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() + + try: + if without_label: + nvram_source = eval(params.get("nvram_source") % (seclabel_model, nvram_file)) + else: + nvram_source = eval(params.get("nvram_source") % (seclabel_label, seclabel_model, nvram_file)) + os_attrs = {**os_dict, **nvram_attrs, **nvram_source} + guest_os.prepare_os_xml(vm_name, os_attrs, firmware_type) + vmxml = guest_os.check_vm_startup(vm, vm_name, error_msg) + if error_msg: + return + test.log.info("Check the os xml in dumpxml") + compare_guest_xml(vmxml, os_attrs) + test.log.info("Check the nvram file label in host") + label_result = process.run("ls -lZ {}".format(nvram_file)).stdout_text + if seclabel_model == "dac": + seclabel_label = seclabel_label.replace(":", " ") + if seclabel_label in label_result: + test.log.info("Get expected nvram file label: {}".format(label_result)) + else: + test.fail("The nvram file label {} is not expected".format(label_result)) + finally: + if vm.is_alive(): + virsh.destroy(vm_name) + if os.path.exists(nvram_file): + os.remove(nvram_file) + bkxml.sync() diff --git a/libvirt/tests/src/guest_resource_control/control_cgroup.py b/libvirt/tests/src/guest_resource_control/control_cgroup.py index 94964830cbf..88951c7ba33 100644 --- a/libvirt/tests/src/guest_resource_control/control_cgroup.py +++ b/libvirt/tests/src/guest_resource_control/control_cgroup.py @@ -20,6 +20,25 @@ logging = log.getLogger('avocado.' + __name__) +def cancel_if_cpu_controller_not_mounted(test): + """ + Following is to deal the situation when realtime task existing. + In this situation, cpu controller cannot be enabled. + FYI: https://bugzilla.redhat.com/show_bug.cgi?id=1513930#c21 + + :param test: the test instance for failure reporting + """ + with open('/proc/mounts', 'r') as mnts: + cg_mount_point = re.findall(r"\s(\S*cgroup)\s", mnts.read())[0] + cg_subtree_file = os.path.join(cg_mount_point, + "cgroup.subtree_control") + with open(cg_subtree_file, 'r') as cg_subtree: + if "cpu" not in cg_subtree.read().replace("cpuset", ""): + test.cancel("CPU controller not mounted. This is a " + "limitation of cgroup v2 when realtime task " + "existing on host.") + + def run(test, params, env): """ Cgroup related cases in function 'guest resource control' @@ -165,21 +184,9 @@ def do_extra_operations(operations="daemon-reload"): vmxml_backup = vmxml.copy() cgtest = CgroupTest(None) - if cgtest.is_cgroup_v2_enabled(): + is_cgroup_v2 = cgtest.is_cgroup_v2_enabled() + if is_cgroup_v2: logging.info("The case executed on cgroup v2 environment.") - # Following is to deal the situation when realtime task existing. - # In this situation, cpu controller cannot be enabled. - # FYI: https://bugzilla.redhat.com/show_bug.cgi?id=1513930#c21 - if "schedinfo" in virsh_cmd: - with open('/proc/mounts', 'r') as mnts: - cg_mount_point = re.findall(r"\s(\S*cgroup)\s", mnts.read())[0] - cg_subtree_file = os.path.join(cg_mount_point, - "cgroup.subtree_control") - with open(cg_subtree_file, 'r') as cg_subtree: - if "cpu" not in cg_subtree.read().replace("cpuset", ""): - test.cancel("CPU controller not mounted. This is a " - "limitation of cgroup v2 when realtime task " - "existing on host.") else: logging.info("The case executed on cgroup v1 environment.") @@ -212,6 +219,8 @@ def do_extra_operations(operations="daemon-reload"): try: if start_vm == "yes" and not vm.is_alive(): vm.start() + if "schedinfo" in virsh_cmd and is_cgroup_v2: + cancel_if_cpu_controller_not_mounted(test) vm.wait_for_login().close() virsh_cmd_line = prepare_virsh_cmd(vm_name, virsh_cmd, virsh_cmd_param, @@ -230,6 +239,8 @@ def do_extra_operations(operations="daemon-reload"): if "--config" in virsh_cmd_options: try: vm.start() + if "schedinfo" in virsh_cmd and is_cgroup_v2: + cancel_if_cpu_controller_not_mounted(test) vm.wait_for_login().close() if "iothread" in virsh_cmd_line: add_iothread(vm) diff --git a/libvirt/tests/src/virsh_cmd/domain/virsh_blkiotune.py b/libvirt/tests/src/guest_resource_control/virsh_blkiotune.py similarity index 97% rename from libvirt/tests/src/virsh_cmd/domain/virsh_blkiotune.py rename to libvirt/tests/src/guest_resource_control/virsh_blkiotune.py index 23c89d2f021..9fa4c2f0134 100644 --- a/libvirt/tests/src/virsh_cmd/domain/virsh_blkiotune.py +++ b/libvirt/tests/src/guest_resource_control/virsh_blkiotune.py @@ -212,8 +212,11 @@ def set_blkio_parameter(test, params, cgstop): if validate_vm_not_start: result = virsh.start(vm_name, debug=True) vm_not_start_error_msg = params.get("vm_not_start_error_msg") - if vm_not_start_error_msg not in result.stderr_text: - test.fail("can not find error message: %s" % vm_not_start_error_msg) + if result.exit_status: + if vm_not_start_error_msg in result.stderr_text: + logging.info("Get the expected error message: %s" % vm_not_start_error_msg) + else: + test.fail("Get unexpected result: %s" % result.stderr_text) def prepare_scheduler(params, test, vm): diff --git a/libvirt/tests/src/host_hypervisor/domcapabilities_output.py b/libvirt/tests/src/host_hypervisor/domcapabilities_output.py index 21f4d4dc44f..163c1ac8f2d 100644 --- a/libvirt/tests/src/host_hypervisor/domcapabilities_output.py +++ b/libvirt/tests/src/host_hypervisor/domcapabilities_output.py @@ -1,6 +1,7 @@ import os from virttest.libvirt_xml import domcapability_xml +from virttest import libvirt_version def get_ovmf_path(): @@ -59,6 +60,17 @@ def test_rm_ovmf_path(test): "is recovered", dir_ovmf_path) +def test_check_iface_backend(test): + domcapa_xml = domcapability_xml.DomCapabilityXML() + get_iface = domcapa_xml.xmltreefile.findall('/devices/interface/enum/value') + get_backend_list = set([i.text for i in get_iface]) + test.log.debug("interface backend supported includes: %s", get_backend_list) + support_list = {'passt', 'default'} + if get_backend_list != support_list: + test.fail("current support interface backend should be %s, " + "but it's %s", support_list, get_backend_list) + + def run(test, params, env): """ This file includes to test scenarios for checking outputs of @@ -69,5 +81,6 @@ def run(test, params, env): """ test_case = params.get("test_case", "") + libvirt_version.is_libvirt_feature_supported(params) run_test = eval("test_%s" % test_case) run_test(test) diff --git a/libvirt/tests/src/in_place_upgrade_guest.py b/libvirt/tests/src/in_place_upgrade_guest.py new file mode 100644 index 00000000000..75a6ec9d741 --- /dev/null +++ b/libvirt/tests/src/in_place_upgrade_guest.py @@ -0,0 +1,210 @@ +# pylint: disable=spelling +# disable pylint spell checker to allow for leapp and preupgrade +import re +import os +import textwrap + +from avocado.utils import process + +from virttest import utils_package +from virttest import utils_test + + +def run(test, params, env): + """ + This case verifies that an in place upgrade on a guest succeeds. + This test only supports upgrading a RHEL X-1 guest to RHEL X on a RHEL X host. + This test ensures that, when relevant, the page size does not change after upgrade. + + :params test: test object + :params params: wrapped dict with all parameters + :params env: environment object + """ + vm_name = params.get("main_vm") + vm = env.get_vm(vm_name) + + try: + if not vm.is_alive(): + vm.start() + session = vm.wait_for_login() + + source_release, target_release = get_release_info(test, params, session) + check_support(test, source_release, target_release) + + pagesize_check_cmd = params.get("pagesize_check_cmd") + target_page_size = session.cmd_output(pagesize_check_cmd).strip() + + utils_package.package_install(["leapp-upgrade*"], session=session, timeout=360) + + prepare_repos_in_guest(test, params, vm, target_release) + + run_leapp_cmd(test, params, session, step="preupgrade") + run_leapp_cmd(test, params, session, step="upgrade") + session = vm.reboot(session=session, timeout=900) + + verify_upgrade_succeeded(test, params, vm, session, target_release, target_page_size) + + session.close() + + finally: + if vm.is_alive(): + vm.destroy(gracefully=False) + + +def get_release_info(test, params, session): + """ + Get the source release and target release versions + + :params test: test object + :params params: wrapped dict with all parameters + :params session: the vm session + :return: tuple, (source version, target version) + """ + release_check_cmd = params.get("release_check_cmd") + test.log.debug("Getting source release (same as release on vm)") + source_release = extract_release_version(test, session.cmd_output(release_check_cmd)) + test.log.debug("Getting target release (same as release on host)") + target_release = extract_release_version(test, process.run(release_check_cmd, shell=True).stdout_text) + return (source_release, target_release) + + +def extract_release_version(test, release_output): + """ + Extract the release version from the full release output + + :params test: test object + :params release_output: output from running release_check_cmd + """ + test.log.debug("Full release output: %s" % release_output) + return re.findall("\d+\.\d+", release_output)[0] + + +def check_support(test, source_release, target_release): + """ + Check whether the test supports upgrading from source release to target release + + :params test: test object + :params source_release: source release version (upgrading from version) + :params target_release: target release version (upgrading to version) + """ + source_major_release = int(source_release.split(".")[0]) + target_major_release = int(target_release.split(".")[0]) + + if (source_major_release + 1 != target_major_release): + test.cancel("Can not upgrade guest from rhel %s to rhel %s - " + "This test only supports upgrading a RHEL X-1 guest to RHEL X on a RHEL X host" % + (source_release, target_release)) + else: + test.log.info("Upgrading guest from rhel %s to rhel %s on a rhel %s host" % + (source_release, target_release, target_release)) + + +def prepare_repos_in_guest(test, params, vm, target_release): + """ + Prepare repos in the guest by including the upgrade repos paths + + :params test: test object + :params params: wrapped dict with all parameters + :params session: the vm + :params target_release: target release version + """ + compose_url = params.get("compose_url") + upgrade_repos_path = params.get("upgrade_repos_path") + vm_arch_name = params.get("vm_arch_name") + + target_major_release = target_release.split(".")[0] + + upgrade_repos_content = textwrap.dedent(f""" + [APPSTREAM] + name=APPSTREAM + baseurl={compose_url}/rhel-{target_major_release}/nightly/RHEL-{target_major_release}/latest-RHEL-{target_release}/compose/AppStream/{vm_arch_name}/os/ + enabled=1 + gpgcheck=0 + [BASEOS] + name=BASEOS + baseurl={compose_url}/rhel-{target_major_release}/nightly/RHEL-{target_major_release}/latest-RHEL-{target_release}/compose/BaseOS/{vm_arch_name}/os/ + enabled=1 + gpgcheck=0 + """) + + test.log.debug("Temporarily creating leapp_upgrade_repositories file on the host: %s" % upgrade_repos_content) + tmp_upgrade_repos_path = os.path.join(test.debugdir, "tmp_leapp_upgrade_repositories.repo") + with open(tmp_upgrade_repos_path, 'w+') as f: + f.write(upgrade_repos_content) + + test.log.info("Copying leapp_upgrade_repositories file onto the guest") + vm.copy_files_to(host_path=tmp_upgrade_repos_path, guest_path=upgrade_repos_path) + + +def run_leapp_cmd(test, params, session, step): + """ + Run the leapp (pre)upgrade cmd + + :params test: test object + :params params: wrapped dict with all parameters + :params session: the vm session + :params step: "preupgrade" or "upgrade" + """ + leapp_cmd = params.get("leapp_preupgrade_cmd") + if step == "upgrade": + leapp_cmd = params.get("leapp_upgrade_cmd") + + status = session.cmd_status(leapp_cmd, timeout=900) + if status == 0: + test.log.info("Leapp %s executed successfully" % step) + else: + test.fail("Leapp %s failed, see logs for more info" % step) + + +def verify_upgrade_succeeded(test, params, vm, session, target_release, target_page_size): + """ + Verify whether the upgrade succeeded by checking + the release version, the kernel version, and the page size + + :params test: test object + :params params: wrapped dict with all parameters + :params vm: the vm + :params session: the vm session + :params target_release: target release version (guest version after upgrade) + :params target_page_size: target page size (result of pagesize_check_cmd) + """ + vm_arch_name = params.get("vm_arch_name") + release_check_cmd = params.get("release_check_cmd") + kernel_check_cmd = params.get("kernel_check_cmd") + pagesize_check_cmd = params.get("pagesize_check_cmd") + + test.log.debug("Getting guest release after upgrade") + post_release_output = extract_release_version(test, session.cmd_output(release_check_cmd)) + if target_release not in post_release_output: + test.fail("The guest after upgrade should be at rhel %s, but is at %s" % + (target_release, post_release_output)) + else: + test.log.info("The guest after upgrade is at rhel %s, as expected" % post_release_output) + + target_major_release = target_release.split(".")[0] + test.log.debug("Getting guest kernel version after upgrade") + post_kernel_output = session.cmd_output(kernel_check_cmd).strip() + if (".el%s" % target_major_release) not in post_kernel_output: + test.fail("The guest after upgrade should be at kernel version .el%s, but is at %s" % + (target_major_release, post_kernel_output)) + else: + test.log.info("The guest after upgrade is at kernel version .el%s (%s), as expected" % + (target_major_release, post_kernel_output)) + + post_page_size = session.cmd_output(pagesize_check_cmd).strip() + if vm_arch_name == "aarch64" and target_page_size != post_page_size: + # Note: the following is a workaround that should be removed after the leapp tool provides 64k support on aarch64 + test.log.info("Guest page size before upgrade (%s) does not match page size after upgrade (%s)" % + (target_page_size, post_page_size)) + test.log.info("Attempting temporary workaround to update the guest default kernel") + kernel_pattern = ".*el%s.*%sk" % (target_release.replace(".", "_"), int(target_page_size) // 1024) + kernel_version = utils_test.get_available_kernel_paths(session, kernel_pattern)[0] + utils_test.update_vm_default_kernel(vm, kernel_version, reboot=True, guest_arch_name=vm_arch_name, timeout=900) + + session = vm.wait_for_login() + post_page_size = session.cmd_output(pagesize_check_cmd).strip() + if target_page_size != post_page_size: + test.fail("Guest page size before upgrade (%s) does not match page size after upgrade and workaround (%s)" % + (target_page_size, post_page_size)) + else: + test.log.info("Guest page size after upgrade and workaround is %s, as expected" % post_page_size) diff --git a/libvirt/tests/src/incremental_backup/incremental_backup_backing_chain.py b/libvirt/tests/src/incremental_backup/incremental_backup_backing_chain.py index 9e18cbe5c30..2ebd1f62cd8 100644 --- a/libvirt/tests/src/incremental_backup/incremental_backup_backing_chain.py +++ b/libvirt/tests/src/incremental_backup/incremental_backup_backing_chain.py @@ -192,6 +192,8 @@ def create_shutoff_snapshot(original_img, snapshot_img): blockcopy_reuse = params.get("blockcopy_reuse") backup_error = "yes" == params.get("backup_error") tmp_dir = data_dir.get_tmp_dir() + with_data_file = "yes" == params.get("with_data_file", "no") + libvirt_version.is_libvirt_feature_supported(params) try: vm_name = params.get("main_vm") @@ -217,8 +219,12 @@ def create_shutoff_snapshot(original_img, snapshot_img): if original_disk_type == "local": image_name = "%s_image.qcow2" % original_disk_target disk_path = os.path.join(tmp_dir, image_name) + data_file = os.path.join(tmp_dir, "datastore") + if with_data_file: + data_file_option = params.get("data_file_option", "") % data_file + extra_cmd = "" if not with_data_file else data_file_option libvirt.create_local_disk("file", disk_path, original_disk_size, - "qcow2") + "qcow2", extra=extra_cmd) disk_params = {"device_type": "disk", "type_name": "file", "driver_type": "qcow2", @@ -233,6 +239,11 @@ def create_shutoff_snapshot(original_img, snapshot_img): virsh.attach_device(vm.name, disk_xml, flagstr="--config", debug=True) vm.start() + guest_xml = virsh.dumpxml(vm_name).stdout_text + logging.debug("The current guest xml is:%s" % guest_xml) + if with_data_file: + if data_file not in guest_xml: + test.fail("The datastore file xml can't be generated automatically in guest!") session = vm.wait_for_login() new_disks_in_vm = list(utils_disk.get_linux_disks(session).keys()) session.close() diff --git a/libvirt/tests/src/incremental_backup/incremental_backup_checkpoint_cmd.py b/libvirt/tests/src/incremental_backup/incremental_backup_checkpoint_cmd.py index 837345c7aa8..432f116612d 100644 --- a/libvirt/tests/src/incremental_backup/incremental_backup_checkpoint_cmd.py +++ b/libvirt/tests/src/incremental_backup/incremental_backup_checkpoint_cmd.py @@ -2,12 +2,14 @@ import re import logging as log import operator +import aexpect from virttest import virsh from virttest import data_dir from virttest import libvirt_version from virttest import utils_disk from virttest import utils_backup +from virttest import remote from virttest.libvirt_xml import vm_xml from virttest.libvirt_xml import checkpoint_xml from virttest.libvirt_xml.devices import graphics @@ -41,6 +43,45 @@ def prepare_checkpoints(disk="vdb", num=1, cp_prefix="test_checkpoint_"): virsh.checkpoint_create_as(vm_name, options, **virsh_dargs) current_checkpoints.append(checkpoint_name) + def edit_checkpoint(vm_name, checkpoint_name, restore=False): + """ + Edit the checkpoints. + + :param vm_name: the domain name + :param checkpoint_name: the checkpoint name + :params restore: determine whether to restore the modified checkpoint + """ + checkpoint_dumpxml = virsh.checkpoint_dumpxml(vm_name, checkpoint_name, "--no-domain") + session = aexpect.ShellSession("sudo -s") + try: + session.sendline("virsh checkpoint-edit %s %s" % (vm_name, checkpoint_name)) + if not restore: + test.log.debug("The checkpoint dumpxml before edit: %s", + checkpoint_dumpxml.stdout_text) + edit_cmd = ":%s#checkpoint='no'#checkpoint='bitmap'#" + else: + edit_cmd = ":%s###" + session.sendline(edit_cmd) + session.send('\x1b') + session.send('ZZ') + remote.handle_prompts(session, None, None, r"[\#\$]\s*$") + session.close() + edit_result = virsh.checkpoint_dumpxml( + vm_name, + checkpoint_name, + "--no-domain", + debug=True + ).stdout_text.strip() + if not restore: + if edit_result.count("bitmap") == 4: + test.log.debug("Edit checkpoint succeeded!") + else: + test.fail("Expect 'bitmap' for four times, but not found!") + except (aexpect.ShellError, aexpect.ExpectError) as details: + log = session.get_output() + session.close() + test.fail("Edit checkpoint failed: %s" % details) + # Cancel the test if libvirt version is too low if not libvirt_version.version_compare(6, 0, 0): test.cancel("Current libvirt version doesn't support " @@ -55,6 +96,8 @@ def prepare_checkpoints(disk="vdb", num=1, cp_prefix="test_checkpoint_"): tmp_dir = data_dir.get_tmp_dir() current_checkpoints = [] virsh_dargs = {'debug': True, 'ignore_status': False} + with_data_file = "yes" == params.get("with_data_file", "no") + libvirt_version.is_libvirt_feature_supported(params) try: vm_name = params.get("main_vm") @@ -75,8 +118,12 @@ def prepare_checkpoints(disk="vdb", num=1, cp_prefix="test_checkpoint_"): disk_path = "" image_name = "{}_image.qcow2".format(test_disk_target) disk_path = os.path.join(tmp_dir, image_name) + data_file = os.path.join(tmp_dir, "datastore") + if with_data_file: + data_file_option = params.get("data_file_option", "") % data_file + extra_cmd = "" if not with_data_file else data_file_option libvirt.create_local_disk("file", disk_path, test_disk_size, - "qcow2") + "qcow2", extra=extra_cmd) disk_params = {"device_type": "disk", "type_name": "file", "driver_type": "qcow2", @@ -86,6 +133,11 @@ def prepare_checkpoints(disk="vdb", num=1, cp_prefix="test_checkpoint_"): virsh.attach_device(vm.name, disk_xml, flagstr="--config", **virsh_dargs) vm.start() + guest_xml = virsh.dumpxml(vm_name).stdout_text + logging.debug("The current guest xml is:%s" % guest_xml) + if with_data_file: + if data_file not in guest_xml: + test.fail("The datastore file xml can't be generated automatically in guest!") session = vm.wait_for_login() new_disks_in_vm = list(utils_disk.get_linux_disks(session).keys()) session.close() @@ -299,6 +351,9 @@ def prepare_checkpoints(disk="vdb", num=1, cp_prefix="test_checkpoint_"): if ((vm_name in stdout and cmd_flag == "--without-checkpoint") or (vm_name not in stdout and cmd_flag == "--with-checkpoint")): test.fail("virsh list with '%s' contains wrong data" % cmd_flag) + elif checkpoint_cmd == "checkpoint_edit": + edit_checkpoint(vm_name, current_checkpoints[0]) + edit_checkpoint(vm_name, current_checkpoints[0], restore=True) # Make sure vm is running and check checkpoints can be normally deleted if not vm.is_alive(): vm.start() diff --git a/libvirt/tests/src/incremental_backup/incremental_backup_event_monitor.py b/libvirt/tests/src/incremental_backup/incremental_backup_event_monitor.py index 95aa815e82e..28fc4a7a235 100644 --- a/libvirt/tests/src/incremental_backup/incremental_backup_event_monitor.py +++ b/libvirt/tests/src/incremental_backup/incremental_backup_event_monitor.py @@ -42,6 +42,8 @@ def run(test, params, env): usage_threshold = params.get("usage_threshold", "100") tmp_dir = data_dir.get_tmp_dir() local_hostname = params.get("loal_hostname", "localhost") + with_data_file = "yes" == params.get("with_data_file", "no") + libvirt_version.is_libvirt_feature_supported(params) # Backup config scratch_type = params.get("scratch_type", "file") reuse_scratch_file = "yes" == params.get("reuse_scratch_file") @@ -115,8 +117,12 @@ def is_event_captured(virsh_session, re_pattern): disk_path = "" image_name = "{}_image.qcow2".format(original_disk_target) disk_path = os.path.join(tmp_dir, image_name) + data_file = os.path.join(tmp_dir, "datastore") + if with_data_file: + data_file_option = params.get("data_file_option", "") % data_file + extra_cmd = "" if not with_data_file else data_file_option libvirt.create_local_disk("file", disk_path, original_disk_size, - "qcow2") + "qcow2", extra=extra_cmd) disk_params = {"device_type": "disk", "type_name": "file", "driver_type": "qcow2", @@ -127,6 +133,11 @@ def is_event_captured(virsh_session, re_pattern): virsh.attach_device(vm.name, disk_xml, flagstr="--config", debug=True) vm.start() + guest_xml = virsh.dumpxml(vm_name).stdout_text + logging.debug("The current guest xml is:%s" % guest_xml) + if with_data_file: + if data_file not in guest_xml: + test.fail("The datastore file xml can't be generated automatically in guest!") session = vm.wait_for_login() new_disks_in_vm = list(utils_disk.get_linux_disks(session).keys()) session.close() diff --git a/libvirt/tests/src/incremental_backup/incremental_backup_multidisk.py b/libvirt/tests/src/incremental_backup/incremental_backup_multidisk.py index 94c8642f1af..daf3bf3bbd6 100644 --- a/libvirt/tests/src/incremental_backup/incremental_backup_multidisk.py +++ b/libvirt/tests/src/incremental_backup/incremental_backup_multidisk.py @@ -49,6 +49,8 @@ def get_disks_need_backup(disk_dict): total_test_disk = int(params.get("total_test_disk", 3)) tmp_dir = data_dir.get_tmp_dir() backup_error = "yes" == params.get("backup_error") + with_data_file = "yes" == params.get("with_data_file", "no") + libvirt_version.is_libvirt_feature_supported(params) # Backup setting scratch_type = params.get("scratch_type", "file") @@ -108,9 +110,13 @@ def prepare_disk_img(test_disk): """ image_name = "{}_image.qcow2".format(test_disk) image_path = os.path.join(tmp_dir, image_name) + data_file = os.path.join(tmp_dir, test_disk) + if with_data_file: + data_file_option = params.get("data_file_option", "") % data_file + extra_cmd = "" if not with_data_file else data_file_option libvirt.create_local_disk("file", image_path, test_disk_size, - "qcow2") - return image_path + "qcow2", extra=extra_cmd) + return image_path, data_file def prepare_disk_xml(test_disk, image_path): """ @@ -209,7 +215,7 @@ def prepare_checkpoint_xml(backup_disks, all_vm_disks): enable_incremental_backup = True backup_params["backup_incremental"] = checkpoint_list[-1] # Prepare disk image - image_path = prepare_disk_img(test_disk) + image_path, data_file = prepare_disk_img(test_disk) # Prepare disk xml to be hotplugged test_disk_xml = prepare_disk_xml(test_disk, image_path) # Hotplug disk @@ -217,6 +223,11 @@ def prepare_checkpoint_xml(backup_disks, all_vm_disks): ignore_status=False) test_disk_dict[test_disk]['path'] = image_path test_disk_dict[test_disk]['is_attached'] = True + guest_xml = virsh.dumpxml(vm_name).stdout_text + logging.debug("The current guest xml is:%s" % guest_xml) + if with_data_file: + if data_file not in guest_xml: + test.fail("The datastore file xml can't be generated automatically in guest!") # Now we use attached disk as backup disks backup_disks = get_disks_need_backup(test_disk_dict) vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) diff --git a/libvirt/tests/src/incremental_backup/incremental_backup_pull_mode.py b/libvirt/tests/src/incremental_backup/incremental_backup_pull_mode.py index 888e3dab3e8..a60d75d4090 100644 --- a/libvirt/tests/src/incremental_backup/incremental_backup_pull_mode.py +++ b/libvirt/tests/src/incremental_backup/incremental_backup_pull_mode.py @@ -50,6 +50,8 @@ def run(test, params, env): local_user_name = params.get("local_user_name", "root") local_user_password = params.get("local_user_password", "redhat") tmp_dir = data_dir.get_tmp_dir() + with_data_file = "yes" == params.get("with_data_file", "no") + libvirt_version.is_libvirt_feature_supported(params) # Backup config scratch_type = params.get("scratch_type", "file") reuse_scratch_file = "yes" == params.get("reuse_scratch_file") @@ -150,8 +152,15 @@ def run(test, params, env): if original_disk_type == "local": image_name = "{}_image.qcow2".format(original_disk_target) disk_path = os.path.join(tmp_dir, image_name) + data_file = os.path.join(tmp_dir, "datastore") + for file in [disk_path, data_file]: + if os.path.exists(file): + os.remove(file) + if with_data_file: + data_file_option = params.get("data_file_option", "") % data_file + extra_cmd = "" if not with_data_file else data_file_option libvirt.create_local_disk("file", disk_path, original_disk_size, - "qcow2") + "qcow2", extra=extra_cmd) disk_params = {"device_type": "disk", "type_name": "file", "driver_type": "qcow2", @@ -213,6 +222,11 @@ def run(test, params, env): virsh.attach_device(vm.name, disk_xml, flagstr="--config", debug=True) vm.start() + guest_xml = virsh.dumpxml(vm_name).stdout_text + logging.debug("The current guest xml is:%s" % guest_xml) + if with_data_file: + if data_file not in guest_xml: + test.fail("The datastore file xml can't be generated automatically in guest!") session = vm.wait_for_login() new_disks_in_vm = list(utils_disk.get_linux_disks(session).keys()) session.close() diff --git a/libvirt/tests/src/incremental_backup/incremental_backup_push_mode.py b/libvirt/tests/src/incremental_backup/incremental_backup_push_mode.py index f23552798a3..48db1776188 100644 --- a/libvirt/tests/src/incremental_backup/incremental_backup_push_mode.py +++ b/libvirt/tests/src/incremental_backup/incremental_backup_push_mode.py @@ -67,6 +67,9 @@ def backup_job_done(vm_name, vm_disk): backup_error = "yes" == params.get("backup_error") expect_backup_canceled = "yes" == params.get("expect_backup_canceled") tmp_dir = data_dir.get_data_dir() + with_data_file = "yes" == params.get("with_data_file", "no") + with_readonly = "yes" == params.get("with_readonly", "no") + libvirt_version.is_libvirt_feature_supported(params) virsh_dargs = {'debug': True, 'ignore_status': True} try: @@ -87,10 +90,15 @@ def backup_job_done(vm_name, vm_disk): if original_disk_type == "local": image_name = "{}_image.qcow2".format(original_disk_target) disk_path = os.path.join(tmp_dir, image_name) - if os.path.exists(disk_path): - os.remove(disk_path) + data_file = os.path.join(tmp_dir, "datastore") + for file in [disk_path, data_file]: + if os.path.exists(file): + os.remove(file) + if with_data_file: + data_file_option = params.get("data_file_option", "") % data_file + extra_cmd = "" if not with_data_file else data_file_option libvirt.create_local_disk("file", disk_path, original_disk_size, - "qcow2") + "qcow2", extra=extra_cmd) disk_params = {"device_type": "disk", "type_name": "file", "driver_type": "qcow2", @@ -167,6 +175,11 @@ def backup_job_done(vm_name, vm_disk): virsh.attach_device(vm.name, disk_xml, flagstr="--config", debug=True) vm.start() + guest_xml = virsh.dumpxml(vm_name).stdout_text + logging.debug("The current guest xml is:%s" % guest_xml) + if with_data_file: + if data_file not in guest_xml: + test.fail("The datastore file xml can't be generated automatically in guest!") session = vm.wait_for_login() new_disks_in_vm = list(utils_disk.get_linux_disks(session).keys()) session.close() @@ -251,12 +264,13 @@ def backup_job_done(vm_name, vm_disk): # Start backup backup_options = backup_xml.xml + " " + checkpoint_xml.xml + if with_readonly: + backup_options = backup_xml.xml + if backup_index == 0: + virsh.checkpoint_create(vm_name, checkpoint_xml.xml, **virsh_dargs) # Create some data in vdb - dd_count = "1" - if expect_backup_canceled: - # Generate more data to extend the backup job duration - dd_count = "100" + dd_count = params.get("dd_count", "1") dd_seek = str(backup_index * 10 + 10) dd_bs = "1M" session = vm.wait_for_login() @@ -266,6 +280,18 @@ def backup_job_done(vm_name, vm_disk): if reuse_target_file: backup_options += " --reuse-external" + if with_readonly and backup_index == 0: + virsh.detach_device(vm_name, disk_xml, + flagstr="--config", debug=True) + virsh.destroy(vm_name) + disk_params.update({"readonly": "yes"}) + disk_xml_readonly = libvirt.create_disk_xml(disk_params) + virsh.attach_device(vm.name, disk_xml_readonly, + flagstr="--config", debug=True) + virsh.start(vm_name, debug=True) + vm.wait_for_login().close() + test.log.debug("The current disk xml is: %s" + % virsh.dumpxml(vm_name, "--xpath //disk").stdout_text) backup_result = virsh.backup_begin(vm_name, backup_options, debug=True) if backup_result.exit_status: @@ -287,9 +313,16 @@ def backup_job_done(vm_name, vm_disk): if not utils_misc.wait_for( lambda: backup_job_done(vm_name, original_disk_target), 60): test.fail("Backup job not finished in 60s") + if with_readonly: + img_info = utils_misc.get_image_info(target_file_path) + if img_info['dsize'] >= 100: + test.log.info("The disk size is acceptable.") + else: + test.fail("Can't get the expected disk size!") - for checkpoint_name in checkpoint_list: - virsh.checkpoint_delete(vm_name, checkpoint_name, debug=True) + if not with_readonly: + for checkpoint_name in checkpoint_list: + virsh.checkpoint_delete(vm_name, checkpoint_name, debug=True) if vm.is_alive(): vm.destroy(gracefully=False) diff --git a/libvirt/tests/src/libvirt_hooks.py b/libvirt/tests/src/libvirt_hooks.py index 4809eb4c47e..169fb2eeb09 100644 --- a/libvirt/tests/src/libvirt_hooks.py +++ b/libvirt/tests/src/libvirt_hooks.py @@ -4,6 +4,7 @@ import platform import time +from avocado.utils import distro from avocado.utils import process from virttest import virt_vm @@ -53,6 +54,9 @@ def prepare_hook_file(hook_op): with open(hook_file, 'w') as hf: hf.write('\n'.join(hook_lines)) os.chmod(hook_file, 0o755) + if distro.detect().name == 'rhel' and int(distro.detect().version) > 9: + process.run("restorecon -Rv /etc/libvirt/hooks", ignore_status=False, shell=True) + process.run("setsebool -P virt_hooks_unconfined on", ignore_status=False, shell=True) # restart libvirtd libvirtd.restart() @@ -85,6 +89,7 @@ def start_stop_hook(): """ Do start/stop operation and check the results. """ + release_reason = params.get("release_reason", "-") logging.info("Try to test start/stop hooks...") hook_para = "%s %s" % (hook_file, vm_name) prepare_hook_file(hook_script % @@ -102,7 +107,10 @@ def start_stop_hook(): vm.destroy() hook_str = hook_para + " stopped end -" assert check_hooks(hook_str) - hook_str = hook_para + " release end -" + if libvirt_version.version_compare(10, 5, 0): + hook_str = hook_para + " release end " + release_reason + else: + hook_str = hook_para + " release end -" assert check_hooks(hook_str) except AssertionError: utils_misc.log_last_traceback() @@ -488,11 +496,11 @@ def run_scale_test(): lxc_hook() except virt_vm.VMStartError as e: - logging.info(str(e)) if start_error: + logging.info(str(e)) pass else: - test.fail('VM Failed to start for some reason!') + test.fail(f"VM Failed to start: {str(e)}") else: if start_error: test.fail('VM started unexpected') diff --git a/libvirt/tests/src/libvirt_mem.py b/libvirt/tests/src/libvirt_mem.py index 69584fafc90..d37006e5309 100644 --- a/libvirt/tests/src/libvirt_mem.py +++ b/libvirt/tests/src/libvirt_mem.py @@ -55,6 +55,16 @@ def run(test, params, env): new_max_mem = None new_cur_mem = None + def get_hugepage_num(total_huge_page_size): + """ + Calculate huge page number according to total huge page size. + + :param total_huge_page_size: required total huge page size in KiB + :return: huge page number required + """ + default_mem_huge_page_size = utils_memory.get_huge_page_size() + return int(total_huge_page_size) // default_mem_huge_page_size + def consume_vm_mem(size=1000, timeout=360): """ To consume guest memory, default size is 1000M @@ -359,8 +369,8 @@ def modify_domain_xml(): align_to_value)) cells[cell]["memory"] = memory_value cpu_xml = vm_xml.VMCPUXML() - cpu_xml.xml = "" - cpu_mode = params.get("cpu_mode") + cpu_mode = params.get("cpu_mode", "host-model") + cpu_xml.xml = "" % cpu_mode model_fallback = params.get("model_fallback") if cpu_mode: cpu_xml.mode = cpu_mode @@ -436,7 +446,6 @@ def modify_domain_xml(): tg_node = params.get("tg_node", 0) pg_size = params.get("page_size") pg_unit = params.get("page_unit", "KiB") - huge_page_num = int(params.get('huge_page_num', 2000)) node_mask = params.get("node_mask", "0") mem_addr = ast.literal_eval(params.get("memory_addr", "{}")) huge_pages = [ast.literal_eval(x) @@ -448,15 +457,22 @@ def modify_domain_xml(): config = utils_config.LibvirtQemuConfig() setup_hugepages_flag = params.get("setup_hugepages") + total_huge_page_size = params.get("total_huge_page_size") + pg_size = str(utils_memory.getpagesize()) if pg_size else None if (setup_hugepages_flag == "yes"): - cpu_arch = cpu_util.get_family() if hasattr(cpu_util, 'get_family')\ - else cpu_util.get_cpu_arch() - if cpu_arch == 'power8': - pg_size = '16384' - huge_page_num = 200 - elif cpu_arch == 'power9': - pg_size = '2048' - huge_page_num = 2000 + pg_size = utils_memory.get_huge_page_size() + huge_page_num = get_hugepage_num(total_huge_page_size) + # Currently aarch64 host has issue with cpu model or family related info, + # so skip it. + if cpu_util.get_arch() != 'aarch64': + cpu_arch = cpu_util.get_family() if hasattr(cpu_util, 'get_family')\ + else cpu_util.get_cpu_arch() + if cpu_arch == 'power8': + pg_size = '16384' + huge_page_num = 200 + elif cpu_arch == 'power9': + pg_size = '2048' + huge_page_num = 2000 [x.update({'size': pg_size}) for x in huge_pages] setup_hugepages(int(pg_size), shp_num=huge_page_num) @@ -499,7 +515,8 @@ def modify_domain_xml(): elif discard: vm.start() session = vm.wait_for_login() - check_qemu_cmd(max_mem_rt, tg_size) + if test_qemu_cmd: + check_qemu_cmd(max_mem_rt, tg_size) dev_xml = None # To attach the memory device. @@ -589,7 +606,8 @@ def modify_domain_xml(): if mem_align: dom_mem = check_mem_align() - check_qemu_cmd(dom_mem['maxMemory'], dom_mem['attached_mem']) + if test_qemu_cmd: + check_qemu_cmd(dom_mem['maxMemory'], dom_mem['attached_mem']) if hot_plug and params['delta'] != dom_mem['attached_mem']: test.fail('Memory after attach not equal to original mem + attached mem') @@ -727,9 +745,11 @@ def _wait_for_vm_start(): # Remove dmesg temp file if os.path.exists(dmesg_file): os.remove(dmesg_file) - except xcepts.LibvirtXMLError: + except xcepts.LibvirtXMLError as e: if define_error: pass + else: + raise e finally: # Delete snapshots. snapshot_lists = virsh.snapshot_list(vm_name) diff --git a/libvirt/tests/src/libvirt_package.py b/libvirt/tests/src/libvirt_package.py index 8ef95a06dfb..31a775f78cb 100644 --- a/libvirt/tests/src/libvirt_package.py +++ b/libvirt/tests/src/libvirt_package.py @@ -37,7 +37,7 @@ def run(test, params, env): elif libvirtd_state == "off": utils_libvirtd.libvirtd_stop() # if package exist, remove it - sm = software_manager.SoftwareManager() + sm = software_manager.manager.SoftwareManager() pkg_exist = [] for item in pkg_list: if sm.check_installed(item): diff --git a/libvirt/tests/src/libvirt_vcpu_plug_unplug.py b/libvirt/tests/src/libvirt_vcpu_plug_unplug.py index d59c78bc969..470495062aa 100644 --- a/libvirt/tests/src/libvirt_vcpu_plug_unplug.py +++ b/libvirt/tests/src/libvirt_vcpu_plug_unplug.py @@ -14,12 +14,16 @@ from virttest.utils_test import libvirt from virttest.libvirt_xml.vm_xml import VMXML +from provider.cpu import patch_total_cpu_count_s390x + + vm_uptime_init = 0 # Using as lower capital is not the best way to do, but this is just a # workaround to avoid changing the entire file. logging = log.getLogger('avocado.' + __name__) +patch_total_cpu_count_s390x(cpu_util) def run(test, params, env): diff --git a/libvirt/tests/src/libvirtd_start.py b/libvirt/tests/src/libvirtd_start.py index b6e17c3efe7..08210ced845 100644 --- a/libvirt/tests/src/libvirtd_start.py +++ b/libvirt/tests/src/libvirtd_start.py @@ -82,7 +82,7 @@ def _check_errors(): # In RHEL6 iptables-services and firewalld is not supported # So try to install all required packages but ignore failures logging.info('Preparing firewall related packages') - software_mgr = software_manager.SoftwareManager() + software_mgr = software_manager.manager.SoftwareManager() for pkg in ['iptables', 'iptables-services', 'firewalld']: if not software_mgr.check_installed(pkg): software_mgr.install(pkg) @@ -149,6 +149,7 @@ def _check_errors(): _check_errors() finally: logging.info('Recovering services status') + process.run("rm -rf /run/virtnetworkd.pid", ignore_status=True) #Restart socket service after starting process at foreground utils_libvirtd.Libvirtd("virtnetworkd.socket").restart() # If service do not exists, then backup status and current status diff --git a/libvirt/tests/src/memory/gmap.py b/libvirt/tests/src/memory/gmap.py new file mode 100644 index 00000000000..e6d1551a455 --- /dev/null +++ b/libvirt/tests/src/memory/gmap.py @@ -0,0 +1,139 @@ +import logging as log +import os +from pathlib import Path + +from avocado.core.exceptions import TestError +from virttest import virsh +from virttest.libvirt_xml import vm_xml +from virttest.utils_libvirt import libvirt_vmxml +from virttest.utils_misc import cmd_status_output + + +logging = log.getLogger('avocado.' + __name__) +cleanup_actions = [] + + +def parent(file_path): + """ + Returns the parent directory of a file path + + :param file_path: absolute file path + :return path: absolute path of parent directory + """ + return Path(file_path).parent.absolute() + + +def get_source_disk_path(vmxml): + """ + Returns the absolute path to a disk image for import. + Assume the boot image is the first disk and an image file. + + :param vmxml: VMXML instance + :return: absolute path to the guest's first disk image file + """ + disks = vmxml.get_disk_all() + disk_list = list(disks.values()) + first_disk = disk_list[0] + return first_disk.find('source').get('file') + + +def update_l2_vm(vmxml, l2_mem, fs_dict): + """ + Update the L2 VM to run L3 inside from virtiofs + + :param vmxml: The VMXML instance + :param l2_mem: The new memory size + :param fs_dict: The filesystem device attributes + """ + vmxml.memory = l2_mem + mb = vm_xml.VMMemBackingXML() + mb.access_mode = "shared" + vmxml.mb = mb + vmxml.sync() + fs = libvirt_vmxml.create_vm_device_by_type("filesystem", fs_dict) + source = fs["source"] + source.update({'dir': parent(get_source_disk_path(vmxml))}) + fs["source"] = source + virsh.attach_device(vmxml.vm_name, fs.xml, flagstr="--config", debug=True) + + +def prepare_l3(vmxml): + """ + Prepares the disk for the L3 guest + + :param vmxml: The L2 VMXML instance + """ + l2_disk_path = get_source_disk_path(vmxml) + l3_disk_path = os.path.join(parent(l2_disk_path), "test.qcow2") + cmd = ("qemu-img convert -f qcow2 -O qcow2 -o lazy_refcounts=on" + " {} {}".format(l2_disk_path, l3_disk_path)) + cmd_status_output(cmd) + cleanup_actions.append(lambda: os.unlink(l3_disk_path)) + + +def start_l3(session, target_tag): + """ + Mount the shared directory with the image file and start + the L3 guest with the qemu-kvm command + + :param session: VM session + :param target_tag: virtiofs mount tag + """ + mount_dir = "/mnt" + cmd = "mount -t virtiofs {} {}".format(target_tag, mount_dir) + cmd_status_output(cmd, session=session) + cmd = ("/usr/libexec/qemu-kvm -m 1024 -smp 1" + " -daemonize {}".format(os.path.join(mount_dir, "test.qcow2"))) + s, _ = cmd_status_output(cmd, session=session) + if s: + raise TestError("Couldn't start L3 guest.") + + +def l1_counters_go_up(): + """ + Check that the shadow memory counters go up + """ + base_path = "/sys/kernel/debug/kvm/" + for a in [ + "gmap_shadow_reuse", + "gmap_shadow_create", + "gmap_shadow_sg_entry", + "gmap_shadow_pg_entry" + ]: + with open(os.path.join(base_path, a), "r") as f: + if f.read().strip() == "0": + return False + return True + + +def run(test, params, env): + """ + Test kvm counters for L3 shadow memory + L1: LPAR + L2: KVM guest + L3: nested KVM guest + """ + vm_name = params.get('main_vm') + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + bkxml = vmxml.copy() + cleanup_actions.append(lambda: bkxml.sync()) + vm = env.get_vm(vm_name) + l2_mem = int(params.get("l2_mem", "3906250")) + target_tag = params.get("target_tag") + fs_dict = eval(params.get("fs_dict")) + + try: + update_l2_vm(vmxml, l2_mem, fs_dict) + prepare_l3(vmxml) + logging.debug("VMXML: %s", vm_xml.VMXML.new_from_dumpxml(vm_name)) + vm.start() + cleanup_actions.append(lambda: vm.destroy()) + session = vm.wait_for_login() + cleanup_actions.append(lambda: session.close()) + start_l3(session, target_tag) + if not l1_counters_go_up(): + test.fail("Gmap counters didn't go up.") + finally: + cleanup_actions.reverse() + for action in cleanup_actions: + action() diff --git a/libvirt/tests/src/memory/memory_allocation/define_value_unit.py b/libvirt/tests/src/memory/memory_allocation/define_value_unit.py index b27f17b9680..3455a31eb28 100644 --- a/libvirt/tests/src/memory/memory_allocation/define_value_unit.py +++ b/libvirt/tests/src/memory/memory_allocation/define_value_unit.py @@ -26,7 +26,6 @@ def run(test, params, env): 1:byte/KB/KiB/MB/MiB/GB/GiB/invalid 2:with numa/without numa """ - def run_positive_test(): """ Start guest @@ -50,12 +49,12 @@ def run_positive_test(): test.log.info("TEST_STEP4: Check guest memory value") session = vm.wait_for_login() guest_mem = utils_misc.get_mem_info(session) - session.close() test.log.debug("Get memory value in guest: %s", guest_mem) test.log.info("TEST_STEP5: Check currentmemory change to " "the value and round up to a multiple of default pagesize") - check_mem_after_operation('login') + check_mem_after_operation('login', session) + session.close() vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) current_mem_new = vmxml.get_current_mem() @@ -107,14 +106,14 @@ def check_mem_config(dest_unit): for item in eval(pattern): libvirt_vmxml.check_guest_xml_by_xpaths(vmxml, item) - def check_mem_after_operation(operation="start"): + def check_mem_after_operation(operation="start", session=None): """ Check mem after operation :param operation: guest operation """ new_vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) - result = get_expected_result(operation) + result = get_expected_result(operation, session) for attr in eval(params.get("vm_attrs")).keys(): if attr == "cpu": numa_memory = new_vmxml.cpu.numa_cell[0]['memory'] @@ -134,7 +133,7 @@ def check_mem_after_operation(operation="start"): test.fail('%s should be %s instead of %s ' % (attr, result[attr], new_value)) else: - test.log.debug("Get correct %s=%s in xml", (attr, result[attr])) + test.log.debug("Get correct %s=%s in xml", attr, result[attr]) def set_negative_memory(case): """ @@ -161,7 +160,7 @@ def set_negative_memory(case): cmd_result = virsh.define(vmxml.xml, debug=True) libvirt.check_result(cmd_result, error_msg) - def get_dest_size(source_size, operation="start", check_current_mem=False): + def get_dest_size(source_size, operation="start", check_current_mem=False, session=None): """ Round up the source size and convert dest size according to the operation @@ -177,10 +176,10 @@ def get_dest_size(source_size, operation="start", check_current_mem=False): 1) When the operation is guest login, Verify the current memory value would change to the value set in defined xml and round up to a - multiple of 4KiB(default pagesize), other memory value same as 2): + multiple of 4KiB(default guest pagesize), other memory value same as 2): - 2000000KB = 1953125 KiB, and divide default_pagesize = 488281.25 - rounds up to 488282, than 488282 * default_page = 1953128 KiB + 2000000KB = 1953125 KiB, and divide default guest pagesize = 488281.25 + rounds up to 488282, than 488282 * default guest page = 1953128 KiB 2) When the operation is guest start or login and non-current memory, Verify the memory value @@ -194,9 +193,16 @@ def get_dest_size(source_size, operation="start", check_current_mem=False): dest_unit = 'KiB' convert_size = memory_base.convert_data_size(source_size, dest_unit) - round_up_size = math.ceil(convert_size/default_pagesize) - dest_size = round_up_size * default_pagesize - + conf_page_size = session.cmd_output('getconf PAGE_SIZE') + balloon_pagesize = 4 + test.log.debug('The PAGE_SIZE of guest is %s', conf_page_size) + pagesize_kib = int(conf_page_size) // 1024 + remainder = convert_size % pagesize_kib + if pagesize_kib - remainder < balloon_pagesize: + round_up_size = math.ceil(convert_size / pagesize_kib) + else: + round_up_size = math.floor(convert_size / pagesize_kib) + dest_size = round_up_size * pagesize_kib else: dest_unit = 'MiB' convert_size = memory_base.convert_data_size(source_size, @@ -210,7 +216,7 @@ def get_dest_size(source_size, operation="start", check_current_mem=False): return int(dest_size) - def get_expected_result(operation='start'): + def get_expected_result(operation='start', session=None): """ Get expected memory result. @@ -220,7 +226,8 @@ def get_expected_result(operation='start'): result_dict.update({ 'memory': get_dest_size(mem_value+mem_unit, operation), 'current_mem': get_dest_size(current_mem+current_mem_unit, - operation, check_current_mem=True), + operation, check_current_mem=True, + session=session), "max_mem_rt": get_dest_size(max_mem+max_mem_unit, operation), "numa_memory": get_dest_size(mem_value+mem_unit, operation), }) @@ -233,7 +240,6 @@ def get_expected_result(operation='start'): case = params.get("case") error_msg = params.get("error_msg") - default_pagesize = int(params.get("default_pagesize")) mem_value = params.get("mem_value") mem_unit = params.get("mem_unit") current_mem = params.get("current_mem") diff --git a/libvirt/tests/src/memory/memory_allocation/lifecycle_with_memory_allocation.py b/libvirt/tests/src/memory/memory_allocation/lifecycle_with_memory_allocation.py index 5a9ed6c38fd..c64e6b31f6e 100644 --- a/libvirt/tests/src/memory/memory_allocation/lifecycle_with_memory_allocation.py +++ b/libvirt/tests/src/memory/memory_allocation/lifecycle_with_memory_allocation.py @@ -9,6 +9,7 @@ # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ import os +import re from virttest import virsh from virttest import libvirt_version @@ -30,7 +31,7 @@ def run(test, params, env): 3:with numa topology """ - def run_positive_test(): + def run_test(): """ Start guest Check the qemu cmd line @@ -39,7 +40,16 @@ def run_positive_test(): test.log.info("TEST_STEP1: Define and start vm") vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) vmxml.setup_attrs(**vm_attrs) - vmxml.sync() + + try: + vmxml.sync() + except Exception as e: + if not libvirt_version.version_compare(9, 6, 0) and mem_config == "with_maxmemory": + if not re.search(error_msg, str(e)): + test.fail("Expected to get '%s', but got '%s'" % (error_msg, e)) + return + else: + test.fail("Expect define successfully, but failed with '%s'" % e) if not vm.is_alive(): vm.start() @@ -51,18 +61,21 @@ def run_positive_test(): check_dominfo() check_qemu_cmdline() - test.log.info("TEST_STEP3:Check vm reboot and memory config") + test.log.info("TEST_STEP3:Check vm memory config") + check_mem_config() + + test.log.info("TEST_STEP4:Check vm reboot and memory config") virsh.reboot(vm_name, ignore_status=False, debug=True) vm.wait_for_login().close() check_mem_config() - test.log.info("TEST_STEP4:Check vm suspend & resume and memory config") + test.log.info("TEST_STEP5:Check vm suspend & resume and memory config") virsh.suspend(vm_name, ignore_status=False, debug=True) virsh.resume(vm_name, ignore_status=False, debug=True) vm.wait_for_login().close() check_mem_config() - test.log.info("TEST_STEP5:Check vm save & restore and memory config") + test.log.info("TEST_STEP6:Check vm save & restore and memory config") if os.path.exists(save_file): os.remove(save_file) virsh.save(vm_name, save_file, ignore_status=False, debug=True) @@ -70,22 +83,22 @@ def run_positive_test(): vm.wait_for_login().close() check_mem_config() - test.log.info("TEST_STEP6:Check vm managedsave,start and memory config") + test.log.info("TEST_STEP7:Check vm managedsave,start and memory config") virsh.managedsave(vm_name, ignore_status=False, debug=True) vm.start() vm.wait_for_login().close() check_mem_config() - test.log.info("TEST_STEP7:Check libvirtd restart and memory config") + test.log.info("TEST_STEP8:Check libvirtd restart and memory config") libvirtd = utils_libvirtd.Libvirtd() libvirtd.restart() vm.wait_for_login().close() check_mem_config() - test.log.info("TEST_STEP8: Destroy vm ") + test.log.info("TEST_STEP9: Destroy vm ") virsh.destroy(vm_name, ignore_status=False, debug=True) - def teardown_positive_test(): + def teardown_test(): """ Clean data. """ @@ -95,27 +108,6 @@ def teardown_positive_test(): vm.undefine(options='--nvram --managed-save') bkxml.sync() - def run_negative_test(): - """ - Define vm and check result. - """ - test.log.info("TEST_STEP1: Define vm with maxMemory and no numa") - vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) - vmxml.setup_attrs(**vm_attrs) - test.log.debug("Define vm with %s.", vmxml) - - cmd_result = virsh.define(vmxml.xml, debug=True) - - test.log.info("TEST_STEP2: Check error message") - libvirt.check_result(cmd_result, error_msg) - - def teardown_negative_test(): - """ - Clean data. - """ - test.log.info("TEST_TEARDOWN: Clean up env.") - bkxml.sync() - def check_qemu_cmdline(): """ Check expected memory value in qemu cmd line. @@ -126,7 +118,8 @@ def check_qemu_cmdline(): expected_str = r"-m size=%sk" % mem_value else: expected_str = r"-m %s" % str(int(mem_value/1024)) - elif mem_config == "with_numa": + elif mem_config == "with_numa" or \ + mem_config == "with_maxmemory" and libvirt_version.version_compare(9, 6, 0): expected_str = r"-m size=%dk,slots=%d,maxmem=%dk" % ( int(mem_value), max_mem_slots, int(max_mem)) @@ -160,7 +153,6 @@ def check_mem_config(): vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) bkxml = vmxml.copy() - case = params.get("case") error_msg = params.get("error_msg") mem_value = int(params.get("mem_value")) current_mem = int(params.get("current_mem")) @@ -171,9 +163,6 @@ def check_mem_config(): vm_attrs = eval(params.get("vm_attrs")) save_file = "/tmp/%s.save" % vm_name - run_test = eval("run_%s" % case) - teardown_test = eval("teardown_%s" % case) - try: run_test() diff --git a/libvirt/tests/src/memory/memory_backing/discard_memory_content_setting.py b/libvirt/tests/src/memory/memory_backing/discard_memory_content_setting.py index a03aebe77b6..3c929f8037f 100644 --- a/libvirt/tests/src/memory/memory_backing/discard_memory_content_setting.py +++ b/libvirt/tests/src/memory/memory_backing/discard_memory_content_setting.py @@ -15,6 +15,8 @@ from virttest.utils_test import libvirt from virttest.utils_libvirt import libvirt_vmxml +from provider.memory import memory_base + def run(test, params, env): """ @@ -97,6 +99,8 @@ def setup_test(): Prepare memory device """ test.log.info("TEST_SETUP: Set hugepage.") + memory_base.check_mem_page_sizes( + test, int(default_page_size), int(set_pagesize)) hp_cfg.set_kernel_hugepages(set_pagesize, set_pagenum) def run_test(): @@ -140,6 +144,7 @@ def teardown_test(): qemu_line = params.get("qemu_line") numa_discard = params.get("numa_discard") mem_discard = params.get("mem_discard") + default_page_size = params.get("default_page_size") set_pagesize = params.get("set_pagesize") set_pagenum = params.get("set_pagenum") diff --git a/libvirt/tests/src/memory/memory_backing/hugepage_mount_path.py b/libvirt/tests/src/memory/memory_backing/hugepage_mount_path.py index 5d1477ca7f6..b4a5024e0d0 100644 --- a/libvirt/tests/src/memory/memory_backing/hugepage_mount_path.py +++ b/libvirt/tests/src/memory/memory_backing/hugepage_mount_path.py @@ -22,6 +22,8 @@ from virttest.utils_libvirt import libvirt_memory from virttest.staging import service +from provider.memory import memory_base + def run(test, params, env): """ @@ -33,7 +35,8 @@ def setup_test(): Set hugepage on host and prepare guest """ test.log.info("TEST_SETUP: Set hugepage on host and prepare guest") - + memory_base.check_mem_page_sizes( + test, default_page_size, int(set_pagesize_2), [int(set_pagesize_1)]) hp_cfg = test_setup.HugePageConfig(params) if case == "customized": process.run("umount %s" % default_path, ignore_status=True) @@ -117,7 +120,7 @@ def _compare_state(): test.log.info("TEST_STEP11: Check mem") session = vm.wait_for_login() - libvirt_memory.consume_vm_freememory(session, consume_value) + libvirt_memory.consume_vm_freememory(session, remain_mem) session.close() test.log.info("TEST_STEP12: Destroy the guest") @@ -160,8 +163,9 @@ def teardown_test(): err_2 = params.get("guest_log_error2") hugetlbfs_mount = params.get("hugetlbfs_mount") default_path = params.get("default_path") - consume_value = int(params.get("consume_value")) + remain_mem = int(params.get("remain_mem")) + default_page_size = int(params.get('default_page_size')) mount_pagesize = params.get("mount_pagesize", '{}') set_pagesize_1 = params.get("set_pagesize_1") set_pagenum_1 = params.get("set_pagenum_1") diff --git a/libvirt/tests/src/memory/memory_backing/hugepage_nodeset.py b/libvirt/tests/src/memory/memory_backing/hugepage_nodeset.py index 90a728885db..80697440e09 100644 --- a/libvirt/tests/src/memory/memory_backing/hugepage_nodeset.py +++ b/libvirt/tests/src/memory/memory_backing/hugepage_nodeset.py @@ -19,6 +19,8 @@ from virttest.utils_test import libvirt from virttest.utils_libvirt import libvirt_vmxml +from provider.memory import memory_base + def check_numa_maps(test, params, result): """ @@ -69,6 +71,8 @@ def setup_test(): Allocate hugepage memory """ test.log.info("TEST_SETUP: Allocate hugepage memory") + memory_base.check_mem_page_sizes( + test, pg_size=int(default_page_size), hp_size=int(set_pagesize)) hp_cfg = test_setup.HugePageConfig(params) hp_cfg.set_kernel_hugepages(set_pagesize, set_pagenum) @@ -127,11 +131,12 @@ def teardown_test(): vm_attrs = eval(params.get('vm_attrs', '{}')) allocated_mem = params.get('allocated_mem') + default_page_size = params.get("default_page_size") set_pagesize = params.get("set_pagesize") set_pagenum = params.get("set_pagenum") expect_xpath = eval(params.get("expect_xpath")) - config = params.get("config") - globals()["config_error"] = params.get("%s_error" % config, None) + numa_config = params.get("numa_config") + globals()["config_error"] = params.get("%s_error" % numa_config, None) try: setup_test() diff --git a/libvirt/tests/src/memory/memory_backing/lifecycle_for_hugepage.py b/libvirt/tests/src/memory/memory_backing/lifecycle_for_hugepage.py index 72d4f9de90a..4877f9f853b 100644 --- a/libvirt/tests/src/memory/memory_backing/lifecycle_for_hugepage.py +++ b/libvirt/tests/src/memory/memory_backing/lifecycle_for_hugepage.py @@ -8,23 +8,220 @@ # # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +import math import os -import re -from avocado.utils import process +from avocado.utils import memory +from avocado.utils import cpu from virttest import utils_libvirtd from virttest import virsh -from virttest import virt_vm from virttest import test_setup from virttest.libvirt_xml import vm_xml from virttest.utils_test import libvirt from virttest.staging import utils_memory +from virttest.utils_libvirt import libvirt_memory + +from provider.numa import numa_base + VIRSH_ARGS = {'debug': True, 'ignore_status': False} +def check_hugepage_support(params, test): + """ + Check if the specified hugepage size is supported on current environment + + :param params: dict, test parameters + :param test: test object + """ + scenario = params.get('scenario') + if scenario in ['1G', '2M', '32M', '64K', '16G']: + if scenario == '2M' and memory.get_huge_page_size()//1024 == 2: + test.cancel("2M is the default huge page size and tested in another test scenario") + vm_attrs = eval(params.get('vm_attrs', '{}')) + if vm_attrs.get('mb'): + numa_base.check_hugepage_availability(vm_attrs["mb"]["hugepages"]["pages"]) + + +def adjust_parameters(params, test): + """ + Update the test parameters according to different architecture + + :param params: dict, test parameters + :param test: test object + :ret: dict, the updated test parameters + """ + def sub_update(): + set_pagesize = default_pgsize_set_mapping[default_pagesize] + params['set_pagesize'] = set_pagesize + params['mount_size'] = set_pagesize + params['set_pagenum'] = int(math.floor(total_hugepage_mem/set_pagesize)) + + vm_attrs = eval(params.get("vm_attrs", "{}")) + scenario = params.get('scenario') + + current_arch = cpu.get_arch() + default_pagesize = memory.get_page_size()//1024 + total_hugepage_mem = int(params.get('total_hugepage_mem')) + if scenario == 'default_page_size': + vm_attrs['mb']['hugepages']['pages'][0]['size'] = default_pagesize + + if current_arch == 'aarch64': + # kernel page size vs. huge page size to be set for kernel mm file + # like if kernel page size 64K, then huge page size to be set is 2048K + default_pgsize_set_mapping = {64: 2048, 4: 1048576} + default_hugepage_size = memory.get_huge_page_size() + params['vm_nr_hugepages'] = int(math.floor(total_hugepage_mem/default_hugepage_size)) + + if scenario == 'default_page_size': + sub_update() + params['HugePages_Free'] = params['vm_nr_hugepages'] + params['free_hugepages'] = params['set_pagenum'] + elif scenario in ['default_hugepage_size', 'scarce_mem']: + sub_update() + params['free_hugepages'] = params['set_pagenum'] + elif scenario == '1G': + params['HugePages_Free'] = params['vm_nr_hugepages'] + elif scenario == '0': + sub_update() + elif scenario in ['2M', '16G', '64K', '32M']: + params['HugePages_Free'] = params['vm_nr_hugepages'] + test.log.debug("params['HugePages_Free']=%s", params.get('HugePages_Free')) + test.log.debug("params['free_hugepages']=%s", params.get('free_hugepages')) + test.log.debug("params['vm_nr_hugepages']=%s", params.get('vm_nr_hugepages')) + test.log.debug("params['set_pagesize']=%s", params.get('set_pagesize')) + test.log.debug("params['set_pagenum']=%s", params.get('set_pagenum')) + test.log.debug("params['mount_size']=%s", params.get('mount_size')) + + params['vm_attrs'] = vm_attrs + test.log.debug("Updated vm_attrs:%s", vm_attrs) + + return params + + +def setup_test(vm_name, params, test): + """ + Set hugepage on host + + :param vm_name: str, vm name + :param params: dict, test parameters + :param test: test object + """ + test.log.info("TEST_SETUP: Set hugepage on host") + vm_nr_hugepages = params.get("vm_nr_hugepages") + set_pagesize = params.get("set_pagesize") + set_pagenum = params.get("set_pagenum") + mount_size = params.get("mount_size") + + utils_memory.set_num_huge_pages(int(vm_nr_hugepages)) + hp_cfg = test_setup.HugePageConfig(params) + hp_cfg.set_kernel_hugepages(set_pagesize, set_pagenum, False) + hp_cfg.hugepage_size = mount_size + hp_cfg.mount_hugepage_fs() + utils_libvirtd.Libvirtd().restart() + + +def run_test(vm, params, test): + """ + Define guest, start guest and check mem. + + :param vm: vm instance + :param params: dict, test parameters + :param test: test object + """ + define_error = params.get("define_error") + start_error = params.get("start_error") + save_file = params.get("save_file", "/tmp/guest.save") + HugePages_Free = params.get("HugePages_Free") + free_hugepages = params.get("free_hugepages") + vm_nr_hugepages = params.get("vm_nr_hugepages") + set_pagesize = params.get("set_pagesize") + set_pagenum = params.get("set_pagenum") + vm_attrs = params.get("vm_attrs") + + test.log.info("TEST_STEP1: Define guest") + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm.name) + if vm_attrs: + vmxml.setup_attrs(**vm_attrs) + cmd_result = virsh.define(vmxml.xml, debug=True) + if define_error: + # check scenario: 0 + libvirt.check_result(cmd_result, define_error) + return + + test.log.info("TEST_STEP2: Start guest") + ret = virsh.start(vm.name, debug=True, ignore_error=True) + libvirt.check_result(ret, expected_fails=start_error) + if start_error: + return + vm.wait_for_login().close() + vmxml = vm_xml.VMXML.new_from_dumpxml(vm.name) + test.log.debug("After start vm, get vmxml is :%s", vmxml) + + test.log.info("TEST_STEP3: Check the huge page memory usage") + hp_cfg = test_setup.HugePageConfig(params) + if int(utils_memory.get_num_huge_pages()) != int(vm_nr_hugepages): + test.fail("HugePages_Total should be %s instead of %s" % ( + vm_nr_hugepages, utils_memory.get_num_huge_pages())) + + actural_nr = hp_cfg.get_kernel_hugepages(set_pagesize) + if int(actural_nr) != int(set_pagenum): + test.fail("nr_hugepages should be %s instead of %s" % ( + set_pagenum, actural_nr)) + + if int(utils_memory.get_num_huge_pages_free()) != int(HugePages_Free): + test.fail("HugePages_Free should be %s instead of %s" % ( + HugePages_Free, utils_memory.get_num_huge_pages_free())) + + actural_freepg = hp_cfg.get_kernel_hugepages(set_pagesize, 'free') + if int(actural_freepg) != int(free_hugepages): + test.fail("free_hugepages should be %s instead of %s" % ( + free_hugepages, actural_freepg)) + + test.log.info("TEST_STEP4: Check the vm lifecycle with hugepage setting") + virsh.suspend(vm.name, **VIRSH_ARGS) + virsh.resume(vm.name, **VIRSH_ARGS) + vm.wait_for_login().close() + + if os.path.exists(save_file): + os.remove(save_file) + virsh.save(vm.name, save_file, **VIRSH_ARGS) + virsh.restore(save_file, **VIRSH_ARGS) + vm.wait_for_login().close() + + virsh.managedsave(vm.name, **VIRSH_ARGS) + vm.start() + vm.wait_for_login().close() + + virsh.reboot(vm.name, **VIRSH_ARGS) + session = vm.wait_for_login() + + test.log.info("TEST_STEP5: Verify guest memory could be consumed") + libvirt_memory.consume_vm_freememory(session, 204800) + + virsh.destroy(vm.name, **VIRSH_ARGS) + + +def teardown_test(vmxml, params, test): + """ + Clean data. + + :param vmxml: VMXML instance + :param params: dict, test parameters + :param test: test object + """ + save_file = params.get("save_file", "/tmp/guest.save") + + test.log.info("TEST_TEARDOWN: Clean up env.") + vmxml.sync() + if os.path.exists(save_file): + os.remove(save_file) + hp_cfg = test_setup.HugePageConfig(params) + hp_cfg.cleanup() + + def run(test, params, env): """ 1.Verify different size huge page take effect for guest vm @@ -33,124 +230,16 @@ def run(test, params, env): Scenario: Huge page memory status: 4k, 2M, 1G, 0, scarce. """ - def setup_test(): - """ - Set hugepage on host - """ - test.log.info("TEST_SETUP: Set hugepage on host") - utils_memory.set_num_huge_pages(int(vm_nr_hugepages)) - - hp_cfg = test_setup.HugePageConfig(params) - hp_cfg.set_kernel_hugepages(set_pagesize, set_pagenum) - hp_cfg.hugepage_size = mount_size - hp_cfg.mount_hugepage_fs() - utils_libvirtd.libvirtd_restart() - virsh.destroy(vm_name) - - def run_test(): - """ - Define guest, start guest and check mem. - """ - test.log.info("TEST_STEP1: Define guest") - vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) - vmxml.setup_attrs(**vm_attrs) - cmd_result = virsh.define(vmxml.xml, debug=True) - if define_error: - # check scenario: 0 - libvirt.check_result(cmd_result, define_error) - return - - test.log.info("TEST_STEP2: Start guest") - try: - vm.start() - vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) - test.log.debug("After start vm, get vmxml is :%s", vmxml) - except virt_vm.VMStartError as details: - # check scenario: scarce_mem - if not re.search(start_error, str(details)): - test.fail("Failed to start guest: {}".format(str(details))) - else: - return - - test.log.info("TEST_STEP3: Check the huge page memory usage") - hp_cfg = test_setup.HugePageConfig(params) - if int(utils_memory.get_num_huge_pages()) != int(vm_nr_hugepages): - test.fail("HugePages_Total should be %s instead of %s" % ( - vm_nr_hugepages, utils_memory.get_num_huge_pages())) - - actural_nr = hp_cfg.get_kernel_hugepages(set_pagesize) - if int(actural_nr) != int(set_pagenum): - test.fail("nr_hugepages should be %s instead of %s" % ( - set_pagenum, actural_nr)) - - if int(utils_memory.get_num_huge_pages_free()) != int(HugePages_Free): - test.fail("HugePages_Free should be %s instead of %s" % ( - HugePages_Free, utils_memory.get_num_huge_pages_free())) - - free_page_num = process.run(free_hugepages_cmd, shell=True, - verbose=True).stdout_text.strip() - if int(free_page_num) != int(free_hugepages): - test.fail("free_hugepages should be %s instead of %s" % ( - free_hugepages, free_page_num)) - - test.log.info("TEST_STEP4: Check the huge page memory usage") - virsh.suspend(vm.name, **VIRSH_ARGS) - virsh.resume(vm.name, **VIRSH_ARGS) - vm.wait_for_login().close() - - if os.path.exists(save_file): - os.remove(save_file) - virsh.save(vm.name, save_file, **VIRSH_ARGS) - virsh.restore(save_file, **VIRSH_ARGS) - vm.wait_for_login().close() - - virsh.managedsave(vm.name, **VIRSH_ARGS) - vm.start() - vm.wait_for_login().close() - - virsh.reboot(vm.name, **VIRSH_ARGS) - session = vm.wait_for_login() - - test.log.info("TEST_STEP5: Verify guest memory could be consumed") - mem_free = utils_memory.freememtotal(session) - status, stdout = session.cmd_status_output("swapoff -a; memhog %s" % ( - mem_free - 204800)) - if status: - raise test.fail("Failed to consume memory:%s" % stdout) - - virsh.destroy(vm.name, **VIRSH_ARGS) - - def teardown_test(): - """ - Clean data. - """ - test.log.info("TEST_TEARDOWN: Clean up env.") - bkxml.sync() - if os.path.exists(save_file): - os.remove(save_file) - hp_cfg = test_setup.HugePageConfig(params) - hp_cfg.cleanup() - + check_hugepage_support(params, test) vm_name = params.get("main_vm") + params = adjust_parameters(params, test) vm = env.get_vm(vm_name) vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) bkxml = vmxml.copy() - define_error = params.get("define_error") - vm_nr_hugepages = params.get("vm_nr_hugepages") - free_hugepages_cmd = params.get("free_hugepages_cmd") - set_pagesize = params.get("set_pagesize") - set_pagenum = params.get("set_pagenum") - HugePages_Free = params.get("HugePages_Free") - mount_size = params.get("mount_size") - free_hugepages = params.get("free_hugepages") - start_error = params.get("start_error") - vm_attrs = eval(params.get("vm_attrs", "{}")) - save_file = params.get("save_file", "/tmp/guest.save") - try: - setup_test() - run_test() + setup_test(vm_name, params, test) + run_test(vm, params, test) finally: - teardown_test() + teardown_test(bkxml, params, test) diff --git a/libvirt/tests/src/memory/memory_backing/memory_access_mode.py b/libvirt/tests/src/memory/memory_backing/memory_access_mode.py index 34af5b28c6e..5bbfbeb1f3a 100644 --- a/libvirt/tests/src/memory/memory_backing/memory_access_mode.py +++ b/libvirt/tests/src/memory/memory_backing/memory_access_mode.py @@ -17,6 +17,8 @@ from virttest.utils_libvirt import libvirt_vmxml from virttest.utils_libvirt import libvirt_memory +from provider.memory import memory_base + def get_vm_attrs(test, params): """ @@ -152,6 +154,8 @@ def setup_test(): """ Setup pagesize """ + memory_base.check_mem_page_sizes( + test, pg_size=int(default_page_size), hp_size=int(set_pagesize)) hp_cfg.set_kernel_hugepages(set_pagesize, set_pagenum) def run_test(): @@ -220,6 +224,7 @@ def teardown_test(): mem_backend = params.get("mem_backend") qemu_monitor_cmd = params.get('qemu_monitor_cmd') qemu_monitor_option = params.get('qemu_monitor_option') + default_page_size = params.get("default_page_size") set_pagesize = params.get("set_pagesize") set_pagenum = params.get("set_pagenum") diff --git a/libvirt/tests/src/memory/memory_backing/memory_source_and_allocation.py b/libvirt/tests/src/memory/memory_backing/memory_source_and_allocation.py index 906d5124569..e557485cafb 100644 --- a/libvirt/tests/src/memory/memory_backing/memory_source_and_allocation.py +++ b/libvirt/tests/src/memory/memory_backing/memory_source_and_allocation.py @@ -7,8 +7,8 @@ # Author: Nannan Li # # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -import re import json +import re from avocado.utils import process @@ -21,6 +21,8 @@ from virttest.utils_libvirt import libvirt_vmxml from virttest.utils_libvirt import libvirt_memory +from provider.memory import memory_base + def run(test, params, env): """ @@ -139,12 +141,12 @@ def check_hugepage(params, mem_name): hugepage = str(json.loads(result)['return']) result = virsh.qemu_monitor_command( - vm_name, check_thread % (mem_name, 'hugetlbsize'), debug=True).stdout_text + vm_name, check_thread % (mem_name, 'size'), debug=True).stdout_text hugepage_size = str(json.loads(result)['return']) if hugepage != 'True': test.fail("Expect to get hugepage 'True', but got '%s'" % hugepage) - if hugepage_size != memory_value: + if int(hugepage_size) != int(memory_value) * 1024: test.fail("Expect to get hugepage size '%s', but got '%s'" % ( hugepage_size, memory_value)) test.log.debug("Get correct hugepage '%s' and hugepage_size '%s'", @@ -154,6 +156,8 @@ def setup_test(): """ Setup pagesize """ + memory_base.check_mem_page_sizes( + test, pg_size=int(default_page_size), hp_size=int(set_pagesize)) hp_cfg.set_kernel_hugepages(set_pagesize, set_pagenum) def run_test(): @@ -242,6 +246,7 @@ def teardown_test(): memory_name_pattern = params.get("memory_name_pattern") check_allocated_cmd = params.get("check_allocated_cmd") numa_attrs = eval(params.get("numa_attrs", '{}')) + default_page_size = params.get("default_page_size") set_pagesize = params.get("set_pagesize") set_pagenum = params.get("set_pagenum") source_attr = params.get("source_attr", "") diff --git a/libvirt/tests/src/memory/memory_backing/page_locking_and_shared_pages.py b/libvirt/tests/src/memory/memory_backing/page_locking_and_shared_pages.py index 7490cdd0505..1f0877a49df 100644 --- a/libvirt/tests/src/memory/memory_backing/page_locking_and_shared_pages.py +++ b/libvirt/tests/src/memory/memory_backing/page_locking_and_shared_pages.py @@ -17,6 +17,8 @@ from virttest.utils_libvirt import libvirt_memory from virttest.staging import utils_memory +from provider.memory import memory_base + def run(test, params, env): """ @@ -47,6 +49,9 @@ def setup_test(): Prepare init xml """ test.log.info("TEST_SETUP: Set hugepage") + + memory_base.check_mem_page_sizes( + test, kernel_pagesize, int(pagesize)) hp_cfg = test_setup.HugePageConfig(params) hp_cfg.set_kernel_hugepages(pagesize, pagenum) @@ -97,9 +102,9 @@ def run_test(): return else: if page_config == "page_default": - if (nr_unevictable_2 - nr_unevictable)*4 < mem_value: + if (nr_unevictable_2 - nr_unevictable)*kernel_pagesize < mem_value: test.fail("Unevictable memory pages should less than %d" % mem_value) - if (lock_pages_2 - lock_pages)*4 < mem_value: + if (lock_pages_2 - lock_pages)*kernel_pagesize < mem_value: test.fail("Locked memory pages should less than %d" % mem_value) elif page_config == "hugepage": if (nr_unevictable_2 - nr_unevictable) < 0: @@ -139,6 +144,7 @@ def teardown_test(): qemu_line = eval(params.get("qemu_line")) hard_limit = int(params.get("hard_limit", 0)) mem_value = int(params.get("mem_value", '')) + kernel_pagesize = int(params.get("kernel_pagesize", 0)) lock_dict = params.get("lock_dict", "") tune_dict = eval(params.get("tune_dict", "{}")) diff --git a/libvirt/tests/src/memory/memory_balloon/memory_balloon_freepagereporting.py b/libvirt/tests/src/memory/memory_balloon/memory_balloon_freepagereporting.py new file mode 100644 index 00000000000..ebb691138e4 --- /dev/null +++ b/libvirt/tests/src/memory/memory_balloon/memory_balloon_freepagereporting.py @@ -0,0 +1,142 @@ +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Copyright Red Hat +# +# SPDX-License-Identifier: GPL-2.0 +# +# Author: Liang Cong +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +import re +import time + +from virttest import utils_misc +from virttest import virsh +from virttest.libvirt_xml import vm_xml +from virttest.libvirt_xml.devices import memballoon +from virttest.staging import utils_memory +from virttest.utils_test import libvirt + + +def run(test, params, env): + """ + Verify the freepagereporting takes effect with various memory balloon models + """ + def get_rss_mem_list(timeout=30): + """" + Get rss memory list from virsh dommemstat cmd per second + + :param timeout: timeout of getting rss memory list from virsh dommemstat cmd + :return: rss memory list + """ + current = 0 + rss_mem_list = [] + while current < timeout: + time.sleep(1) + rss_mem_list.append(get_rss_mem()) + current += 1 + return rss_mem_list + + def get_rss_mem(): + """" + Get rss memory from virsh dommemstat cmd + """ + output = virsh.dommemstat(vm_name, **virsh_dargs).stdout_text + match = re.search(r"rss\s+(\d+)", output) + return int(match.group(1)) + + def run_test(): + """ + Test steps + 1. Define guest + 2. Start the domain + 3. Check the memory usage of the guest on host + 4. Login the guest and consume the guest memory + 5. Verify the memory usage is increased after consuming more memory on host + 6. Check the memory after memory consumption + """ + test.log.info("TEST_STEP1: Define guest") + vmxml.del_device('memballoon', by_tag=True) + mem_balloon = memballoon.Memballoon() + mem_balloon.setup_attrs(**memballoon_dict) + vmxml.devices = vmxml.devices.append(mem_balloon) + vmxml.setup_attrs(**mem_attrs) + vmxml.sync() + + test.log.info("TEST_STEP2: Start the domain") + vm.start() + + test.log.info("TEST_STEP3: Check the memory usage of the guest on host") + session = vm.wait_for_login() + init_rss = get_rss_mem() + + test.log.info( + "TEST_STEP4: Login the guest and consume the guest memory") + rss_mem_thread = utils_misc.InterruptedThread(get_rss_mem_list) + rss_mem_thread.start() + free_mem = utils_memory.freememtotal(session) + session.cmd_status("swapoff -a") + session.cmd_status(mem_consume_cmd % (free_mem - unconsumed_mem)) + session.close() + rss_mem_list = rss_mem_thread.join() + test.log.debug( + "The rss memory list is %s during guest consumption." % rss_mem_list) + + test.log.info( + "TEST_STEP5: Verify the memory usage is increased after consuming more memory on host") + second_rss_mem = max(rss_mem_list) + if second_rss_mem < init_rss: + test.fail("Expected rss memory after consuming %s is larger than %s" % ( + second_rss_mem, init_rss)) + + test.log.info("TEST_STEP6: Check the memory after memory consumption") + third_rss_mem = rss_mem_list[-1] + rss_mem_changed = second_rss_mem - third_rss_mem + if max_memory_difference and abs(rss_mem_changed) > max_memory_difference: + test.fail("Expected rss memory changed lower than %s, but got %s" % ( + max_memory_difference, abs(rss_mem_changed))) + if min_memory_difference and rss_mem_changed < min_memory_difference: + test.fail("Expected rss memory changed larger than %s, but got %s" % ( + min_memory_difference, rss_mem_changed)) + + test.log.info( + "TEST_STEP7: Change the current memory allocation of the guest.") + result = virsh.setmem(domain=vm_name, size=set_memory, **virsh_dargs) + libvirt.check_exit_status(result) + + test.log.info( + "TEST_STEP8: Check the memory allocation config by virsh dominfo.") + if not utils_misc.wait_for(lambda: vm.get_used_mem() == int(set_memory), timeout=10): + test.fail("Expect used memory of dominfo is %s, but got %s" % ( + set_memory, vm.get_used_mem())) + max_mem = vm.get_max_mem() + if max_mem != int(mem_value): + test.fail("Expected max memory of dominfo is %s, but got %s" % + (mem_value, max_mem)) + + def teardown_test(): + """ + Clean test environment. + """ + test.log.info("TEST_TEARDOWN: Clean up environment.") + bkxml.sync() + + vm_name = params.get("main_vm") + vm = env.get_vm(vm_name) + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + bkxml = vmxml.copy() + memballoon_dict = eval(params.get('memballoon_dict', '{}')) + mem_attrs = eval(params.get('mem_attrs', '{}')) + virsh_dargs = {"debug": True, "ignore_status": True} + max_memory_difference = int(params.get('max_memory_difference', '0')) + min_memory_difference = int(params.get('min_memory_difference', '0')) + set_memory = params.get('set_memroy') + mem_value = params.get('mem_value') + mem_consume_cmd = params.get('mem_consume_cmd') + unconsumed_mem = int(params.get('unconsumed_mem')) + + try: + run_test() + + finally: + teardown_test() diff --git a/libvirt/tests/src/memory/memory_balloon/period_config_of_memory_balloon.py b/libvirt/tests/src/memory/memory_balloon/period_config_of_memory_balloon.py new file mode 100644 index 00000000000..a5dc82ad8ef --- /dev/null +++ b/libvirt/tests/src/memory/memory_balloon/period_config_of_memory_balloon.py @@ -0,0 +1,159 @@ +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Copyright Redhat +# +# SPDX-License-Identifier: GPL-2.0 + +# Author: Nannan Li +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +import re + +from virttest import virsh + +from virttest.libvirt_xml import vm_xml +from virttest.utils_libvirt import libvirt_vmxml + + +def run(test, params, env): + """ + Verify memory statistics config "period" takes effect with various memory balloon models + + Scenario: + 1.memory balloon models: virtio, virtio-transitional, virtio-non-transitional. + 2.period: int period, undefined. + 3.mem config: mem, current mem. + """ + + def check_same_value(value1, value2, log_msg): + """ + This function checks whether two values are same or not. + + :param value1: First value to be checked. + :param value2: Second value to be checked. + :param log_msg: Log message to display in case of failure. + :raises: Test.Fail if values are not same. + """ + if value1 != value2: + test.fail("The %s should not change from '%s' to '%s'" + % (log_msg, value1, value2)) + + def get_memory_statistics(): + """ + Get memory statistics by virsh dommemstat + + :return: usable mem, last_update, disk_caches value in result. + """ + res = virsh.dommemstat(vm_name, ignore_status=False, + debug=True).stdout_text + if re.findall(r'usable (\d+)', res): + usable_mem = re.findall(r'usable (\d+)', res)[0] + last_update = re.findall(r'last_update (\d+)', res)[0] + disk_caches = re.findall(r'disk_caches (\d+)', res)[0] + return usable_mem, last_update, disk_caches + else: + test.fail("Fail to get virsh dommemstat result") + + def check_vm_dommemstat(period_config, usable_mem, last_update, + disk_caches): + """ + Check correct vm dommemstat result. + + :params: period_config: period config, undefined , 0 or number + :params: usable_mem, the usable mem value before consume mem + :params: last_update, the last update value before consume mem + :params: disk_caches, the disk caches value before consume mem + """ + usable_mem_new, last_update_new, disk_caches_new = get_memory_statistics() + + if period_config in ["undefined", "0"]: + check_same_value(usable_mem_new, usable_mem, "usable value") + check_same_value(last_update_new, last_update, "last update") + check_same_value(disk_caches_new, disk_caches, "disk caches") + + elif period_config.isdigit() and period_config != "0": + if usable_mem_new == usable_mem: + test.fail("The usable mem should be as '%s' instead of '%s'" + % (usable_mem_new, usable_mem)) + if last_update_new <= last_update: + test.fail("The last update '%s' should bigger than to '%s'" + % (last_update_new, last_update)) + if disk_caches_new == disk_caches: + test.fail("The disk caches mem '%s' should not same as '%s' " % + (disk_caches_new, disk_caches)) + + def check_xml_and_dommemstat(period_set): + """ + Check memory balloon xml and dommemstat after consume. + + :params: period_set, the period value. + """ + vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) + test.log.debug("Get current guest xml is :%s\n" % vmxml) + + xpath_existed = True + if period_set in ["undefined", "0"]: + xpath_existed = False + if not libvirt_vmxml.check_guest_xml_by_xpaths( + vmxml, expect_xpath, ignore_status=True) == xpath_existed: + test.fail("Expect to get '%s' in xml " % expect_xpath) + + guest_session = vm.wait_for_login() + usable_mem, last_update, disk_caches = get_memory_statistics() + + status, stdout = guest_session.cmd_status_output(mem_operation) + guest_session.close() + if status != 0 and status != 124: + test.fail("Failed to consume memory: %s" % stdout) + + check_vm_dommemstat(period_set, usable_mem, last_update, disk_caches) + + def run_test(): + """ + Define and start guest + Check memTotal and memory allocation + """ + test.log.info("TEST_STEP1: Define guest with memballon") + vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) + vmxml.setup_attrs(**mem_attrs) + vmxml.del_device('memballoon', by_tag=True) + libvirt_vmxml.modify_vm_device(vmxml, 'memballoon', device_dict) + + test.log.info("TEST_STEP2: Start guest ") + vm.start() + + test.log.info("TEST_STEP3,4,5: Check memory balloon xml and dommemstat " + "after consume") + check_xml_and_dommemstat(period_value_1) + + test.log.info("TEST_STEP6: Change the period setting") + virsh.dommemstat(vm_name, period_cmd, ignore_status=False, debug=True) + + test.log.info("TEST_STEP7: Repeat TEST_STEP3-5") + check_xml_and_dommemstat(period_value_2) + + def teardown_test(): + """ + Clean data. + """ + test.log.info("TEST_TEARDOWN: Clean up env.") + bkxml.sync() + + vm_name = params.get("main_vm") + vm = env.get_vm(vm_name) + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + bkxml = vmxml.copy() + + mem_attrs = eval(params.get("mem_attrs", "{}")) + device_dict = eval(params.get("device_dict", "{}")) + mem_operation = params.get("mem_operation") + period_value_1 = params.get("period_value_1") + period_value_2 = params.get("period_value_2") + period_cmd = params.get("period_cmd") + expect_xpath = eval(params.get("xpath")) + + try: + run_test() + + finally: + teardown_test() diff --git a/libvirt/tests/src/memory/memory_devices/change_virtio_mem_request_size.py b/libvirt/tests/src/memory/memory_devices/change_virtio_mem_request_size.py new file mode 100644 index 00000000000..feeeda85c77 --- /dev/null +++ b/libvirt/tests/src/memory/memory_devices/change_virtio_mem_request_size.py @@ -0,0 +1,398 @@ +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Copyright Redhat +# +# SPDX-License-Identifier: GPL-2.0 + +# Author: Nannan Li +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +import re + +from avocado.utils import memory + +from virttest import utils_misc +from virttest import utils_test +from virttest import virsh + +from virttest.libvirt_xml import vm_xml +from virttest.utils_test import libvirt +from virttest.utils_libvirt import libvirt_vmxml +from virttest.staging import utils_memory + +from provider.memory import memory_base + +VIRSH_ARGS = {'debug': True, 'ignore_status': False} + + +def get_vm_attrs(test, params): + """ + Get vm attrs. + + :param test: test object + :param params: dictionary with the test parameters + :return vm_attrs: get updated vm attrs dict. + """ + vm_attrs = eval(params.get("vm_attrs", "{}")) + source_attr = params.get("source_attr", "") + hugepages_attr = params.get("hugepages_attr", "") + mb_value = "" + + for item in [source_attr, hugepages_attr]: + if item != "": + mb_value += item + "," + mb_attrs = eval("{'mb':{%s}}" % mb_value[:-1]) + + vm_attrs.update(mb_attrs) + test.log.debug("Get current vm attrs is :%s", vm_attrs) + + return vm_attrs + + +def define_guest_with_basic_virtio_mem(test, params, vm_name, mem_basic_dict): + """ + Define guest with virtio memory device. + + :param test: test object. + :param params: dictionary with the test parameters. + :param vm_name: vm name. + :param mem_basic_dict: the virtio memory device dict. + """ + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + vm_attrs = get_vm_attrs(test, params) + vmxml.setup_attrs(**vm_attrs) + + libvirt_vmxml.modify_vm_device( + vmxml, "memory", + dev_dict=eval(mem_basic_dict % (params.get('target_size'), + params.get('request_size'), + params.get('default_pagesize')))) + test.log.debug("Define vm with %s.", vm_xml.VMXML.new_from_inactive_dumpxml( + vm_name)) + + +def get_various_size(test, vm_name, check_item='requested_size', index=0): + """ + Get various memory size. + + :param test: test object. + :param vm_name: vm name. + :param check_item: The item you want to check, eg: requested_size. + :param index: memory index of memory list in devices. + :return actual_size, the actual size in xml. + """ + vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) + mem_list = vmxml.devices.by_device_tag('memory') + actual_attrs = mem_list[index].fetch_attrs() + test.log.debug("Get memory attrs list is: '%s'", actual_attrs) + actual_size = actual_attrs['target'][check_item] + + return actual_size + + +def check_various_size(test, vm_name, expected_size, + check_item='requested_size', index=0): + """ + Check Various size in vmxml memory device + + :param test: test object. + :param vm_name: vm name. + :param expected_size: expected size value. + :param check_item: The item you want to check, eg: requested_size. + :param index: memory index of memory list in devices. + """ + actual_size = get_various_size(test, vm_name, check_item=check_item, + index=index) + + if int(actual_size) != int(expected_size): + test.fail("Expect to get '%s':'%s', but got:'%s' in '%sth' " + "memory" % (check_item, str(expected_size), actual_size, index+1)) + else: + test.log.debug("Check '%s' is '%s' successfully", check_item, expected_size) + + +def update_virtio_mem_request_size(test, params, vm_name, device_opt, target_requested): + """ + Update specified virtio memory request value. + + :param test: test object. + :param params: dictionary with the test parameters. + :param vm_name: vm name. + :param device_opt: the device option to update. + :param target_requested: the request value to update. + """ + error_msg = params.get("error_msg") + expected_event = params.get("expected_event") + virsh_opts = params.get("virsh_opts") + guest_state = params.get("guest_state") + + event_session = virsh.EventTracker.start_get_event(vm_name) + res = virsh.update_memory_device( + vm_name, options=virsh_opts % (device_opt, target_requested), debug=True) + libvirt.check_result(res, error_msg) + + event_output = virsh.EventTracker.finish_get_event(event_session) + pattern = r"%s\S+ \S+ \S+ '\S+\s+\S+ virtiomem%s" % ( + expected_event, re.findall(r"\d+", device_opt)[0]) + + def _check_event_output(patt, output, expect_exist=True): + is_existed = bool(re.findall(patt, output)) + if is_existed != expect_exist: + test.fail('Expect %s to get: %s from the event output:%s' % ( + '' if expect_exist else 'not', patt, output)) + else: + test.log.debug("Check event %s success in the event output", patt) + + if guest_state != "shutoff_guest": + _check_event_output(pattern, event_output, expect_exist=error_msg is None) + + +def check_mem_total(test, params, session, old_mem_total): + """ + Compare mem total value in different scenarios. + + :param test: test object. + :param params: dictionary with the test parameters. + :param session: vm session. + :param old_mem_total: The old mem total value to compare. + :return: new_mem_total, current mem total value. + """ + + update_req = int(memory_base.convert_data_size( + params.get("update_request_size"), 'KiB')) + basic_req = int(memory_base.convert_data_size( + params.get("basic_request"), 'KiB')) + new_mem_total = int(utils_memory.memtotal(session)) + if params.get('normal_or_zero_request'): + if new_mem_total - old_mem_total != update_req - basic_req: + test.fail("Expect two memTotal values(%s and %s) difference is " + "(%s - %s)" % (new_mem_total, old_mem_total, + update_req, basic_req)) + + elif params.get('bigger_or_not_muti_request'): + if new_mem_total != old_mem_total: + test.fail("Expect mem total to be '%s', but found '%s'" % ( + old_mem_total, new_mem_total)) + test.log.debug("Check memtotal success") + + return new_mem_total + + +def check_guest_xml(test, vm_name, params): + """ + Check correct memory size in guest xml. + + :param test: test object. + :param vm_name: vm name + :param params: dictionary with the test parameters. + """ + expect_xpath = params.get("expect_xpath") + target_size = int(params.get("target_size")) + mem_value = int(params.get("mem_value")) + current_mem = int(params.get("current_mem")) + with_numa = params.get("with_numa", "yes") == "yes" + basic_request = int(re.findall(r'\d+', params.get("basic_request"))[0]) + update_request_size = int(memory_base.convert_data_size( + params.get("update_request_size"), 'KiB')) + + test.log.debug("Start checking memory size and current memory size") + virtio_mem_value = current_0 = current_1 = 0 + if params.get('normal_or_zero_request'): + virtio_mem_value = current_0 = current_1 = update_request_size + elif params.get('bigger_or_not_muti_request'): + virtio_mem_value = current_0 = current_1 = basic_request + + expect_memory = mem_value + target_size * 2 \ + if with_numa else mem_value + target_size + expect_current = current_mem + current_0 + current_1 \ + if with_numa else current_mem - target_size + current_0 + current_1 + xpath = expect_xpath % (expect_memory, + expect_current) + test.log.debug("Checking xml pathern is :%s", xpath) + + vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) + test.log.debug("Current mem xml is :%s\n", vmxml) + libvirt_vmxml.check_guest_xml_by_xpaths(vmxml, eval(xpath)) + + test.log.debug("Start checking all memory device size") + check_list = [(params.get('default_pagesize'), 'block_size', 0), + (params.get('default_pagesize'), 'block_size', 1), + (virtio_mem_value, 'requested_size', 0), + (virtio_mem_value, 'requested_size', 1), + (virtio_mem_value, 'current_size', 0), + (virtio_mem_value, 'current_size', 1)] + for items in check_list: + check_various_size(test, vm_name, items[0], check_item=items[1], + index=items[2]) + + +def update_and_check_memory_size(test, params, session, update_device, + update_size, old_mem_total): + """ + Update request size and check memory size. + + :param test: test object. + :param params: dictionary with the test parameters. + :param session: vm session + :param update_device: the device to update + :param update_size: the size to update + :param old_mem_total: the old mem total value to compare with new mem total. + :return new_mem_total: return the current mem total + """ + vm_name = params.get("main_vm") + update_virtio_mem_request_size(test, params, vm_name, update_device, + update_size) + new_mem_total = check_mem_total(test, params, session, old_mem_total) + return new_mem_total + + +def check_delayed_current(test, params, mem_index, expected_current_size): + """ + Check the virtio memory current value. + :param test: test object. + :param params: dictionary with the test parameters. + :param expected_current_size, expected current size value. + :param mem_index, Check after or before attaching memory device. + """ + vm_name = params.get("main_vm") + + def _get_virtio_current(): + return vm_xml.VMXML.new_from_dumpxml( + vm_name).devices.by_device_tag("memory")[ + mem_index].target.current_size + + if not utils_misc.wait_for( + lambda: expected_current_size == _get_virtio_current(), 20): + test.fail( + "Attached virtio memory current size should be %s" % expected_current_size) + test.log.debug("Checked attached virtio memory current size successfully") + + +def run(test, params, env): + """ + Verify virtio-mem memory device requested memory size could be changed + """ + def setup_test(): + """ + Allocate huge page memory and update kernel parameter. + """ + test.log.info("TEST_SETUP: Set hugepage and add kernel parameter") + default_pagesize = memory.get_huge_page_size() + params.update({'default_pagesize': default_pagesize}) + utils_memory.set_num_huge_pages(int(allocate_huge_pages)/default_pagesize) + if kernel_params_add: + test.log.info("TEST_SETUP: Add kernel parmater") + utils_test.update_boot_option( + vm, args_added=kernel_params_add, guest_arch_name=vm_arch_name) + + def run_test_shutoff_guest(): + """ + 1.Define vm. + 2.Change virtio-mem requested size and check virtio-mem config + """ + test.log.info("TEST_STEP1: Define vm with numa and virtio-mem device") + if vm.is_alive(): + virsh.destroy(vm_name, **VIRSH_ARGS) + define_guest_with_basic_virtio_mem(test, params, vm_name, mem_basic) + + test.log.info("TEST_STEP2: Change the requested size of the virtio-mem") + update_virtio_mem_request_size(test, params, vm_name, + basic_device, update_request_size) + if params.get('bigger_or_not_muti_request'): + return + + test.log.info("TEST_STEP3: Check the virtio-mem memory device config") + converted_req = int(memory_base.convert_data_size(update_request_size, requested_unit)) + check_list = [(target_size, 'size'), (converted_req, 'requested_size'), + (basic_node, 'node'), (params.get('default_pagesize'), 'block_size')] + for items in check_list: + check_various_size(test, vm_name, items[0], check_item=items[1]) + + def run_test_running_guest(): + """ + 1.Define vm. + 2.Change virtio-mem requested size and check virtio-mem config + 3.Hotplug a virtio-mem device and check virtio-mem config + """ + test.log.info("TEST_STEP1: Define vm with numa and virtio-mem device") + define_guest_with_basic_virtio_mem(test, params, vm_name, mem_basic) + + test.log.info("TEST_STEP2: Start guest") + virsh.start(vm_name, **VIRSH_ARGS) + session = vm.wait_for_login() + + test.log.info("TEST_STEP3: Attach a new virtio-memory device") + mem_obj = libvirt_vmxml.create_vm_device_by_type( + "memory", eval(mem_attach % (params.get('target_size'), + params.get('request_size'), + params.get('default_pagesize')))) + virsh.attach_device(vm.name, mem_obj.xml, wait_for_event=True, **VIRSH_ARGS) + check_delayed_current(test, params, 1, int(params.get('request_size'))) + + test.log.info("TEST_STEP4: Get the first time total memory in guest") + mem_total_1 = int(utils_memory.memtotal(session)) + + test.log.info("TEST_STEP5,6: Change the first virtio-mem requested size" + "with alias name and check total memory") + mem_total_2 = update_and_check_memory_size( + test, params, session, basic_device_alias, update_request_size, + mem_total_1) + + test.log.info("TEST_STEP7,8: Change the second virtio-mem requested " + "size with node id and check total memory") + update_and_check_memory_size(test, params, session, attached_device, + update_request_size, mem_total_2) + session.close() + + test.log.info("TEST_STEP9: Check the memory allocation and virtio-mem " + "device active config by virsh dumpxml") + check_guest_xml(test, vm.name, params) + + def teardown_test(): + """ + Clean data. + """ + test.log.info("TEST_TEARDOWN: Clean up env.") + utils_memory.set_num_huge_pages(0) + bkxml.sync() + if kernel_params_remove: + if not vm.is_alive(): + vm.start() + utils_test.update_boot_option( + vm, args_removed=kernel_params_remove, guest_arch_name=vm_arch_name) + + vm_name = params.get("main_vm") + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + bkxml = vmxml.copy() + vm = env.get_vm(vm_name) + + allocate_huge_pages = re.findall(r'\d+', params.get("allocate_huge_pages"))[0] + vm_arch_name = params.get("vm_arch_name") + guest_state = params.get("guest_state") + basic_node = params.get("basic_node") + target_size = int(params.get("target_size")) + mem_basic = params.get("mem_basic", "{}") + mem_attach = params.get("mem_attach", "{}") + attached_device = params.get("attached_device") + basic_device = params.get("basic_device") + basic_device_alias = params.get("basic_device_alias") + update_request_size = params.get("update_request_size") + requested_unit = params.get("requested_unit") + requested_setting = params.get("requested_setting") + kernel_params_add = params.get("kernel_params_add") + kernel_params_remove = params.get("kernel_params_remove") + params.update( + {'normal_or_zero_request': requested_setting in [ + "normal_requested", "zero_requested"]}) + params.update( + {'bigger_or_not_muti_request': requested_setting in [ + "bigger_requested", "not_mutiple_of_block_requested"]}) + + run_test = eval('run_test_%s' % guest_state) + memory_base.check_supported_version(params, test, vm) + try: + setup_test() + run_test() + + finally: + teardown_test() diff --git a/libvirt/tests/src/memory/memory_devices/dimm_memory_hot_unplug.py b/libvirt/tests/src/memory/memory_devices/dimm_memory_hot_unplug.py new file mode 100644 index 00000000000..05420240d0c --- /dev/null +++ b/libvirt/tests/src/memory/memory_devices/dimm_memory_hot_unplug.py @@ -0,0 +1,212 @@ +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Copyright Redhat +# +# SPDX-License-Identifier: GPL-2.0 + +# Author: Nannan Li +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +import os + +from avocado.utils import process +from avocado.utils import memory + +from virttest import utils_misc +from virttest.utils_test import libvirt +from virttest.libvirt_xml import vm_xml +from virttest.utils_libvirt import libvirt_vmxml + +from provider.memory import memory_base +from virttest.staging import utils_memory + +virsh_dargs = {"ignore_status": False, "debug": True} + + +def adjust_size_unit(params): + """ + Adjust the unit of dimm target size. + + :param params: cartesian config parameters. + :return target_size, init define dimm target size. + """ + plug_dimm_type = params.get("plug_dimm_type") + if plug_dimm_type in ["source_and_mib"]: + target_size = memory_base.convert_data_size( + params.get("target_size") + params.get('size_unit'), 'KiB') + else: + target_size = params.get("target_size") + + return int(target_size) + + +def check_guest_virsh_dominfo(vm, test, params, unplugged=False): + """ + Check current memory value and memory value in virsh dominfo result. + + :param vm: vm object. + :param test: test object. + :param params: dictionary with the test parameters. + :param unplugged: boolean, the flag of unplugging. + """ + mem_value = int(params.get("mem_value")) + current_mem = int(params.get("current_mem")) + + target_size = adjust_size_unit(params) + if unplugged: + expected_mem = str(mem_value - target_size) + expected_curr = str(current_mem - target_size) + else: + expected_mem = str(mem_value) + expected_curr = str(current_mem) + + memory_base.check_dominfo(vm, test, expected_mem, expected_curr) + + +def check_after_detach(vm, test, params): + """ + Check the below points after unplugging. + + 1. Check the audit log by ausearch. + 2. Check the libvirtd log. + 3. Check the memory allocation and memory device config. + 4. Check the memory info by virsh dominfo. + 5. Check the guest memory. + + :param vm: vm object. + :param test: test object. + :param params: dictionary with the test parameters. + :param operation: string, the flag for attaching or detaching. + """ + mem_value = int(params.get("mem_value")) + current_mem = int(params.get("current_mem")) + expected_log = params.get("expected_log") + audit_cmd = params.get("audit_cmd") + base_xpath, dimm_xpath = params.get("base_xpath"), params.get("dimm_xpath") + + target_size = adjust_size_unit(params) + libvirtd_log_file = os.path.join(test.debugdir, "libvirtd.log") + ausearch_check = params.get("ausearch_check") % (mem_value, mem_value - target_size) + + # Check the audit log by ausearch. + ausearch_result = process.run(audit_cmd, shell=True) + libvirt.check_result(ausearch_result, expected_match=ausearch_check) + test.log.debug("Check audit log %s successfully." % ausearch_check) + + # Check the libvirtd log. + result = utils_misc.wait_for( + lambda: libvirt.check_logfile(expected_log, libvirtd_log_file), timeout=20) + if not result: + test.fail("Can't get expected log %s in %s" % (expected_log, libvirtd_log_file)) + + # Check the memory allocation and memory device config. + vmxml = vm_xml.VMXML.new_from_dumpxml(vm.name) + libvirt_vmxml.check_guest_xml_by_xpaths( + vmxml, eval(base_xpath % (mem_value - target_size, current_mem - target_size))) + if vmxml.devices.by_device_tag("memory"): + test.fail("Dimm memory still exist after unplugging") + + # Check the memory info by virsh dominfo. + check_guest_virsh_dominfo(vm, test, params, unplugged=True) + + # Check the guest memory. + session = vm.wait_for_login() + new_memtotal = utils_memory.memtotal(session) + session.close() + expected_memtotal = params.get('old_memtotal') - target_size + if new_memtotal != expected_memtotal: + test.fail("Memtotal is %s, should be %s " % (new_memtotal, expected_memtotal)) + test.log.debug("Check Memtotal successfully.") + + +def run(test, params, env): + """ + Verify dimm memory device hot unplug with different configs. + """ + def setup_test(): + """ + Allocate memory on the host. + """ + process.run("echo %d > %s" % ( + allocate_size / default_hugepage_size, + kernel_hp_file % default_hugepage_size), shell=True) + + def run_test(): + """ + 1. Define vm with dimm memory device. + 2. Hot unplug dimm memory. + 3. Check audit log, libvirtd log, memory allocation and memory device + config. + """ + test.log.info("TEST_STEP1: Define vm with dimm memory") + memory_base.define_guest_with_memory_device(params, dimm_dict, vm_attrs) + + test.log.info("TEST_STEP2: Start guest") + vm.start() + session = vm.wait_for_login() + + test.log.info("TEST_STEP3: Get the guest memory") + params.update({'old_memtotal': utils_memory.memtotal(session)}) + session.close() + + test.log.info("TEST_STEP4: Check the memory allocation and dimm config") + target_size = adjust_size_unit(params) + vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) + libvirt_vmxml.check_guest_xml_by_xpaths( + vmxml, eval(base_xpath % (mem_value, current_mem))) + libvirt_vmxml.check_guest_xml_by_xpaths( + vmxml.devices.by_device_tag("memory")[0], eval(dimm_xpath % (target_size, slot))) + + test.log.info("TEST_STEP5: Check the memory info by virsh dominfo") + check_guest_virsh_dominfo(vm, test, params) + + test.log.info("TEST_STEP6: Hot unplug one dimm memory device") + memory_base.plug_memory_and_check_result( + test, params, mem_dict=unplug_dict, operation='detach', + expected_error=unplug_error, expected_event=unplug_event, + event_timeout=20) + + if mem_state in ["online_movable_mem"]: + test.log.info("TEST_STEP7: Check audit and libvirt log, " + "memory allocation and memory device config") + check_after_detach(vm, test, params) + + def teardown_test(): + """ + Clean data. + """ + test.log.info("TEST_TEARDOWN: Clean up env.") + bkxml.sync() + process.run("echo 0 > %s" % (kernel_hp_file % default_hugepage_size), shell=True) + + vm_name = params.get("main_vm") + original_xml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + bkxml = original_xml.copy() + vm = env.get_vm(vm_name) + default_hugepage_size = memory.get_huge_page_size() + + slot = params.get("slot") + plug_dimm_type = params.get("plug_dimm_type") + if plug_dimm_type == "source_and_mib": + dimm_dict = eval(params.get("dimm_dict") % default_hugepage_size) + unplug_dict = dimm_dict + else: + dimm_dict = eval(params.get("dimm_dict")) + unplug_dict = eval(params.get("unplug_dimm_dict", "{}")) + + unplug_error = params.get('unplug_error') + unplug_event = params.get('unplug_event') + kernel_hp_file = params.get("kernel_hp_file") + vm_attrs = eval(params.get("vm_attrs", "{}")) + allocate_size = int(params.get("allocate_size")) + mem_value = int(params.get("mem_value")) + current_mem = int(params.get("current_mem")) + base_xpath, dimm_xpath = params.get("base_xpath"), params.get("dimm_xpath") + mem_state = params.get("mem_state") + + try: + setup_test() + run_test() + + finally: + teardown_test() diff --git a/libvirt/tests/src/memory/memory_devices/dimm_memory_hotplug.py b/libvirt/tests/src/memory/memory_devices/dimm_memory_hotplug.py new file mode 100644 index 00000000000..e00b410306d --- /dev/null +++ b/libvirt/tests/src/memory/memory_devices/dimm_memory_hotplug.py @@ -0,0 +1,245 @@ +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Copyright Redhat +# +# SPDX-License-Identifier: GPL-2.0 + +# Author: Nannan Li +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +import os + +from avocado.utils import process +from avocado.utils import memory + +from virttest import utils_misc + +from virttest.utils_test import libvirt +from virttest.libvirt_xml import vm_xml +from virttest.utils_libvirt import libvirt_vmxml + +from provider.memory import memory_base +from virttest.staging import utils_memory + +virsh_dargs = {"ignore_status": False, "debug": True} + + +def adjust_dimm_dict(params): + """ + Adjust dimm memory dict and plugging dimm dict. + + :param params: dictionary with the test parameters + """ + source_dict = params.get("source_dict", "") + addr_dict = params.get("addr_dict", "") + plug_addr = params.get("plug_addr", "") + dimm_dict = eval(params.get("dimm_dict", "{}")) + plug_dimm_dict = eval(params.get("plug_dimm_dict", "{}")) + default_hugepage_size = memory.get_huge_page_size() + + if source_dict: + dimm_dict['source'] = eval(source_dict % default_hugepage_size) + plug_dimm_dict['source'] = eval(source_dict % default_hugepage_size) + if addr_dict: + dimm_dict['address'] = eval(addr_dict) + plug_dimm_dict['address'] = eval(plug_addr) + params.update({'dimm_dict': dimm_dict}) + params.update({'plug_dimm_dict': plug_dimm_dict}) + + +def adjust_size_unit(params, plugged=False): + """ + Adjust the unit of dimm target size and plugged dimm target size. + + :param params: cartesian config parameters. + :param plugged: the flag of after plugging. + :return target_size, plugged_size, init define dimm target size and + plugged dimm target size + """ + plug_dimm_type = params.get("plug_dimm_type") + if plug_dimm_type in ["source_and_mib", "zero_memory_unit_gb"]: + target_size = memory_base.convert_data_size( + params.get("target_size") + params.get('size_unit'), 'KiB') + else: + target_size = params.get("target_size") + + if plugged: + if plug_dimm_type in ["source_and_mib", "zero_memory_unit_gb"]: + plugged_size = memory_base.convert_data_size( + params.get("plug_target_size") + params.get('plug_size_unit'), 'KiB') + else: + plugged_size = params.get('plug_target_size') + else: + plugged_size = 0 + return int(target_size), int(plugged_size) + + +def attach_dimm_and_check_result(test, params): + """ + Attach dimm memory and check result. + + :param test: test object. + :param params: dictionary with the test parameters. + """ + plug_error = params.get('plug_error') + plug_event = params.get('plug_event') + plug_dict = params.get("plug_dimm_dict") + memory_base.plug_memory_and_check_result( + test, params, mem_dict=plug_dict, operation='attach', + expected_error=plug_error, expected_event=plug_event) + + +def check_guest_virsh_dominfo(vm, test, params, plugged=False): + """ + Check current memory value and memory value in virsh dominfo result. + + :param vm: vm object. + :param test: test object. + :param params: dictionary with the test parameters. + :param plugged: the flag of checking after plugging dimm. + """ + mem_value = int(params.get("mem_value")) + current_mem = int(params.get("current_mem")) + target_size, plugged_size = adjust_size_unit(params, plugged=plugged) + expected_mem = str(mem_value + target_size + plugged_size) + expected_curr = str(current_mem + plugged_size) + + memory_base.check_dominfo(vm, test, expected_mem, expected_curr) + + +def check_after_attach(vm, test, params): + """ + Check the below points after plugging or unplugging + 1. Check the audit log by ausearch. + 2. Check the libvirtd log. + 3. Check the memory allocation and memory device config. + 4. Check the memory info by virsh dominfo. + 5. Check the guest memory. + + :param vm: vm object. + :param test: test object. + :param params: dictionary with the test parameters. + :param operation: string, the flag for attaching or detaching. + """ + mem_value = int(params.get("mem_value")) + current_mem = int(params.get("current_mem")) + expected_log = params.get("expected_log") + audit_cmd = params.get("audit_cmd") + plug_slot = params.get("plug_slot") + libvirtd_log_file = os.path.join(test.debugdir, "libvirtd.log") + target_size, plugged_size = adjust_size_unit(params, plugged=True) + base_xpath, dimm_xpath = params.get("base_xpath"), params.get("dimm_xpath") + ausearch_check = params.get("ausearch_check") % ( + mem_value+target_size, mem_value+target_size+plugged_size) + + # Check the audit log by ausearch. + ausearch_result = process.run(audit_cmd, shell=True) + libvirt.check_result(ausearch_result, expected_match=ausearch_check) + test.log.debug("Check audit log %s successfully." % ausearch_check) + + # Check the libvirtd log. + result = utils_misc.wait_for( + lambda: libvirt.check_logfile(expected_log, libvirtd_log_file), timeout=20) + if not result: + test.fail("Can't get expected log %s in %s" % (expected_log, libvirtd_log_file)) + + # Check the memory allocation and memory device config. + vmxml = vm_xml.VMXML.new_from_dumpxml(vm.name) + libvirt_vmxml.check_guest_xml_by_xpaths( + vmxml, eval(base_xpath % (mem_value + target_size + plugged_size, + current_mem + plugged_size))) + libvirt_vmxml.check_guest_xml_by_xpaths( + vmxml.devices.by_device_tag("memory")[1], eval(dimm_xpath % (plugged_size, plug_slot))) + + # Check the memory info by virsh dominfo. + check_guest_virsh_dominfo(vm, test, params, plugged=True) + + # Check the guest memory. + session = vm.wait_for_login() + new_memtotal = utils_memory.memtotal(session) + session.close() + expected_memtotal = params.get('old_memtotal') + plugged_size + if new_memtotal != expected_memtotal: + test.fail("Memtotal is %s, should be %s " % (new_memtotal, expected_memtotal)) + test.log.debug("Check Memtotal successfully.") + + +def run(test, params, env): + """ + Verify dimm memory device hot-plug with different configs. + """ + def setup_test(): + """ + Allocate memory on the host. + """ + process.run("echo %d > %s" % ( + allocate_size / default_hugepage_size, + kernel_hp_file % default_hugepage_size), shell=True) + + def run_test(): + """ + 1. Define vm with dimm memory device. + 2. Hotplug dimm memory. + 3. Check audit log, libvirtd log, memory allocation and memory device + config. + """ + test.log.info("TEST_STEP1: Define vm with dimm memory") + memory_base.define_guest_with_memory_device(params, params.get("dimm_dict"), vm_attrs) + + test.log.info("TEST_STEP2: Start guest") + vm.start() + session = vm.wait_for_login() + + test.log.info("TEST_STEP3: Get the guest memory") + params.update({'old_memtotal': utils_memory.memtotal(session)}) + session.close() + + test.log.info("TEST_STEP4: Check the memory allocation and dimm config") + target_size, _ = adjust_size_unit(params) + vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) + libvirt_vmxml.check_guest_xml_by_xpaths( + vmxml, eval(base_xpath % (mem_value + target_size, current_mem))) + libvirt_vmxml.check_guest_xml_by_xpaths( + vmxml.devices.by_device_tag("memory")[0], eval(dimm_xpath % (target_size, slot))) + + test.log.info("TEST_STEP5: Check the memory info by virsh dominfo") + check_guest_virsh_dominfo(vm, test, params) + + test.log.info("TEST_STEP6: Hot plug one dimm memory device") + attach_dimm_and_check_result(test, params) + + if plug_dimm_type in ["target_and_address", "source_and_mib"]: + test.log.info("TEST_STEP7:Check audit and libvirt log, memory " + "allocation and memory device config ") + check_after_attach(vm, test, params) + + def teardown_test(): + """ + Clean data. + """ + test.log.info("TEST_TEARDOWN: Clean up env.") + bkxml.sync() + process.run("echo 0 > %s" % (kernel_hp_file % default_hugepage_size), shell=True) + + vm_name = params.get("main_vm") + original_xml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + bkxml = original_xml.copy() + vm = env.get_vm(vm_name) + adjust_dimm_dict(params) + + slot = params.get("slot") + kernel_hp_file = params.get("kernel_hp_file") + vm_attrs = eval(params.get("vm_attrs", "{}")) + allocate_size = int(params.get("allocate_size")) + mem_value = int(params.get("mem_value")) + current_mem = int(params.get("current_mem")) + base_xpath, dimm_xpath = params.get("base_xpath"), params.get("dimm_xpath") + plug_dimm_type = params.get("plug_dimm_type") + default_hugepage_size = memory.get_huge_page_size() + + try: + setup_test() + run_test() + + finally: + teardown_test() diff --git a/libvirt/tests/src/memory/memory_devices/dimm_memory_lifecycle.py b/libvirt/tests/src/memory/memory_devices/dimm_memory_lifecycle.py new file mode 100644 index 00000000000..f3ea9dcdbb7 --- /dev/null +++ b/libvirt/tests/src/memory/memory_devices/dimm_memory_lifecycle.py @@ -0,0 +1,261 @@ +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Copyright Red Hat +# +# SPDX-License-Identifier: GPL-2.0 +# +# Author: Liang Cong +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +import os +import re + +from avocado.utils import process + +from virttest import data_dir +from virttest import test_setup +from virttest import virsh +from virttest.libvirt_xml import vm_xml +from virttest.libvirt_xml.devices import memory +from virttest.utils_libvirt import libvirt_memory +from virttest.utils_libvirt import libvirt_vmxml +from virttest.utils_libvirtd import Libvirtd +from virttest.utils_test import libvirt + +from provider.memory import memory_base +from provider.numa import numa_base + + +def run(test, params, env): + """ + Verify various config of dimm memory device settings take effect + during the life cycle of guest vm. + """ + + def clean_empty_memory_device_config(mem_device_dict): + """ + Clean empty config of the memory device + + :param mem_device_dict (dict): memory device config dictionary + """ + for key in list(mem_device_dict.keys()): + if not mem_device_dict[key]: + del mem_device_dict[key] + + def check_dimm_mem_device_xml(xpath_dict): + """ + Check the dimm memory device config by xpath + + :param xpath_dict (dict): xpath dict to check if the memory config is correct, + like {"alias_name":[xpath1, xpath2]},...} + """ + vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) + test.log.debug(f"Current guest config xml is:\n{vmxml}") + memory_devices = vmxml.devices.by_device_tag('memory') + target_memory_num = 0 + for alias_name, xpath_list in xpath_dict.items(): + for memory_device in memory_devices: + if alias_name == memory_device.alias.get('name'): + target_memory_num = target_memory_num + 1 + for xpath in xpath_list: + libvirt_vmxml.check_guest_xml_by_xpaths(memory_device, xpath) + if target_memory_num != len(xpath_dict): + test.fail( + f"Expected {len(xpath_dict)} dimm mem devices with required alias name, but found {target_memory_num}") + + def check_numa_node_memory_allocation(mem_size, numa_list, page_size): + """ + Check memory is allocated on target numa list with correct page size + + :param mem_size (int): memory size + :param numa_list (list): target numa list + :param page_size (str): page size of the memory + """ + cmd_output = numa_base.get_host_numa_memory_alloc_info(mem_size) + actual_numa_list = re.findall(r'N(\d+)=', cmd_output) + if not set(actual_numa_list).issubset(set(numa_list)): + test.fail( + f"Expected numa list {numa_list} doesn't contain actual numa in numa_maps output {cmd_output}") + if not re.search(fr'kernelpagesize_kB={page_size}', cmd_output): + test.fail( + f"Failed to find {page_size}kb memory page size in numa_maps output {cmd_output}") + + def check_case_availability(): + """ + Check whether the case is available + """ + memory_base.check_mem_page_sizes(test, page_size, default_hp_size) + memory_base.check_supported_version(params, test, vm) + + def setup_test(): + """ + Setup for the case: + 1. Get host available numa nodes + 2. Change parameters according to available numa nodes + 3. Allocate huge page memory for target host node if needs + """ + if nodeset_num: + numatest_obj = numa_base.NumaTest(vm, params, test) + if 1 == nodeset_num: + min_memory_size = init_size + plug_size + elif 2 == nodeset_num: + min_memory_size = init_size if init_size >= plug_size else plug_size + numatest_obj.check_numa_nodes_availability(nodeset_num, min_memory_size) + numa_list = numatest_obj.get_available_numa_nodes(min_memory_size)[:nodeset_num] + nodeset_str = numa_base.convert_to_string_with_dash( + ','.join([str(node) for node in numa_list])) + params["numa_node_list"] = numa_list + source_dict = params.get("source_dict") + source_xpath = params.get("source_xpath") + source_dict = eval(source_dict % nodeset_str) + source_xpath = eval(source_xpath % nodeset_str) + init_mem_device_dict["source"] = source_dict + plug_mem_device_dict["source"] = source_dict + init_xpath_list[0] = source_xpath + plug_xpath_list[0] = source_xpath + test.log.debug(f"Selected numa nodeset is:{nodeset_str}") + + if use_huge_page: + params["target_nodes"] = " ".join([str(node) for node in numa_list]) + params["target_hugepages"] = (init_size + plug_size) / default_hp_size + hpc = test_setup.HugePageConfig(params) + hpc.setup() + + if vm.is_alive(): + vm.destroy() + + def run_test(): + """ + Test steps + """ + test.log.info("TEST_STEP1: Define the guest") + clean_empty_memory_device_config(init_mem_device_dict) + memory_base.define_guest_with_memory_device(params, init_mem_device_dict, vm_attrs) + + if use_huge_page: + test.log.info("TEST_STEP2: Check secure context for default huge page mount path") + cmd_result = process.run(check_path_secure_cmd, ignore_status=True, shell=True) + libvirt.check_result(cmd_result, expected_match=path_secure_context) + + test.log.info("TEST_STEP3: Start the guest") + vm.start() + vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) + test.log.debug(f"Guest config xml after start is:\n{vmxml}") + + if use_huge_page: + test.log.info("TEST_STEP4: Check secure context for default huge page mount path") + check_cmd = check_guest_secure_cmd % (vm.get_id(), vm_name) + cmd_result = process.run(check_cmd, ignore_status=True, shell=True) + libvirt.check_result(cmd_result, expected_match=guest_secure_context) + + test.log.info("TEST_STEP5: Check dimm memory device config by virsh dumpxml") + check_dimm_mem_device_xml({init_alias_name: init_xpath_list}) + + if bios_check: + test.log.info("TEST_STEP6: Check smbios, sysinfo and idmap info by virsh dumpxml") + libvirt_vmxml.check_guest_xml_by_xpaths(vmxml, bios_check_xpath) + + test.log.info("TEST_STEP7: Hotplug a dimm memory device") + clean_empty_memory_device_config(plug_mem_device_dict) + mem_device = memory.Memory() + mem_device.setup_attrs(**plug_mem_device_dict) + virsh.attach_device(vm_name, mem_device.xml, **virsh_dargs) + + test.log.info( + "TEST_STEP8: Check dimm memory device config by virsh dumpxml") + check_dimm_mem_device_xml( + {init_alias_name: init_xpath_list, plug_alias_name: plug_xpath_list}) + + test.log.info("TEST_STEP9: Consume the guest memory") + with vm.wait_for_login() as session: + libvirt_memory.consume_vm_freememory(session) + + if nodeset_num: + test.log.info("TEST_STEP10: Check dimm memory device source node") + numa_list = [str(node) for node in params['numa_node_list']] + expected_page_size = default_hp_size if use_huge_page else page_size + check_numa_node_memory_allocation(init_size, numa_list, expected_page_size) + check_numa_node_memory_allocation(plug_size, numa_list, expected_page_size) + + test.log.info("TEST_STEP11: Life cycle test") + virsh.suspend(vm_name, **virsh_dargs) + virsh.resume(vm_name, **virsh_dargs) + check_dimm_mem_device_xml( + {init_alias_name: init_xpath_list, plug_alias_name: plug_xpath_list}) + + virsh.save(vm_name, state_file, **virsh_dargs) + virsh.restore(state_file, **virsh_dargs) + check_dimm_mem_device_xml( + {init_alias_name: init_xpath_list, plug_alias_name: plug_xpath_list}) + + virsh.managedsave(vm_name, **virsh_dargs) + vm.start() + check_dimm_mem_device_xml( + {init_alias_name: init_xpath_list, plug_alias_name: plug_xpath_list}) + + vm.reboot() + vm.wait_for_login().close() + check_dimm_mem_device_xml( + {init_alias_name: init_xpath_list, plug_alias_name: plug_xpath_list}) + + libvirt_daemon = Libvirtd() + if not libvirt_daemon.restart(reset_failed=False): + test.error("libvirt deamon restarts failed or is not working properly") + check_dimm_mem_device_xml( + {init_alias_name: init_xpath_list, plug_alias_name: plug_xpath_list}) + + def teardown_test(): + """ + 1. Restore guest config xml + 2. Clean huge page memory + 3. Remove state file + """ + bkxml.sync() + if use_huge_page: + hpc = test_setup.HugePageConfig(params) + hpc.cleanup() + if os.path.exists(state_file): + os.remove(state_file) + + vm_name = params.get("main_vm") + vm = env.get_vm(vm_name) + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + bkxml = vmxml.copy() + + vm_attrs = eval(params.get("vm_attrs", "{}")) + bios_check = params.get("bios_check", "no") == "yes" + if bios_check: + sysinfo_attrs = eval(params.get("sysinfo_attrs", "{}")) + idmap_attrs = eval(params.get("idmap_attrs", "{}")) + os_attrs = eval(params.get("os_attrs", "{}")) + vm_attrs.update({'sysinfo': sysinfo_attrs, + 'os': os_attrs, 'idmap': idmap_attrs}) + bios_check_xpath = eval(params.get("bios_check_xpath")) + init_mem_device_dict = eval( + params.get("init_mem_device_dict", "{}")) + plug_mem_device_dict = eval( + params.get("plug_mem_device_dict", "{}")) + init_xpath_list = eval(params.get("init_xpath_list")) + plug_xpath_list = eval(params.get("plug_xpath_list")) + check_path_secure_cmd = params.get("check_path_secure_cmd") + path_secure_context = params.get("path_secure_context") + check_guest_secure_cmd = params.get("check_guest_secure_cmd") + guest_secure_context = params.get("guest_secure_context") + init_alias_name = params.get("init_alias_name") + plug_alias_name = params.get("plug_alias_name") + page_size = int(params.get("page_size")) + default_hp_size = int(params.get("default_hp_size")) + init_size = int(params.get("init_size")) + plug_size = int(params.get("plug_size")) + nodeset_num = int(params.get("nodeset_num", "0")) + use_huge_page = "yes" == params.get("use_huge_page") + state_file = f"{data_dir.get_tmp_dir()}/{vm_name}.save" + virsh_dargs = {"debug": True, "ignore_status": False} + + try: + check_case_availability() + setup_test() + run_test() + + finally: + teardown_test() diff --git a/libvirt/tests/src/memory/memory_devices/dimm_memory_with_access_and_discard.py b/libvirt/tests/src/memory/memory_devices/dimm_memory_with_access_and_discard.py new file mode 100644 index 00000000000..1b0fc451745 --- /dev/null +++ b/libvirt/tests/src/memory/memory_devices/dimm_memory_with_access_and_discard.py @@ -0,0 +1,233 @@ +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Copyright Redhat +# +# SPDX-License-Identifier: GPL-2.0 + +# Author: Nannan Li +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +import re +import json + +from avocado.utils import memory +from avocado.utils import process + +from virttest import utils_test +from virttest import virsh +from virttest.libvirt_xml import vm_xml +from virttest.utils_libvirtd import Libvirtd +from virttest.utils_libvirt import libvirt_vmxml + +virsh_dargs = {"ignore_status": False, "debug": True} + + +def get_vm_attrs(test, params): + """ + Get vm attrs. + + :param test: test object + :param params: dictionary with the test parameters + :return vm_attrs: get updated vm attrs dict. + """ + vm_attrs = eval(params.get("vm_attrs", "{}")) + source_attr = params.get("source_attr", "") + discard_attr = params.get("discard_attr", "") + access_attr = params.get("access_attr", "") + + mb_value = "" + for item in [source_attr, discard_attr, access_attr]: + if item != "": + mb_value += item + "," + mb_attrs = eval("{'mb':{%s}}" % mb_value[:-1]) + + vm_attrs.update(mb_attrs) + test.log.debug("Get current vm attrs is :%s", vm_attrs) + + return vm_attrs + + +def create_dimm_objects(test, params): + """ + Get 6 basic different dimm memory devices object. + + :param test: test object. + :param params: dictionary with the test parameters. + :return mem_list: dimm memory device object list. + """ + default_hugepage_size = memory.get_huge_page_size() + mem_list = [] + for item in [(None, None, 0), ('shared', 'yes', 0), + (None, None, 1), ('private', 'no', 1), + (None, None, 2), ('shared', 'yes', 2)]: + + single_mem = eval(params.get("dimm_basic") % default_hugepage_size) + target = single_mem['target'] + target.update({'node': item[2]}) + + if item[0] is not None: + single_mem.update({'mem_access': item[0]}) + if item[1] is not None: + single_mem.update({'mem_discard': item[1]}) + test.log.debug("Get one dimm dict is:'%s'\n", single_mem) + + dimm_obj = libvirt_vmxml.create_vm_device_by_type( + 'memory', single_mem) + mem_list.append(dimm_obj) + + return mem_list + + +def plug_dimm(test, params, vm, operation): + """ + Hot plug or Cold plug dimm + + :param test: test object. + :param params: dictionary with the test parameters. + :param vm: vm object. + :param operation: flag for hot plugging or cold plugging. + """ + vm_name = params.get("main_vm") + attach_option = params.get("attach_option") + + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + vmxml.remove_all_device_by_type("memory") + + all_dimms = create_dimm_objects(test, params) + if operation == "cold_plug": + pass + elif operation == "hot_plug": + vm.start() + vm.wait_for_login().close() + Libvirtd().restart() + + for mem in all_dimms: + virsh.attach_device(vm_name, mem.xml, + flagstr=attach_option, + **virsh_dargs) + + +def check_access_and_discard(test, params, vm, + expected_share, expected_discard): + """ + Check access and discard setting. + + :param test: test object. + :param params: dictionary with the test parameters. + :param vm: vm object. + :param expected_share: expected access shared value list. + :param expected_discard: expected discard value list. + """ + dimm_mem_num = int(params.get("dimm_mem_num")) + check_discard = params.get("check_discard") + discard_error_msg = params.get("discard_error_msg") + mem_name_list = [] + + if not vm.is_alive(): + vm.start() + # Check access share setting + ret = virsh.qemu_monitor_command(vm.name, "info memdev", "--hmp", + debug=True).stdout_text.replace("\r\n", "") + for index in range(dimm_mem_num): + mem_name = "memdimm%d" % index + pattern = "memory backend: %s.*share: %s " % (mem_name, expected_share[index]) + if not re.search(pattern, ret): + test.fail("Expect '%s' exist, but not found" % pattern) + else: + test.log.debug("Check access shared value is '%s': PASS", pattern) + mem_name_list.append(mem_name) + + # Check discard setting + for index, mem_name in enumerate(mem_name_list): + res = virsh.qemu_monitor_command( + vm.name, check_discard % mem_name, debug=True).stdout_text + + if 'return' in json.loads(res): + actual_discard = str(json.loads(res)['return']) + if actual_discard != expected_discard[index]: + test.fail("Expect discard is '%s', but got '%s'" % ( + expected_discard[index], actual_discard)) + else: + test.log.debug("Check discard value is '%s' PASS", actual_discard) + else: + actual_error = json.loads(res)['error']['desc'] + if not re.search(discard_error_msg, actual_error): + test.fail("Expected to get '%s' in '%s'" % (discard_error_msg, + actual_error)) + else: + test.log.debug("Check '%s' PASS ", actual_error) + + +def run(test, params, env): + """ + Verify dimm memory device works with access and discard settings. + """ + def setup_test(): + """ + Set kernel parameter memhp_default_state to online_movable( + this would make hotunplug more reliable) + """ + utils_test.update_boot_option(vm, args_added=kernel_params_add, + need_reboot=True) + vm.destroy() + + def run_test(): + """ + 1.Define vm with dimm memory device. + 2.Check the dimm memory device access and discard setting. + 3.Define vm without dimm memory device and restart service, and hotplug + dimm device. + """ + test.log.info("TEST_STEP1: Define vm with numa") + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + vm_attrs = get_vm_attrs(test, params) + vmxml.setup_attrs(**vm_attrs) + vmxml.sync() + + test.log.info("TEST_STEP2-5: Plug dimm memory devices") + plug_dimm(test, params, vm, operation) + + test.log.info("TEST_STEP6,7: Check dimm memory access and discard") + check_access_and_discard(test, params, vm, expected_share, + expected_discard) + + test.log.info("TEST_STEP8:Hot unplug all dimm memory device") + for dimm in create_dimm_objects(test, params): + virsh.detach_device(vm_name, dimm.xml, **virsh_dargs) + + test.log.info("TEST_STEP9: Destroy vm") + vm.destroy() + + test.log.info("TEST_STEP10: Check the host path for memory file backing") + res = process.run(check_path % vm_name, shell=True, ignore_status=True).stderr_text + if not re.search(path_error, res): + test.fail("Expected '%s', but got '%s'" % (path_error, res)) + + def teardown_test(): + """ + Clean data. + """ + test.log.info("TEST_TEARDOWN: Clean up env.") + if not vm.is_alive(): + vm.start() + utils_test.update_boot_option(vm, args_removed=kernel_params_add) + bkxml.sync() + + vm_name = params.get("main_vm") + original_xml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + bkxml = original_xml.copy() + vm = env.get_vm(vm_name) + + operation = params.get("operation") + kernel_params_add = params.get("kernel_params_add") + expected_share = eval(params.get("expected_share")) + expected_discard = eval(params.get("expected_discard")) + check_path = params.get("check_path") + path_error = params.get("path_error", "No such file or directory") + + try: + setup_test() + run_test() + + finally: + teardown_test() diff --git a/libvirt/tests/src/memory/memory_devices/dimm_memory_with_auto_placement_numatune.py b/libvirt/tests/src/memory/memory_devices/dimm_memory_with_auto_placement_numatune.py new file mode 100644 index 00000000000..e4beeda8399 --- /dev/null +++ b/libvirt/tests/src/memory/memory_devices/dimm_memory_with_auto_placement_numatune.py @@ -0,0 +1,74 @@ +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Copyright Redhat +# +# SPDX-License-Identifier: GPL-2.0 + +# Author: Nannan Li +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +from virttest import virsh + +from virttest.libvirt_xml import vm_xml +from virttest.utils_libvirt import libvirt_vmxml + +from provider.numa import numa_base + + +def run(test, params, env): + """ + 1.Define guest with dimm devices and start guest. + 2.Attach dimm memory. + """ + + def setup_test(): + """ + Check available numa nodes num. + """ + test.log.info("TEST_SETUP: Check available numa nodes num") + numa_obj = numa_base.NumaTest(vm, params, test) + numa_obj.check_numa_nodes_availability() + + def run_test(): + """ + Verify dimm memory device works with auto placement numatune. + """ + test.log.info("TEST_SETUP1: Define guest with dimm memory") + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + vmxml.setup_attrs(**vm_attrs) + new_dimm = libvirt_vmxml.create_vm_device_by_type('memory', dimm_dict) + vmxml.devices = vmxml.devices.append(new_dimm) + vmxml.sync() + + test.log.info("TEST_STEP2: Start vm") + vm.start() + vm.wait_for_login().close() + vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) + test.log.debug("Get guest xml is '%s' ", vmxml) + + test.log.info("TEST_SETUP3: Hotplug a dimm device") + attach_mem = libvirt_vmxml.create_vm_device_by_type('memory', attach_dimm) + virsh.attach_device(vm.name, attach_mem.xml, debug=True, + wait_for_event=True, ignore_status=False) + + def teardown_test(): + """ + Clean data. + """ + test.log.info("TEST_TEARDOWN: Clean up env.") + bkxml.sync() + + vm_name = params.get("main_vm") + vm = env.get_vm(vm_name) + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + bkxml = vmxml.copy() + vm_attrs = eval(params.get('vm_attrs', '{}')) + dimm_dict = eval(params.get('dimm_dict', '{}')) + attach_dimm = eval(params.get("attach_dimm", '{}')) + + try: + setup_test() + run_test() + + finally: + teardown_test() diff --git a/libvirt/tests/src/memory/memory_devices/dimm_memory_with_memory_alloccation_and_numa.py b/libvirt/tests/src/memory/memory_devices/dimm_memory_with_memory_alloccation_and_numa.py new file mode 100644 index 00000000000..a80e1f07bd2 --- /dev/null +++ b/libvirt/tests/src/memory/memory_devices/dimm_memory_with_memory_alloccation_and_numa.py @@ -0,0 +1,198 @@ +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Copyright Redhat +# +# SPDX-License-Identifier: GPL-2.0 + +# Author: Nannan Li +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +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.memory import memory_base + +virsh_dargs = {'debug': True, 'ignore_status': False} + + +def get_vm_attrs(test, params): + """ + Get vm attrs. + + :param test: test object + :param params: dictionary with the test parameters + :return vm_attrs: get updated vm attrs dict. + """ + mem_dict = params.get("mem_dict") + max_dict = params.get("max_dict") + numa_dict = params.get("numa_dict") + all_attrs = "" + for item in [mem_dict, max_dict, numa_dict]: + if item != "": + all_attrs += item + "," + + vm_attrs = eval("{"+all_attrs+"}") + test.log.debug("Get current vm attrs is :%s", vm_attrs) + + return vm_attrs + + +def define_guest(params, guest_xml): + """ + Define guest and check result. + + :param params: dictionary with the test parameters. + :param guest_xml: the xml you want to define. + """ + define_error = params.get("define_error") + device_operation = params.get("device_operation") + big_size_msg = params.get("big_size_msg") + + res = virsh.define(guest_xml.xml, debug=True) + if params.get('slot_no_numa'): + if device_operation == "init_define_with_big_dimm": + libvirt.check_result(res, big_size_msg) + else: + libvirt.check_exit_status(res) + else: + libvirt.check_result(res, define_error) + + +def check_hotplug_result(params, result): + """ + Check guest hot plug result + + :param params: dict wrapped with params. + :param result: hot plug result. + """ + mem_alloc = params.get("memory_allocation") + device_operation = params.get("device_operation") + numa_setting = params.get("numa_setting") + hotplug_error = params.get("hotplug_error") + hotplug_error_2 = params.get("hotplug_error_2") + + if mem_alloc == "no_maxmemory": + if numa_setting == "no_numa" and device_operation == "hotplug_with_node": + libvirt.check_result(result, hotplug_error_2) + elif mem_alloc == "with_slot" and device_operation == "hotplug_with_node": + libvirt.check_exit_status(result) + else: + libvirt.check_result(result, hotplug_error) + + +def check_coldplug_result(params, result): + """ + Check guest cold plug result + + :param params: dict wrapped with params. + :param result: cold plug result. + """ + mem_alloc = params.get("memory_allocation") + device_operation = params.get("device_operation") + coldplug_error = params.get("coldplug_error") + coldplug_error_2 = params.get("coldplug_error_2") + + if mem_alloc == "with_slot": + if device_operation == "coldplug_without_node": + libvirt.check_result(result, coldplug_error_2) + else: + libvirt.check_exit_status(result) + elif mem_alloc == "no_slot": + libvirt.check_result(result, coldplug_error) + elif mem_alloc == "no_maxmemory": + if device_operation == "coldplug_without_node": + libvirt.check_result(result, coldplug_error_2) + else: + libvirt.check_result(result, coldplug_error) + + +def run(test, params, env): + """ + Verify dimm memory device works with various memory allocation + and guest numa settings. + """ + def run_test_init_define(): + """ + Test when define guest with dimm memory. + """ + test.log.info("TEST_STEP1: Define vm with dimm and memory allocation") + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + vmxml.setup_attrs(**vm_attrs) + vmxml.devices = vmxml.devices.append(mem_obj) + define_guest(params, vmxml) + + if params.get('slot_no_numa') and device_operation == "init_define_with_dimm": + test.log.info("TEST_STEP2,3: Start vm and check guest xml") + vm.start() + vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) + test.log.debug("Get guest xml:%s\n" % vmxml) + libvirt_vmxml.check_guest_xml_by_xpaths(vmxml, basic_xpath) + libvirt_vmxml.check_guest_xml_by_xpaths( + vmxml, eval(dimm_numa_xpath % (str(mem_value-int(target_size)), + target_size))) + + def run_test_coldplug(): + """ + Test guest cold plug with dimm memory. + """ + test.log.info("TEST_STEP1: Define vm without dimm") + original_vmxml.setup_attrs(**vm_attrs) + virsh.define(original_vmxml.xml, **virsh_dargs) + + test.log.info("TEST_STEP2: Cold plug vm with dimm") + ret = virsh.attach_device(vm_name, mem_obj.xml, debug=True, + flagstr="--config") + check_coldplug_result(params, ret) + + def run_test_hotplug(): + """ + Test guest hot plug with dimm memory. + """ + test.log.info("TEST_STEP1: Define vm without dimm") + original_vmxml.setup_attrs(**vm_attrs) + virsh.define(original_vmxml.xml, **virsh_dargs) + virsh.start(vm_name, **virsh_dargs) + vm.wait_for_login().close() + + test.log.info("TEST_STEP2: Hot plug vm with dimm") + res = virsh.attach_device(vm_name, mem_obj.xml, debug=True) + check_hotplug_result(params, res) + + def teardown_test(): + """ + Clean data. + """ + test.log.info("TEST_TEARDOWN: Clean up env.") + bkxml.sync() + + vm_name = params.get("main_vm") + original_vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + bkxml = original_vmxml.copy() + vm = env.get_vm(vm_name) + memory_base.adjust_memory_size(params) + + vm_attrs = get_vm_attrs(test, params) + device_operation = params.get("device_operation") + fs = eval(params.get("format_size")) if params.get("format_size") else "" + dimm_dict = eval(params.get("dimm_dict") % fs) + mem_obj = libvirt_vmxml.create_vm_device_by_type('memory', dimm_dict) + + target_size = params.get("target_size") + mem_value = int(params.get("mem_value")) + basic_xpath = eval(params.get("basic_xpath")) + dimm_numa_xpath = params.get("dimm_numa_xpath") + run_test = eval('run_test_%s' % device_operation.split('_with')[0]) + + memory_allocation = params.get("memory_allocation") + numa_setting = params.get("numa_setting") + params.update( + {'slot_no_numa': memory_allocation == "with_slot" and numa_setting == "no_numa"}) + + try: + run_test() + + finally: + teardown_test() diff --git a/libvirt/tests/src/memory/memory_devices/invalid_dimm_memory_device_config.py b/libvirt/tests/src/memory/memory_devices/invalid_dimm_memory_device_config.py new file mode 100644 index 00000000000..148040df382 --- /dev/null +++ b/libvirt/tests/src/memory/memory_devices/invalid_dimm_memory_device_config.py @@ -0,0 +1,171 @@ +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Copyright Redhat +# +# SPDX-License-Identifier: GPL-2.0 + +# Author: Nannan Li +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +from avocado.utils import process + +from virttest import libvirt_version +from virttest import virsh + +from virttest.libvirt_xml import vm_xml +from virttest.libvirt_xml.devices import memory +from virttest.utils_test import libvirt + +from provider.numa import numa_base + + +def get_pagesize_value(params): + """ + Get pagesize value + + :param params: Dictionary with the test parameters + :return: page_size, The page size to set in original vmxml + """ + invalid_pagesize = params.get("invalid_pagesize") + pagesize_cmd = params.get("pagesize_cmd") + + if invalid_pagesize: + page_size = invalid_pagesize + else: + page_size = process.run(pagesize_cmd, ignore_status=True, + shell=True).stdout_text.strip() + return int(page_size) + + +def get_mem_obj(mem_dict): + """ + Get mem object. + + :param mem_dict: memory dict value. + :return mem_obj: object of memory devices. + """ + mem_obj = memory.Memory() + mem_obj.setup_attrs(**eval(mem_dict)) + return mem_obj + + +def define_guest(test, params, page_size): + """ + Define guest with specific + + :param test: test object. + :param params: dict, test parameters. + :param page_size: page size value in vm xml. + """ + vm_name = params.get("main_vm") + vm_attrs = eval(params.get("vm_attrs")) + dimm_dict = params.get("dimm_dict") + invalid_setting = params.get("invalid_setting") + + vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) + vmxml.setup_attrs(**vm_attrs) + + devices = vmxml.get_devices() + mem_obj = get_mem_obj(dimm_dict % page_size) + devices.append(mem_obj) + vmxml.set_devices(devices) + 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, 0, 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}) + + # Define guest + 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 memory device configs + + 1.invalid value: + exceed slot number, max address base, nonexistent guest node + nonexistent node mask, invalid pagesize, invalid address type + 2.memory setting: with numa + """ + + def setup_test(): + """ + Check host has at least 2 numa nodes. + """ + test.log.info("TEST_SETUP: Check the numa nodes") + numa_obj = numa_base.NumaTest(vm, params, test) + numa_obj.check_numa_nodes_availability() + + def run_test(): + """ + Define vm with dimm. + Start vm. + Hotplug dimm. + """ + test.log.info("TEST_STEP1: Define vm and check result") + source_pagesize = get_pagesize_value(params) + define_guest(test, params, source_pagesize) + + test.log.info("TEST_STEP2: Start guest ") + start_result = virsh.start(vm_name, ignore_status=True) + if start_vm_error: + # Start success for unexisted_node scenario and version>9.0 + if libvirt_version.version_compare(9, 0, 0) and \ + invalid_setting == "unexisted_node": + libvirt.check_exit_status(start_result) + else: + libvirt.check_result(start_result, start_vm_error) + + test.log.info("TEST_STEP3: Start guest without dimm devices") + original_xml.setup_attrs(**vm_attrs) + test.log.debug("Define vm by '%s' \n", original_xml) + original_xml.sync() + virsh.start(vm_name, debug=True, ignore_status=False) + + test.log.info("TEST_STEP4: Hotplug dimm memory device") + attach_error = params.get("start_vm_error", params.get("define_error")) + + mem_obj = get_mem_obj(dimm_dict % source_pagesize) + 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() + + 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() + dimm_dict = params.get("dimm_dict") + invalid_setting = params.get("invalid_setting") + vm_attrs = eval(params.get("vm_attrs")) + start_vm_error = params.get("start_vm_error") + + try: + setup_test() + run_test() + + finally: + teardown_test() 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 00000000000..69aa3f10aac --- /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 = eval(params.get("start_vm_error", "[]")) + elif not libvirt_version.version_compare(9, 9, 0) and \ + invalid_setting == "invalid_addr_type": + define_error = eval(params.get("define_error_8", "[]")) + else: + define_error = eval(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 not any(s in str(e) for s in define_error): + 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 not any(s in result for s in attach_error): + test.fail("Expected get error in '%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 = eval(params.get("start_vm_error", "[]")) + + # Get attach error + if invalid_setting == "max_addr": + attach_error = eval(params.get("attach_error", "[]")) + elif not libvirt_version.version_compare(9, 9, 0) and \ + invalid_setting == "invalid_addr_type": + attach_error = eval(params.get("attach_error_8", "[]")) + else: + attach_error = eval(params.get("start_vm_error", params.get("define_error", "[]"))) + + try: + setup_test() + run_test() + + finally: + teardown_test() diff --git a/libvirt/tests/src/memory/memory_devices/invalid_virtio_mem_config.py b/libvirt/tests/src/memory/memory_devices/invalid_virtio_mem_config.py new file mode 100644 index 00000000000..53b3ff076a4 --- /dev/null +++ b/libvirt/tests/src/memory/memory_devices/invalid_virtio_mem_config.py @@ -0,0 +1,148 @@ +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# SPDX-License-Identifier: GPL-2.0 + +# Author: Nannan Li +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +from avocado.utils import process + +from virttest import virsh + +from virttest.libvirt_xml import vm_xml +from virttest.libvirt_xml.devices import memory +from virttest.utils_test import libvirt + +from provider.numa import numa_base +from provider.memory import memory_base + + +def get_page_size(params): + """ + Get pagesize value + + :param params: Dictionary with the test parameters + """ + invalid_pagesize = params.get("invalid_pagesize") + pagesize_cmd = params.get("pagesize_cmd") + + if invalid_pagesize: + page_size = invalid_pagesize + else: + page_size = process.run(pagesize_cmd, ignore_status=True, + shell=True).stdout_text.strip() + return int(page_size) + + +def get_mem_obj(mem_dict): + """ + Get mem object. + + :param mem_dict: memory dict value + :return: mem_obj, memory object. + """ + mem_obj = memory.Memory() + mem_obj.setup_attrs(**eval(mem_dict)) + return mem_obj + + +def define_guest(test, params, page_size): + """ + Define guest with specific + + :param test: test object + :param params: Dictionary with the test parameters. + :params: page_size, the pagesize that used when define guest. + """ + vm_name = params.get("main_vm") + vm_attrs = eval(params.get("vm_attrs")) + mem_dict = params.get("mem_dict") + define_error = params.get("define_error") + + vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) + vmxml.setup_attrs(**vm_attrs) + + virtio_mem = get_mem_obj(mem_dict % page_size) + vmxml.devices = vmxml.devices.append(virtio_mem) + test.log.debug("Define vm with %s." % vmxml) + + # Define guest + 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 virtio-mem device configs + + 1.invalid value: + over committed requested memory, max address base, nonexistent guest node + nonexistent node mask, invalid pagesize, small block size, invalid block size + 2.memory setting: with numa + """ + + def setup_test(): + """ + Check host has at least 2 numa nodes. + """ + if with_numa: + test.log.info("TEST_SETUP: Check the numa nodes") + numa_obj = numa_base.NumaTest(vm, params, test) + numa_obj.check_numa_nodes_availability() + + def run_test(): + """ + Define vm with virtio-mem and start vm. + Define vm without virtio-mem and hotplug virtio-mem. + """ + test.log.info("TEST_STEP1: Define vm with virio-mem") + source_pagesize = get_page_size(params) + define_guest(test, params, source_pagesize) + + test.log.info("TEST_STEP2: Start guest") + start_result = virsh.start(vm_name, ignore_status=True, debug=True) + libvirt.check_result(start_result, start_vm_error) + + test.log.info("TEST_STEP3: Start guest without virtio-mem") + original_vmxml.setup_attrs(**vm_attrs) + test.log.debug("Define vm without virtio-mem by '%s' \n", original_vmxml) + original_vmxml.sync() + virsh.start(vm_name, debug=True) + + test.log.info("TEST_STEP4: Hotplug virtio-mem memory device") + mem_obj = get_mem_obj(mem_dict % source_pagesize) + 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() + + vm_name = params.get("main_vm") + with_numa = params.get("with_numa", "yes") == "yes" + vm = env.get_vm(vm_name) + original_vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + bkxml = original_vmxml.copy() + mem_dict = params.get("mem_dict") + vm_attrs = eval(params.get("vm_attrs")) + start_vm_error = params.get("start_vm_error") + attach_error = params.get("start_vm_error", params.get("define_error")) + + try: + memory_base.check_supported_version(params, test, vm) + setup_test() + run_test() + + finally: + teardown_test() diff --git a/libvirt/tests/src/memory/memory_devices/lifecycle_for_file_backed_nvdimm_memory.py b/libvirt/tests/src/memory/memory_devices/lifecycle_for_file_backed_nvdimm_memory.py new file mode 100644 index 00000000000..bae4536330b --- /dev/null +++ b/libvirt/tests/src/memory/memory_devices/lifecycle_for_file_backed_nvdimm_memory.py @@ -0,0 +1,329 @@ +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Copyright Redhat +# +# SPDX-License-Identifier: GPL-2.0 + +# Author: Nannan Li +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +import os +import re +import json + +from avocado.utils import process + +from virttest import virsh + +from virttest.libvirt_xml import vm_xml +from virttest.utils_libvirtd import Libvirtd +from virttest.utils_libvirt import libvirt_vmxml + +from provider.memory import memory_base + + +def delete_extra_attr(dict1, dict2): + """ + Delete extra different attributes between two dictionaries. + + :param dict1, first dictionary. + :param dict2, second dictionary. + """ + keys_to_remove = set(dict1.keys()).symmetric_difference(set(dict2.keys())) + for key in keys_to_remove: + if key in dict1: + del dict1[key] + if key in dict2: + del dict2[key] + return dict1, dict2 + + +def check_nvdimm_config(params, test, mem_index=0): + """ + Check nvdimm memory devices xml config. + + :param params: Optional new VM creation parameters. + :param test: test object. + :param mem_index: memory index in memory list, default 0. + """ + address_config = params.get("address_config") + expected_access = params.get("access") + addr_slot = [params.get("addr_slot"), params.get("addr_slot_attach")] + addr_base = [params.get("addr_base"), params.get("addr_base_attach")] + alias_name = eval(params.get("alias_name", "[]")) + target = [eval(params.get("target_attrs")[10:]), + eval(params.get("target_attach_attrs")[10:])] + source = [eval(params.get("source_attrs")[10:]), + eval(params.get("source_attach_attrs")[10:])] + + vmxml = vm_xml.VMXML.new_from_dumpxml(params.get("main_vm")) + actual_attrs = vmxml.devices.by_device_tag('memory')[mem_index].fetch_attrs() + test.log.debug("Get actual memory attrs: %s", actual_attrs) + delete_extra_attr(source[mem_index], actual_attrs['source']) + delete_extra_attr(target[mem_index], actual_attrs['target']) + + def _compare_values(expected, actual, check_item=''): + if expected != actual: + test.fail("Expect to get '%s' instead of '%s' " % (expected, actual)) + else: + test.log.debug("Check %s=%s PASS", check_item, actual) + + # check nvdimm memory device source and target config + _compare_values(source[mem_index], actual_attrs['source'], 'source attrs') + _compare_values(target[mem_index], actual_attrs['target'], 'target attrs') + + # check nvdimm memory device alias, access mode and address config + _compare_values(alias_name[mem_index], actual_attrs['alias']['name'], 'alias') + _compare_values(expected_access, actual_attrs['mem_access'], 'access mode') + if address_config != "addr_undefined": + _compare_values(addr_slot[mem_index], actual_attrs['address']['attrs']['slot'], 'addr slot') + _compare_values(addr_base[mem_index], actual_attrs['address']['attrs']['base'], 'addr base') + + +def check_nvdimm_device_content(test, params, session, expected_content, + existed=True): + """ + Check the nvdimm device content exist or not. + + :param test: test object. + :param params: Optional new VM creation parameters. + :param session: guest session. + :param expected_content: expected file content. + :param existed: bool type, True if expected_content existed. + """ + mount_file_1 = params.get("mount_file_1") + mount_file_2 = params.get("mount_file_2") + nvdimm_devices = params.get("nvdimm_devices").split(" ") + paths = eval(params.get("paths")) + + def _get_uuid(vm_session): + uuids = [] + for dev in nvdimm_devices: + uuid_out = vm_session.cmd_output('blkid %s' % dev) + uuid = re.findall(r' UUID="(\S+)"', uuid_out)[0] + if not uuid: + test.fail("Expect to get uuid in '%s'" % uuid_out) + uuids.append(uuid) + params.update({'uuids': uuids}) + + if existed: + # Check if mounted and remount + for index in range(len(paths)): + if not session.cmd_output("mount | grep '%s'" % paths[index]): + if not params.get("uuids"): + _get_uuid(session) + session.cmd_output('mount -o dax -U {} {}'.format( + params.get('uuids')[index], paths[index])) + + # Check file content + for item in [mount_file_1, mount_file_2]: + output = session.cmd_output('cat %s ' % item).strip() + if expected_content not in output: + test.fail('"%s" should be in output:"%s"' % (expected_content, output)) + test.log.debug("Check '%s' in '%s' is '%s' PASS", + expected_content, output, [mount_file_1, mount_file_2]) + else: + # Check blkid is not existed. + for dev in nvdimm_devices: + output = session.cmd_output('blkid %s ' % dev).strip() + if output: + test.fail("Expect to get no blkid, but got:'%s'" % output) + + +def check_alignment_value(params, test, check_cmd): + """ + Check guest alignment value by virsh qemu_monitor_command + + :param params: dictionary with the test parameters + :param test: test object + :param check_cmd: the cmd option of virsh qemu_monitor_command + """ + vm_name = params.get("main_vm") + expected_align = params.get("expected_align") + + result = virsh.qemu_monitor_command(vm_name, check_cmd, debug=True).stdout_text + actual_align = str(json.loads(result)['return']) + if actual_align != expected_align: + test.fail("Expected alignment value '%s' instead of '%s'" % ( + expected_align, actual_align)) + + +def do_domain_lifecyle(params, vm, test): + """ + Do lifecycle for guest. + + :param params: Dictionary with the test parameters + :param vm: vm object + :param test: test object + """ + virsh_dargs = {'debug': True, 'ignore_status': False} + target_config = params.get("target_config") + file_content = params.get("file_content") + + def _check_after_operation(): + session = vm.wait_for_login() + if target_config != "target_readonly": + check_nvdimm_device_content(test, params, session, file_content) + check_nvdimm_config(params, test) + check_nvdimm_config(params, test, mem_index=1) + session.close() + + virsh.suspend(vm.name, **virsh_dargs) + virsh.resume(vm.name, **virsh_dargs) + _check_after_operation() + + virsh.reboot(vm.name, **virsh_dargs) + _check_after_operation() + + save_file = params.get("save_file") + if os.path.exists(save_file): + os.remove(save_file) + virsh.save(vm.name, save_file, **virsh_dargs) + virsh.restore(save_file, **virsh_dargs) + _check_after_operation() + + virsh.managedsave(vm.name, **virsh_dargs) + vm.start() + _check_after_operation() + + virsh.reboot(vm.name, **virsh_dargs) + _check_after_operation() + + Libvirtd().restart() + _check_after_operation() + + +def run(test, params, env): + """ + Verify various configs of file backed nvdimm memory device take effect + during the life cycle of guest vm. + """ + + def setup_test(): + """ + Create file backend for nvdimm device + """ + test.log.info("Setup env.") + for path in [source_path, source_path_attach]: + process.run('truncate -s %s %s' % (nvdimm_file_size, path), + verbose=True, shell=True) + + def run_test(): + """ + 1. Define a vm with a nvdimm memory device and check the nvdimm configuration. + 2. Hotplug an nvdimm memory device and check the nvdimm configuration. + 3. Check the alignment with the virsh qemu-monitor-command. + 4. Create a file system on two nvdimm devices in the guest. + 6. Lifecycle checks for a guest with an attached device. + 7. Hotplug another nvdimm device. + """ + test.log.info("TEST_STEP1: Define vm with nvdimm memory device") + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + vmxml.setup_attrs(**vm_attrs) + mem_obj = libvirt_vmxml.create_vm_device_by_type('memory', nvdimm_dict) + vmxml.devices = vmxml.devices.append(mem_obj) + vmxml.sync() + + test.log.info("TEST_STEP2: Start guest") + vm.start() + vm.wait_for_login().close() + + test.log.info("TEST_STEP3: Check nvdimm memory device xml") + check_nvdimm_config(params, test) + + test.log.info("TEST_STEP4: Hot plug all memory device") + attach_mem = libvirt_vmxml.create_vm_device_by_type('memory', nvdimm_attach_dict) + virsh.attach_device(vm_name, attach_mem.xml, **virsh_dargs) + vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) + test.log.debug('Get xml after attaching memory is "%s"', vmxml) + + test.log.info("TEST_STEP5: Check nvdimm memory device xml") + check_nvdimm_config(params, test) + check_nvdimm_config(params, test, mem_index=1) + + test.log.info("TEST_STEP6:Check alignment by virsh.qemu-monitor-command") + check_alignment_value(params, test, check_alignment % alias_name[0]) + check_alignment_value(params, test, check_alignment % alias_name[1]) + + test.log.info("TEST_STEP7: Login guest and check nvdimm memory device") + session = vm.wait_for_login() + for dev in nvdimm_devices: + status, output = session.cmd_status_output("ls %s" % dev) + if status: + test.fail("Expect nvdimm device in guest, but got: %s" % output) + + test.log.info("TEST_STEP8: Create file system on two nvdimme device") + memory_base.create_file_within_nvdimm_disk( + test, session, test_device=nvdimm_devices[0], + mount_point=nvdimm_path, test_file=mount_file_1, + test_str=file_content, error_msg=error_msg) + memory_base.create_file_within_nvdimm_disk( + test, session, test_device=nvdimm_devices[1], + mount_point=nvdimm_path_attach, test_file=mount_file_2, + test_str=file_content, error_msg=error_msg) + session.close() + + test.log.info("TEST_STEP9: Do lifecycle") + do_domain_lifecyle(params, vm, test) + + if target_config != "target_readonly": + test.log.info("TEST_STEP10: Attach device again") + virsh.destroy(vm_name) + virsh.start(vm_name) + virsh.attach_device(vm_name, attach_mem.xml, **virsh_dargs) + + test.log.info("TEST_STEP11: Login the guest to check the file") + session = vm.wait_for_login() + check_nvdimm_device_content(test, params, session, file_content, + existed=content_existed) + session.close() + + def teardown_test(): + """ + Clean data. + """ + test.log.info("TEST_TEARDOWN: Clean up env.") + bkxml.sync() + if not vm.is_alive(): + vm.start() + session = vm.wait_for_login() + for file in [mount_file_1, mount_file_2]: + session.cmd("rm -f %s " % file) + session.close() + + bkxml.sync() + + for file in [source_path, source_path_attach]: + if os.path.exists(file): + os.remove(file) + + vm_name = params.get("main_vm") + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + bkxml = vmxml.copy() + vm = env.get_vm(vm_name) + + vm_attrs = eval(params.get("vm_attrs", "{}")) + nvdimm_dict = eval(params.get("nvdimm_dict")) + nvdimm_attach_dict = eval(params.get("nvdimm_attach_dict")) + error_msg = params.get("error_msg") + nvdimm_path = params.get("nvdimm_path") + nvdimm_path_attach = params.get("nvdimm_path_attach") + source_path = params.get("source_path") + source_path_attach = params.get("source_path_attach") + mount_file_1 = params.get("mount_file_1") + mount_file_2 = params.get("mount_file_2") + file_content = params.get("file_content") + nvdimm_file_size = params.get("nvdimm_file_size") + nvdimm_devices = params.get("nvdimm_devices").split(" ") + target_config = params.get("target_config",) + content_existed = bool(params.get("content_existed")) + check_alignment = params.get("check_alignment") + alias_name = eval(params.get("alias_name", "[]")) + virsh_dargs = {'debug': True, 'ignore_status': False} + + try: + setup_test() + run_test() + + finally: + teardown_test() diff --git a/libvirt/tests/src/memory/memory_devices/lifecycle_of_mixed_memory_devices.py b/libvirt/tests/src/memory/memory_devices/lifecycle_of_mixed_memory_devices.py index 0868e463e27..63a9d50b16b 100644 --- a/libvirt/tests/src/memory/memory_devices/lifecycle_of_mixed_memory_devices.py +++ b/libvirt/tests/src/memory/memory_devices/lifecycle_of_mixed_memory_devices.py @@ -8,6 +8,7 @@ # # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +import math import os import re @@ -127,6 +128,7 @@ def attach_all_memory_devices(vm, params, operate_flag): vm.start() for mem in mem_list: dev_dict = globals()[mem] + update_mem_device_pagesize(dev_dict) mem_dev = memory.Memory() mem_dev.setup_attrs(**dev_dict) virsh.attach_device(vm.name, mem_dev.xml, debug=True, @@ -146,6 +148,7 @@ def detach_all_memory_devices(vm_name, params, operate_flag): for index, value in enumerate(set_value): if value[get_index(params, operate_flag)] != "": dev_dict = globals()[value[-1]] + update_mem_device_pagesize(dev_dict) mem_xml = memory.Memory() mem_xml.setup_attrs(**dev_dict) virsh.detach_device(vm_name, mem_xml.xml, debug=True, @@ -260,6 +263,19 @@ def get_affected_mem(params, operation): return memory_affected, current_mem_affected +def update_mem_device_pagesize(mem_device_dict): + """ + update memory device page size and block size to default hugepage size. + + :param mem_device_dict: memory device dictionary. + """ + page_size = int(utils_memory.get_huge_page_size()) + if 'source' in mem_device_dict and 'pagesize' in mem_device_dict['source']: + mem_device_dict['source']['pagesize'] = page_size + if 'target' in mem_device_dict and 'block_size' in mem_device_dict['target']: + mem_device_dict['target']['block_size'] = page_size + + def update_vm_devices(vmxml, params): """ Update vm devices. @@ -276,6 +292,7 @@ def update_vm_devices(vmxml, params): mem_list.append(value[-1]) for index, mem in enumerate(mem_list): dev_dict = globals()[mem] + update_mem_device_pagesize(dev_dict) new_mem = memory.Memory() new_mem.setup_attrs(**dev_dict) devices.append(new_mem) @@ -293,10 +310,12 @@ def setup_test(): """ test.log.info("TEST_SETUP: Set hugepage and guest boot ") process.run(truncate_cmd, ignore_status=False, shell=True) - utils_memory.set_num_huge_pages(int(nr_hugepages)) + nr_hugepages = math.ceil( + int(total_hugepage_size) / utils_memory.get_huge_page_size()) + utils_memory.set_num_huge_pages(nr_hugepages) result = process.run("cat %s" % kernel_hp_file, ignore_status=True, verbose=False).stdout_text.strip() - if nr_hugepages != result: + if str(nr_hugepages) != result: test.fail("Hugepage set failed, should be %s instead of %s" % ( nr_hugepages, result)) @@ -408,7 +427,7 @@ def teardown_test(): kernel_params_remove = params.get("kernel_params_remove") kernel_params_add = params.get("kernel_params_add") truncate_cmd = params.get("truncate_cmd") - nr_hugepages = params.get("nr_hugepages") + total_hugepage_size = params.get("total_hugepage_size") kernel_hp_file = params.get("kernel_hp_file") nvdimm_path_1 = params.get("nvdimm_path_1") nvdimm_path_2 = params.get("nvdimm_path_2") diff --git a/libvirt/tests/src/memory/memory_devices/nvdimm_memory_turn_to_dram.py b/libvirt/tests/src/memory/memory_devices/nvdimm_memory_turn_to_dram.py new file mode 100644 index 00000000000..1523da35bd0 --- /dev/null +++ b/libvirt/tests/src/memory/memory_devices/nvdimm_memory_turn_to_dram.py @@ -0,0 +1,127 @@ +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Copyright Redhat +# +# SPDX-License-Identifier: GPL-2.0 +# Author: Nannan Li +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +import re + +from avocado.utils import distro +from avocado.utils import process + +from virttest import virsh +from virttest import utils_misc +from virttest import utils_package +from virttest.libvirt_xml import vm_xml +from virttest.utils_test import libvirt +from virttest.utils_libvirt import libvirt_bios + +from provider.memory import memory_base + + +def run(test, params, env): + """ + Turned nvdimm to the regular DRAM. + """ + def setup_test(): + """ + Create nvdimm file on the host. + """ + process.run(truncate_cmd) + + def run_test(): + """ + Turned nvdimm to the regular DRAM would increase total memory + """ + test.log.info("TEST_STEP1: Define vm with nvdimm memory") + memory_base.define_guest_with_memory_device(params, nvdimm_dict, vm_attrs) + + test.log.info("TEST_STEP2: Start guest and Check nvdimm passed in the qemu command line") + vm.start() + session = vm.wait_for_login() + libvirt.check_qemu_cmd_line(eval(expected_qemu_cmdline)) + + test.log.info("TEST_STEP3:Check the guest support NVDIMM") + libvirt_bios.check_boot_config(session, test, check_list) + + test.log.info("TEST_STEP4:Login to the guest, check mem size and nvdimm mode") + vm_mem_before = utils_misc.get_mem_info(session) + + test.log.debug("VM's memory before updating nvdimm to dram: %s", vm_mem_before) + + if not utils_package.package_install('ndctl', session=session): + test.fail('Cannot install ndctl to vm') + utils_misc.cmd_status_output(create_namespace, session=session) + utils_misc.cmd_status_output(check_dev, session=session) + + ndctl_list = eval(utils_misc.cmd_status_output(list_nvdimm_namespace, session=session)[1]) + if ndctl_list[0]['mode'] != devdax_mode: + test.fail("Expected mode devdax, but %s" % ndctl_list["mode"]) + test.log.debug("Check mode: %s PASS", devdax_mode) + + test.log.info("TEST_STEP5:Turned nvdimm to the regular DRAM, and hot-added memory matches the expectation") + if not utils_package.package_install('daxctl', session=session): + test.fail('Cannot install daxctl to vm') + if distro.detect().name == 'rhel' and int(distro.detect().version) >= 9: + utils_misc.cmd_status_output(persistence_config, session=session) + utils_misc.cmd_status_output(add_kmem, session=session) + + utils_misc.cmd_status_output(create_namespace, session=session) + output = utils_misc.cmd_status_output(update_to_dram, session=session)[1] + if not re.findall(r'"mode":"%s"' % dram_mode, output): + test.fail("Expected mode is dram") + test.log.debug("Check new mode: %s PASS") + + vm_mem_after = utils_misc.get_mem_info(session) + test.log.debug("New memory total value is:%s", vm_mem_after) + if int(vm_mem_after) <= int(vm_mem_before): + test.fail("Memory should increase after updating nvdimm to dram") + test.log.debug("Check guest memory increase successfully") + + test.log.info("TEST_STEP6:Used memhog for memory operation") + utils_misc.cmd_status_output("memhog -r%s 500M" % repeat_times, session=session) + session.close() + + test.log.info("TEST_STEP7:Reboot and check guest status") + virsh.reboot(vm_name, debug=True) + if vm.state() != "running": + test.fail("VM %s should be running, not %s" % (vm.name, vm.state())) + test.log.debug("Check guest status is running") + + def teardown_test(): + """ + Clean data. + """ + test.log.info("TEST_TEARDOWN: Clean up env.") + bkxml.sync() + process.run("rm -rf %s" % nvdimm_path) + + vm_name = params.get("main_vm") + original_xml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + bkxml = original_xml.copy() + vm = env.get_vm(vm_name) + nvdimm_path = params.get("nvdimm_path") + truncate_cmd = params.get("truncate_cmd") + expected_qemu_cmdline = params.get("expected_qemu_cmdline") + nvdimm_dict = eval(params.get("nvdimm_dict")) + vm_attrs = eval(params.get("vm_attrs", "{}")) + repeat_times = params.get("repeat_times") + + devdax_mode = params.get("devdax_mode") + dram_mode = params.get("dram_mode") + create_namespace = params.get("create_namespace") + check_dev = params.get("check_dev") + list_nvdimm_namespace = params.get("list_nvdimm_namespace") + add_kmem = params.get("add_kmem") + update_to_dram = params.get("update_to_dram") + persistence_config = params.get("persistence_config") + check_list = eval(params.get("check_list", "{}")) + + try: + setup_test() + run_test() + + finally: + teardown_test() diff --git a/libvirt/tests/src/memory/memory_devices/virtio_mem_access_and_discard.py b/libvirt/tests/src/memory/memory_devices/virtio_mem_access_and_discard.py new file mode 100644 index 00000000000..7980c11fe59 --- /dev/null +++ b/libvirt/tests/src/memory/memory_devices/virtio_mem_access_and_discard.py @@ -0,0 +1,204 @@ +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Copyright Redhat +# +# SPDX-License-Identifier: GPL-2.0 + +# Author: Nannan Li +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +import re +import json + +from avocado.utils import process + +from virttest import virsh + +from virttest.libvirt_xml.devices import memory +from virttest.libvirt_xml import vm_xml +from virttest.utils_libvirtd import Libvirtd + +from provider.memory import memory_base + + +def get_vm_attrs(test, params): + """ + Get vm attrs. + + :param test: test object + :param params: dictionary with the test parameters + :return vm_attrs: get updated vm attrs dict. + """ + vm_attrs = eval(params.get("vm_attrs", "{}")) + source_attr = params.get("source_attr", "") + discard_attr = params.get("discard_attr", "") + access_attr = params.get("access_attr", "") + + mb_value = "" + for item in [source_attr, discard_attr, access_attr]: + if item != "": + mb_value += item + "," + mb_attrs = eval("{'mb':{%s}}" % mb_value[:-1]) + + vm_attrs.update(mb_attrs) + test.log.debug("Get current vm attrs is :%s", vm_attrs) + + return vm_attrs + + +def get_virtio_mem(test, params): + """ + Get basic different virtio-mem memory devices. + + :param test: test object. + :param params: dictionary with the test parameters. + :return mem_list: virtio-mem attr dict list. + """ + mem_conf_list = eval(params.get("mem_conf_list")) + conf_map = {0: 'mem_access', 1: 'mem_discard', 2: 'node'} + mem_list = [] + for item in mem_conf_list: + single_mem = eval(params.get("mem_basic")) + target = single_mem['target'] + for k, v in conf_map.items(): + if item[k] is not None: + if v == "node": + target.update({v: item[k]}) + else: + single_mem.update({v: item[k]}) + mem_list.append(single_mem) + + test.log.debug("Get all virtio-mem list:'%s'", mem_list) + return mem_list + + +def check_access_and_discard(test, params, vm, + expected_share, expected_discard): + """ + Check access and discard setting. + + :param test: test object. + :param params: dictionary with the test parameters. + :param vm: vm object. + :param expected_share: expected access shared value list. + :param expected_discard: expected discard value list. + """ + virtio_mem_num = len(eval(params.get("mem_conf_list"))) + check_discard = params.get("check_discard") + discard_error_msg = params.get("discard_error_msg") + mem_name_list = [] + + # Check access share setting + ret = virsh.qemu_monitor_command(vm.name, "info memdev", "--hmp", + debug=True).stdout_text.replace("\r\n", "") + for index in range(virtio_mem_num): + mem_name = "memvirtiomem%d" % index + pattern = "memory backend: %s.*share: %s " % (mem_name, expected_share[index]) + if not re.search(pattern, ret): + test.fail("Expect '%s' exist, but not found" % pattern) + else: + test.log.debug("Check access shared value is '%s': PASS", pattern) + mem_name_list.append(mem_name) + + # Check discard setting + for index, mem_name in enumerate(mem_name_list): + res = virsh.qemu_monitor_command( + vm.name, check_discard % mem_name, debug=True).stdout_text + + if 'return' in json.loads(res): + actual_discard = str(json.loads(res)['return']) + if actual_discard != expected_discard[index]: + test.fail("Expect discard is '%s', but got '%s'" % ( + expected_discard[index], actual_discard)) + else: + test.log.debug("Check discard value is '%s' PASS", actual_discard) + else: + actual_error = json.loads(res)['error']['desc'] + if not re.search(discard_error_msg, actual_error): + test.fail("Expected to get '%s' in '%s'" % (discard_error_msg, + actual_error)) + else: + test.log.debug("Check '%s' PASS ", actual_error) + + +def run(test, params, env): + """ + Verify virtio-mem memory device works with access and discard settings. + """ + def run_test(): + """ + 1.Define vm with virtio-mem device + 2.Check the virtio-mem memory device access and discard setting + 3.Define vm without virtio-mem device and restart service, and hotplug + virtio-mem device. + """ + test.log.info("TEST_STEP1: Define vm with virtio-mem") + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + vm_attrs = get_vm_attrs(test, params) + vmxml.setup_attrs(**vm_attrs) + + virtio_mems = get_virtio_mem(test, params) + for mem in virtio_mems: + virtio_mem = memory.Memory() + virtio_mem.setup_attrs(**mem) + vmxml.devices = vmxml.devices.append(virtio_mem) + vmxml.sync() + + test.log.info("TEST_STEP2: Start guest") + vm.start() + + test.log.info("TEST_STEP3,4: Check virtio-mem access and discard") + check_access_and_discard(test, params, vm, expected_share, + expected_discard) + + test.log.info("TEST_STEP5: Destroy vm") + vm.destroy() + + test.log.info("TEST_STEP6: Check the host path for memory file backing") + res = process.run(check_path % vm_name, shell=True, ignore_status=True).stderr_text + if not re.search(path_error, res): + test.fail("Expected '%s', but got '%s'" % (path_error, res)) + + test.log.info("TEST_STEP7: Define guest without virtio-mem memory") + bkxml.setup_attrs(**vm_attrs) + bkxml.sync() + vm.start() + + test.log.info("TEST_STEP8: Restart service") + Libvirtd().restart() + + test.log.info("TEST_STEP9: Hot plug all memory device") + for mem in virtio_mems: + virtio_mem = memory.Memory() + virtio_mem.setup_attrs(**mem) + virsh.attach_device(vm_name, virtio_mem.xml, + debug=True, ignore_status=False) + + test.log.info("TEST_STEP10: Check discard and access again.") + check_access_and_discard(test, params, vm, + expected_share, expected_discard) + + def teardown_test(): + """ + Clean data. + """ + test.log.info("TEST_TEARDOWN: Clean up env.") + orig_vmxml.sync() + + vm_name = params.get("main_vm") + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + bkxml = vmxml.copy() + orig_vmxml = vmxml.copy() + vm = env.get_vm(vm_name) + + expected_share = eval(params.get("expected_share")) + expected_discard = eval(params.get("expected_discard")) + check_path = params.get("check_path") + path_error = params.get("path_error", "No such file or directory") + + try: + memory_base.check_supported_version(params, test, vm) + run_test() + + finally: + teardown_test() diff --git a/libvirt/tests/src/memory/memory_devices/virtio_mem_auto_placement.py b/libvirt/tests/src/memory/memory_devices/virtio_mem_auto_placement.py new file mode 100644 index 00000000000..f84970894e2 --- /dev/null +++ b/libvirt/tests/src/memory/memory_devices/virtio_mem_auto_placement.py @@ -0,0 +1,94 @@ +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Copyright Redhat +# +# SPDX-License-Identifier: GPL-2.0 + +# Author: Nannan Li +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +import time + +from virttest import virsh + +from virttest.libvirt_xml import vm_xml +from virttest.libvirt_xml.devices import memory +from virttest.utils_libvirt import libvirt_vmxml + +from provider.memory import memory_base +from provider.numa import numa_base + + +def run(test, params, env): + """ + 1.Define guest with virtio-mem devices. + 2.Attach virtio-mem and check mem value + """ + + def setup_test(): + """ + Check available numa nodes num. + """ + memory_base.check_supported_version(params, test, vm) + test.log.info("TEST_SETUP: Check available numa nodes num") + numa_obj = numa_base.NumaTest(vm, params, test) + numa_obj.check_numa_nodes_availability() + + def run_test(): + """ + Define guest, check xml, check memory + """ + test.log.info("TEST_SETUP1: Define guest") + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + vmxml.setup_attrs(**vm_attrs) + virsh.define(vmxml.xml, debug=True, ignore_status=False) + + libvirt_vmxml.modify_vm_device( + vm_xml.VMXML.new_from_inactive_dumpxml(vm_name), 'memory', + virtio_mem_dict) + + test.log.info("TEST_STEP2: Start vm") + vm.start() + vm.wait_for_login().close() + + test.log.info("TEST_SETUP3: Hotplug a virtio-mem device") + mem_obj = memory.Memory() + mem_obj.setup_attrs(**virtio_mem_dict) + virsh.attach_device(vm.name, mem_obj.xml, debug=True, + wait_for_event=True, ignore_status=False) + + test.log.info("TEST_SETUP4: Check the virtio-mem device memory") + time.sleep(3) + vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) + test.log.debug("The new xml is:\n%s", vmxml) + + mem_list = vmxml.devices.by_device_tag('memory') + for mem in mem_list: + actual_size = mem.fetch_attrs()['target']['current_size'] + if str(actual_size) != requested_size: + test.fail("Expected to get requested size '%s', " + "but got '%s'" % (requested_size, actual_size)) + else: + test.log.debug('Check requested size "%s" correctly' % requested_size) + + def teardown_test(): + """ + Clean data. + """ + test.log.info("TEST_TEARDOWN: Clean up env.") + bkxml.sync() + + vm_name = params.get("main_vm") + vm = env.get_vm(vm_name) + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + bkxml = vmxml.copy() + vm_attrs = eval(params.get('vm_attrs', '{}')) + virtio_mem_dict = eval(params.get('virtio_mem_dict', '{}')) + requested_size = params.get("requested_size") + + try: + setup_test() + run_test() + + finally: + teardown_test() diff --git a/libvirt/tests/src/memory/memory_devices/virtio_mem_coldplug_and_unplug.py b/libvirt/tests/src/memory/memory_devices/virtio_mem_coldplug_and_unplug.py new file mode 100644 index 00000000000..4e6c4cba762 --- /dev/null +++ b/libvirt/tests/src/memory/memory_devices/virtio_mem_coldplug_and_unplug.py @@ -0,0 +1,193 @@ +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Copyright Redhat +# +# SPDX-License-Identifier: GPL-2.0 + +# Author: Nannan Li +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +from avocado.utils import memory + +from virttest import virsh +from virttest.libvirt_xml import vm_xml +from virttest.utils_test import libvirt +from virttest.utils_libvirt import libvirt_vmxml + +from provider.memory import memory_base + + +def adjust_virtio_params(params): + """ + Adjust all virtio related size and xpath. + + :param params: dict wrapped with params. + """ + plug_target_size = int(params.get('plug_target_size', 0)) + plug_request_size = int(params.get('plug_request_size', 0)) + target_size, request_size = int(params.get('target_size')), int(params.get('request_size')) + plug_size_unit = params.get('plug_size_unit') + plug_request_unit = params.get('plug_request_unit') + size_unit, request_unit = params.get('size_unit'), params.get('request_unit') + + def _convert_size(curr_size, curr_unit, var_str): + if curr_unit != "KiB": + new_size = memory_base.convert_data_size(str(curr_size) + curr_unit) + params.update({var_str: int(new_size)}) + + _convert_size(target_size, size_unit, 'target_size') + _convert_size(request_size, request_unit, 'request_size') + _convert_size(plug_target_size, plug_size_unit, 'plug_target_size') + _convert_size(plug_request_size, plug_request_unit, 'plug_request_size') + + +def adjust_virtio_xpath(params): + """ + Adjust all expected virtio xpath in different scenarios. + + :param params: dict wrapped with params. + :return virtio_xpath, unplug_xpath, plug_xpath, expected defined virtio xpath, + expected plugged virtio xpath, expected unplugged virtio xpath. + """ + default_hugepage_size = memory.get_huge_page_size() + adjust_virtio_params(params) + + plug_target_size = params.get('plug_target_size') + plug_request_size = params.get('plug_request_size') + target_size, request_size = params.get('target_size'), params.get('request_size') + case = params.get("case") + virtio_xpath = params.get("virtio_xpath") + unplug_xpath = params.get("unplug_xpath") + plug_xpath = params.get("plug_xpath") + + if case == "source_and_mib": + virtio_xpath = virtio_xpath % (target_size, default_hugepage_size, + request_size) + unplug_xpath = eval(virtio_xpath) + plug_xpath = eval(plug_xpath % (plug_target_size, default_hugepage_size, + plug_request_size)) + elif case == "plug_exceeded_max_mem": + virtio_xpath = virtio_xpath % default_hugepage_size + plug_xpath = eval(plug_xpath % (plug_target_size, default_hugepage_size, + plug_request_size)) + else: + virtio_xpath = virtio_xpath % default_hugepage_size + if unplug_xpath: + unplug_xpath = eval(unplug_xpath % default_hugepage_size) + if plug_xpath: + plug_xpath = eval(plug_xpath % default_hugepage_size) + return eval(virtio_xpath), unplug_xpath, plug_xpath + + +def check_xpath_unexist(test, vmxml, not_exist_path): + """ + Check specific xpath info not exist in guest xml. + + :param test: test object. + :param vmxml: current guest xml. + :param not_exist_path: The xpath that should not exist in guest. + """ + if libvirt_vmxml.check_guest_xml_by_xpaths( + vmxml, not_exist_path, ignore_status=True): + test.fail("Expect to not get %s in guest" % not_exist_path) + + +def run(test, params, env): + """ + Verify virtio-mem memory device cold-plug and cold-unplug + with different configs + """ + def setup_test(): + """ + Check Versions. + """ + test.log.info("TEST_SETUP: Check related version") + memory_base.check_supported_version(params, test, vm) + + def run_test(): + """ + Define guest, then cold unplug and cold plug virtio mem device. + """ + test.log.info("TEST_SETUP1: Define guest") + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + vmxml.setup_attrs(**vm_attrs) + vmxml.devices = vmxml.devices.append( + libvirt_vmxml.create_vm_device_by_type('memory', virtio_dict)) + virsh.define(vmxml.xml, debug=True, ignore_status=False) + + test.log.info("TEST_STEP2: Check guest xml") + virtio_xpath, unplug_xpath, plug_xpath = adjust_virtio_xpath(params) + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + libvirt_vmxml.check_guest_xml_by_xpaths(vmxml, numa_xpath+virtio_xpath) + + if unplug_dict: + test.log.info("TEST_SETUP3,4:Cold unplug a virtio-mem and check xml") + cold_unplug_obj = libvirt_vmxml.create_vm_device_by_type( + 'memory', unplug_dict) + ret = virsh.detach_device(vm.name, cold_unplug_obj.xml, + flagstr=plug_option, debug=True) + + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + if unplug_error: + libvirt.check_result(ret, unplug_error) + libvirt_vmxml.check_guest_xml_by_xpaths(vmxml, numa_xpath+virtio_xpath) + else: + libvirt.check_exit_status(ret) + check_xpath_unexist(test, vmxml, unplug_xpath) + + if plug_dict: + test.log.info("TEST_SETUP5-7: Cold plug virtio-mem and check xml") + cold_plug_obj = libvirt_vmxml.create_vm_device_by_type( + 'memory', plug_dict) + ret = virsh.attach_device(vm.name, cold_plug_obj.xml, + flagstr=plug_option, debug=True) + if case in ["with_addr", "source_and_mib", "duplicate_addr"]: + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + if plug_error: + libvirt.check_result(ret, plug_error, any_error=True) + libvirt_vmxml.check_guest_xml_by_xpaths(vmxml, numa_xpath+virtio_xpath) + if case != "duplicate_addr": + check_xpath_unexist(test, vmxml, plug_xpath) + else: + libvirt.check_exit_status(ret) + libvirt_vmxml.check_guest_xml_by_xpaths(vmxml, numa_xpath+plug_xpath) + elif case in ["plug_exceeded_max_mem"]: + for plug_time in range(0, 3): + ret = virsh.attach_device(vm.name, cold_plug_obj.xml, + flagstr=plug_option, debug=True) + if plug_time == 2: + libvirt.check_result(ret, plug_error) + + def teardown_test(): + """ + Clean data. + """ + test.log.info("TEST_TEARDOWN: Clean up env.") + bkxml.sync() + + vm_name = params.get("main_vm") + vm = env.get_vm(vm_name) + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + bkxml = vmxml.copy() + case = params.get("case") + default_hugepage_size = memory.get_huge_page_size() + + plug_option = params.get("plug_option") + vm_attrs = eval(params.get('vm_attrs', '{}')) + numa_xpath = eval(params.get("numa_xpath", "")) + unplug_error = params.get("unplug_error") + plug_error = params.get("plug_error") + virtio_dict = eval(params.get('virtio_dict', '{}') % default_hugepage_size) + unplug_dict = params.get('unplug_dict') + plug_dict = params.get('plug_dict') + + unplug_dict = eval(unplug_dict % default_hugepage_size) if unplug_dict else '' + plug_dict = eval(plug_dict % default_hugepage_size) if plug_dict else '' + + try: + setup_test() + run_test() + + finally: + teardown_test() diff --git a/libvirt/tests/src/memory/memory_devices/virtio_mem_device_lifecycle.py b/libvirt/tests/src/memory/memory_devices/virtio_mem_device_lifecycle.py new file mode 100644 index 00000000000..f794354e22a --- /dev/null +++ b/libvirt/tests/src/memory/memory_devices/virtio_mem_device_lifecycle.py @@ -0,0 +1,224 @@ +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Copyright Red Hat +# +# SPDX-License-Identifier: GPL-2.0 +# +# Author: Liang Cong +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +import os + +from virttest.utils_libvirtd import Libvirtd +from virttest import virsh + +from virttest.libvirt_xml import vm_xml +from virttest.libvirt_xml.devices import memory +from virttest import test_setup +from virttest import utils_misc +from virttest.utils_libvirt import libvirt_memory +from virttest.utils_libvirt import libvirt_vmxml + +from provider.memory import memory_base +from provider.numa import numa_base + + +def run(test, params, env): + """ + Verify various config of dimm memory device settings take effect + during the life cycle of guest vm. + """ + + def clean_empty_memory_device_config(mem_device_dict): + """ + Clean empty config of the memory device + + :param mem_device_dict (dict): memory device config dictionary + """ + for key in list(mem_device_dict.keys()): + if not mem_device_dict[key]: + del mem_device_dict[key] + + def check_virtio_mem_device_xml(xpath_dict): + """ + Check the virtio-mem memory device config by xpath + + :param xpath_dict (dict): xpath dict to check if the memory config is correct, + like {"alias_name":[xpath1, xpath2]},...} + """ + vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) + test.log.debug("Current guest config xml is:\n%s", vmxml) + memory_devices = vmxml.devices.by_device_tag('memory') + target_memory_num = 0 + for alias_name, xpath_list in xpath_dict.items(): + for memory_device in memory_devices: + if alias_name == memory_device.alias.get('name'): + target_memory_num = target_memory_num + 1 + for xpath in xpath_list: + libvirt_vmxml.check_guest_xml_by_xpaths(memory_device, xpath) + if target_memory_num != len(xpath_dict): + test.fail('Expected %d virtio-mem mem devices with required alias name, but found %d' + % (len(xpath_dict), target_memory_num)) + + def check_current_mem_size(alias_name, expect_current_size): + """ + Check if virtio-mem memory with alias_name has expected current memory size + + :param alias_name (str): alias name of the virtio-mem device + :param expect_current_size (int): expected current memory size of the virtio-mem device + + :return: bool, true if virtio-mem memory with alias_name has expected current memory size + """ + vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) + memory_devices = vmxml.devices.by_device_tag('memory') + for memory_device in memory_devices: + if alias_name == memory_device.alias.get('name') and memory_device.target.current_size == expect_current_size: + return True + return False + + def check_case_availability(): + """ + Check whether the case is available + """ + memory_base.check_mem_page_sizes(test, page_size, default_hp_size) + memory_base.check_supported_version(params, test, vm) + + def setup_test(): + """ + Setup for the case: + 1. Get host available numa nodes + 2. Change parameters according to available numa nodes + 3. Allocate huge page memory for target host node if needs + """ + if nodeset_num: + numatest_obj = numa_base.NumaTest(vm, params, test) + if 1 == nodeset_num: + min_memory_size = init_size + plug_size + elif 2 == nodeset_num: + min_memory_size = init_size if init_size >= plug_size else plug_size + numatest_obj.check_numa_nodes_availability(nodeset_num, min_memory_size) + numa_list = numatest_obj.get_available_numa_nodes(min_memory_size)[:nodeset_num] + nodeset_str = numa_base.convert_to_string_with_dash( + ','.join([str(node) for node in numa_list])) + source_dict = params.get("source_dict") + source_xpath = params.get("source_xpath") + source_dict = eval(source_dict % nodeset_str) + source_xpath = eval(source_xpath % nodeset_str) + init_mem_device_dict["source"] = source_dict + plug_mem_device_dict["source"] = source_dict + init_xpath_list[0] = source_xpath + plug_xpath_list[0] = source_xpath + test.log.debug("Selected numa nodeset is:%s", nodeset_str) + + if use_huge_page: + params["target_nodes"] = " ".join([str(node) for node in numa_list]) + params["target_hugepages"] = (init_size + plug_size) / default_hp_size + hpc = test_setup.HugePageConfig(params) + hpc.setup() + + if vm.is_alive(): + vm.destroy() + + def run_test(): + """ + Test steps + """ + test.log.info("TEST_STEP1: Define the guest") + clean_empty_memory_device_config(init_mem_device_dict) + memory_base.define_guest_with_memory_device(params, init_mem_device_dict, vm_attrs) + + test.log.info("TEST_STEP2: Start the guest") + vm.start() + vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) + test.log.debug("Guest config xml after start is:\n%s", vmxml) + + test.log.info("TEST_STEP3: Wait for the guest os is boot up," + "Check virtio-mem memory device config by virsh dumpxml") + vm.wait_for_login().close() + check_virtio_mem_device_xml({init_alias_name: init_xpath_list}) + + test.log.info("TEST_STEP4: Hotplug a virtio-mem memory device") + clean_empty_memory_device_config(plug_mem_device_dict) + mem_device = memory.Memory() + mem_device.setup_attrs(**plug_mem_device_dict) + virsh.attach_device(vm_name, mem_device.xml, debug=True, ignore_status=False) + if not utils_misc.wait_for( + lambda: check_current_mem_size(plug_alias_name, plug_requested), 20): + test.fail('Hot-plugged virtio-mem mem devices with alias name %s should have ' + 'current memory size %d' % (plug_alias_name, plug_requested)) + + test.log.info("TEST_STEP5: Consume the guest memory") + session = vm.wait_for_login() + libvirt_memory.consume_vm_freememory(session) + + test.log.info( + "TEST_STEP6: Check virtio-mem memory device config by virsh dumpxml") + check_virtio_mem_device_xml({init_alias_name: init_xpath_list, plug_alias_name: plug_xpath_list}) + + test.log.info("TEST_STEP7: Life cycle test") + virsh.suspend(vm_name, ignore_status=False, debug=True) + virsh.resume(vm_name, ignore_status=False, debug=True) + check_virtio_mem_device_xml({init_alias_name: init_xpath_list, plug_alias_name: plug_xpath_list}) + + virsh.save(vm_name, state_file, ignore_status=False, debug=True) + virsh.restore(state_file, ignore_status=False, debug=True) + check_virtio_mem_device_xml({init_alias_name: init_xpath_list, plug_alias_name: plug_xpath_list}) + + virsh.managedsave(vm_name, ignore_status=False, debug=True) + vm.start() + check_virtio_mem_device_xml({init_alias_name: init_xpath_list, plug_alias_name: plug_xpath_list}) + + vm.reboot() + vm.wait_for_login().close() + check_virtio_mem_device_xml({init_alias_name: init_xpath_list, plug_alias_name: plug_xpath_list}) + + libvirt_daemon = Libvirtd() + if not libvirt_daemon.restart(reset_failed=False): + test.fail('libvirt deamon restarts failed or is not working properly') + check_virtio_mem_device_xml({init_alias_name: init_xpath_list, plug_alias_name: plug_xpath_list}) + + def teardown_test(): + """ + 1. Restore guest config xml + 2. Clean huge page memory + 3. Remove state file + """ + bkxml.sync() + if use_huge_page: + hpc = test_setup.HugePageConfig(params) + hpc.cleanup() + if os.path.exists(state_file): + os.remove(state_file) + + vm_name = params.get("main_vm") + vm = env.get_vm(vm_name) + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + bkxml = vmxml.copy() + + vm_attrs = eval(params.get("vm_attrs", "{}")) + init_mem_device_dict = eval( + params.get("init_mem_device_dict", "{}")) + plug_mem_device_dict = eval( + params.get("plug_mem_device_dict", "{}")) + init_xpath_list = eval(params.get("init_xpath_list")) + plug_xpath_list = eval(params.get("plug_xpath_list")) + init_alias_name = params.get("init_alias_name") + plug_alias_name = params.get("plug_alias_name") + plug_requested = int(params.get("plug_requested")) + page_size = int(params.get("page_size")) + default_hp_size = int(params.get("default_hp_size")) + init_size = int(params.get("init_size")) + plug_size = int(params.get("plug_size")) + nodeset_num = int(params.get("nodeset_num", "0")) + use_huge_page = "yes" == params.get("use_huge_page") + state_file = params.get('state_file', '/tmp/%s.save') % vm_name + + try: + check_case_availability() + setup_test() + run_test() + + finally: + teardown_test() diff --git a/libvirt/tests/src/memory/memory_devices/virtio_mem_dynamic_slots.py b/libvirt/tests/src/memory/memory_devices/virtio_mem_dynamic_slots.py new file mode 100644 index 00000000000..51f83b7b165 --- /dev/null +++ b/libvirt/tests/src/memory/memory_devices/virtio_mem_dynamic_slots.py @@ -0,0 +1,143 @@ +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Copyright Redhat +# +# SPDX-License-Identifier: GPL-2.0 + +# Author: Nannan Li +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +import re + +from avocado.utils import memory + +from virttest import utils_misc +from virttest import virsh +from virttest import test_setup +from virttest.libvirt_xml import vm_xml +from virttest.utils_libvirt import libvirt_vmxml + +from provider.memory import memory_base + + +def update_vm_attrs(test, params): + """ + Update vm attrs. + + :param test: Virt test object. + :param params: Dict with test params. + :return vm_attrs: expected vm attrs dict. + """ + source_attr = params.get('source_attr') + hugepages_attr = params.get('hugepages_attr') + vm_attrs = eval(params.get("vm_attrs")) + + mb_value = "" + for item in [source_attr, hugepages_attr]: + if item is not None: + mb_value = mb_value + item + "," + mb = eval("{'mb':{%s}}" % mb_value[:-1]) + vm_attrs.update(mb) + test.log.debug("Get current vm attrs is :%s", vm_attrs) + + return vm_attrs + + +def run(test, params, env): + """ + Verify dynamic memory slots attribute works with virtio-mem memory device + """ + def check_current_mem_size(mem_index, expect_current_size): + """ + Check if virtio-mem memory of mem_index has expected current memory size + + :param mem_index (int): index of the virtio-mem device + :param expect_current_size (int): expected current memory size of the virtio-mem device + + :return (bool): true virtio-mem memory of index has expected current memory size + """ + vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) + memory_devices = vmxml.devices.by_device_tag('memory') + return memory_devices[mem_index].target.current_size == expect_current_size + + def setup_test(): + """ + Allocate huge page memory + """ + if memory_backing == "hugepages_mb": + test.log.info("TEST_SETUP: Allocate huge page memory") + params["target_hugepages"] = allocate_size/default_hugepage_size + hp_cfg = test_setup.HugePageConfig(params) + params["hpc_cfg"] = hp_cfg + hp_cfg.setup() + + def run_test(): + """ + Verify dynamic memory slots attribute works with virtio-mem memory device + """ + test.log.info("TEST_STEP1: Define guest with virtio memory") + vm_attrs = update_vm_attrs(test, params) + memory_base.define_guest_with_memory_device( + params, virtio_mem_dict, vm_attrs) + + test.log.info("TEST_STEP2: Start vm") + vm.start() + vm.wait_for_login().close() + test.log.debug("Get xml after starting vm:%s", + vm_xml.VMXML.new_from_inactive_dumpxml(vm_name)) + + test.log.info("TEST_SETUP3: Hotplug a virtio-mem device") + mem_obj = libvirt_vmxml.create_vm_device_by_type("memory", virtio_mem_dict) + virsh.attach_device( + vm.name, mem_obj.xml, wait_for_event=True, **virsh_dargs) + if not utils_misc.wait_for(lambda: check_current_mem_size(1, request_size), 20): + test.fail('Hot-plugged virtio-mem mem device should have ' + 'current memory size %d' % request_size) + + test.log.info("TEST_SETUP4: Check qemu-monitor-command") + output = virsh.qemu_monitor_command( + vm_name, monitor_cmd, monitor_option, **virsh_dargs + ) + for pattern in slots_pattern: + if not re.search(pattern, output.stdout_text.strip()): + test.fail("Expect '%s' in qemu-monitor-command" % pattern) + + def teardown_test(): + """ + Clean data. + """ + test.log.info("TEST_TEARDOWN: Clean up env.") + bkxml.sync() + if memory_backing == "hugepages_mb": + params["hpc_cfg"].cleanup() + + vm_name = params.get("main_vm") + vm = env.get_vm(vm_name) + memory_base.check_supported_version(params, test, vm) + + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + bkxml = vmxml.copy() + virsh_dargs = {"debug": True, "ignore_status": False} + + default_hugepage_size = memory.get_huge_page_size() + allocate_size = int(params.get("allocate_size")) + request_size = int(params.get("request_size")) + memory_backing = params.get("memory_backing") + machine_version = params.get("machine_version") + monitor_cmd = params.get("monitor_cmd") + monitor_option = params.get("monitor_option") + slots_pattern = eval(params.get("slots_pattern")) + dynamic_slot_attr = eval(params.get("dynamic_slot_attr", "{}")) + virtio_mem_dict = eval(params.get('virtio_mem_dict') % default_hugepage_size) + if dynamic_slot_attr: + virtio_mem_dict['target']['attrs'] = dynamic_slot_attr + + if not libvirt_vmxml.check_guest_machine_type(vmxml, machine_version): + test.fail("Guest config machine should be >= rhel{}".format( + machine_version)) + try: + setup_test() + run_test() + + finally: + teardown_test() diff --git a/libvirt/tests/src/memory/memory_devices/virtio_mem_hot_unplug.py b/libvirt/tests/src/memory/memory_devices/virtio_mem_hot_unplug.py new file mode 100644 index 00000000000..5cdab1c14bb --- /dev/null +++ b/libvirt/tests/src/memory/memory_devices/virtio_mem_hot_unplug.py @@ -0,0 +1,359 @@ +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Copyright Redhat +# +# SPDX-License-Identifier: GPL-2.0 + +# Author: Nannan Li +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +import os +import uuid + +from avocado.utils import memory + +from virttest import virsh +from virttest import utils_misc +from virttest import utils_sys +from virttest import utils_test +from virttest import test_setup +from virttest.libvirt_xml import vm_xml +from virttest.staging import utils_memory +from virttest.utils_test import libvirt +from virttest.utils_libvirt import libvirt_vmxml + +from provider.memory import memory_base + +virsh_dargs = {"ignore_status": False, "debug": True} +default_hugepage_size = memory.get_huge_page_size() + + +def adjust_virtio_dict(params): + """ + Adjust virtio memory dict and unplugging dict. + + :param params: dictionary with the test parameters. + :return virtio_dict, unplug_dict , the virtio memory dict when define guest + and unplug. + """ + alias_name = "ua-" + str(uuid.uuid1()) + params.update({"alias": alias_name}) + + source_dict = params.get("source_dict", "") + virtio_dict, unplug_dict = params.get("virtio_dict"), params.get("unplug_dict") + virtio_dict = eval(virtio_dict % (alias_name, default_hugepage_size)) + unplug_dict = eval(unplug_dict % (alias_name, default_hugepage_size)) + + if source_dict: + virtio_dict['source'] = eval(source_dict % default_hugepage_size) + unplug_dict['source'] = eval(source_dict % default_hugepage_size) + + return virtio_dict, unplug_dict + + +def adjust_virtio_size(params, test): + """ + Adjust all virtio related size to KiB. + + :param params: dict wrapped with params. + :param test: test object. + :return target_size, request_size, unplug_target_size, unplug_request_size. + virtio target size, virtio requested size, unplugged virtio target size, + unplugged virtio requested size. + """ + unplug_target_size = int(params.get('unplug_target_size', 0)) + unplug_request_size = int(params.get('unplug_request_size', 0)) + target_size, request_size = int(params.get('target_size')), int( + params.get('request_size')) + unplug_size_unit = params.get('unplug_size_unit') + unplug_request_unit = params.get('unplug_request_unit') + size_unit, request_unit = params.get('size_unit'), params.get( + 'request_unit') + + def _convert_size(curr_size, curr_unit, item): + if curr_unit != "KiB": + new_size = memory_base.convert_data_size(str(curr_size) + curr_unit) + test.log.debug("Convert %s %s to be %s", item, curr_size, new_size) + return int(new_size) + else: + return int(curr_size) + target_size = _convert_size(target_size, size_unit, "target_size") + request_size = _convert_size(request_size, request_unit, "request_size") + unplug_target_size = _convert_size(unplug_target_size, unplug_size_unit, "unplug_target_size") + unplug_request_size = _convert_size(unplug_request_size, unplug_request_unit, "unplug_request_size") + return target_size, request_size, unplug_target_size, unplug_request_size + + +def compare_two_values(test, expected, actual, item_name=''): + """ + Compare two value should be equal + + :param test: test object + :param expected, expected value + :param actual, actual value + :param item_name,checking item name, such as memory value, current memory + """ + if actual != expected: + test.fail( + "Expect %s is %s , but got %s" % (item_name, expected, actual)) + test.log.debug("Checked the %s successfully", item_name) + + +def check_source_and_addr_xml(test, params, virtio_mem_xml): + """ + Check virtio memory source and address xml if existed. + + :param test: test object + :param params: dictionary with the test parameters + :param virtio_mem_xml, virtio memory xml + """ + expected_base = params.get("base") + addr_dict = params.get("addr_dict", "") + source_dict = params.get("source_dict", "") + expected_source_pgsize = default_hugepage_size + + if source_dict: + if virtio_mem_xml.source.pagesize != expected_source_pgsize: + test.fail("Got virtio memory source pagesize %s, should be %s" % ( + virtio_mem_xml.source.pagesize, expected_source_pgsize)) + test.log.debug("Check virtio memory source xml successfully") + if addr_dict: + actual_base = virtio_mem_xml.target.address.attrs.get("base") + if actual_base != expected_base: + test.fail("Got virtio memory address base %s, should be %s" % ( + actual_base, expected_base)) + test.log.debug("Check virtio memory address xml successfully") + + +def check_guest_xml(test, params, hot_unplugged=False): + """ + Check guest xml. + + :param test: test object. + :param params: dictionary with the test parameters. + :param hot_unplugged: boolean, the flag of hot unplugging or not. + + """ + case = params.get("case") + vm_name = params.get("main_vm") + mem_value = int(params.get("mem_value")) + current_mem = int(params.get("current_mem")) + with_numa = params.get('with_numa', 'yes') == 'yes' + + target_size, request_size, unplug_target_size, unplug_request_size = \ + adjust_virtio_size(params, test) + expected_virito_curr = 0 if case == "none_zero_request" else request_size + + vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) + acutal_mem = vmxml.memory + acutal_curr = vmxml.current_mem + virtio_mem_xml = vmxml.devices.by_device_tag("memory") + + if not hot_unplugged: + acutal_virtio_target = virtio_mem_xml[0].target.size + acutal_virtio_block = virtio_mem_xml[0].target.block_size + acutal_virtio_requested = virtio_mem_xml[0].target.requested_size + acutal_virtio_current = virtio_mem_xml[0].target.current_size + if with_numa: + params.update({"expected_mem0": mem_value + target_size}) + params.update({"expected_curr0": current_mem + acutal_virtio_current}) + else: + params.update({"expected_mem0": mem_value}) + params.update({"expected_curr0": current_mem - target_size + acutal_virtio_current}) + params.update({"curr1": acutal_virtio_current}) + + check_source_and_addr_xml(test, params, virtio_mem_xml[0]) + compare_two_values( + test, params.get("expected_mem0"), acutal_mem, 'memory') + compare_two_values( + test, params.get("expected_curr0"), acutal_curr, 'current memory') + + compare_two_values( + test, target_size, acutal_virtio_target, 'virtio memory target size') + compare_two_values( + test, default_hugepage_size, acutal_virtio_block, 'virtio memory block size') + compare_two_values( + test, request_size, acutal_virtio_requested, 'virtio memory requested size') + compare_two_values( + test, expected_virito_curr, acutal_virtio_current, 'virtio memory current size') + + else: + if virtio_mem_xml: + test.fail("Guest virtio memory xml is not empty, but got %s", virtio_mem_xml) + test.log.debug("Check unplugged virtio memory unexisted successfully") + + params.update( + {"expected_mem1": params.get("expected_mem0") - unplug_target_size}) + params.update( + {"expected_curr1": params.get("expected_curr0") - params.get("curr1")}) + + compare_two_values(test, params.get("expected_mem1"), acutal_mem, 'memory') + compare_two_values(test, params.get("expected_curr1"), acutal_curr, 'current memory') + + +def check_guest_virsh_dominfo(vm, test, params, hot_unplugged=False): + """ + Check memory value and current memory value in virsh dominfo result. + + :param vm: vm object. + :param test: test object. + :param params: dictionary with the test parameters. + :param hot_unplugged: boolean, the flag of hot unplugging or not. + """ + if hot_unplugged: + expected_mem = params.get("expected_mem1") + expected_curr = params.get("expected_curr1") + else: + expected_mem = params.get("expected_mem0") + expected_curr = params.get("expected_curr0") + memory_base.check_dominfo(vm, test, str(expected_mem), str(expected_curr)) + + +def check_after_detach(vm, test, params): + """ + Check the below points after unplugging. + + 1. Check the audit log by ausearch. + 2. Check the libvirtd log. + 3. Check the memory allocation and memory device config. + 4. Check the memory info by virsh dominfo. + 5. Check the guest memory. + :param vm: vm object. + :param test: test object. + :param params: dictionary with the test parameters. + :param operation: string, the flag for attaching or detaching. + """ + expected_log = params.get("expected_log") + audit_cmd = params.get("audit_cmd") + target_size, request_size, unplug_target_size, unplug_request_size = \ + adjust_virtio_size(params, test) + libvirtd_log_file = os.path.join(test.debugdir, "libvirtd.log") + ausearch_check = params.get("ausearch_check") % ( + params.get("expected_mem0"), params.get("expected_mem0") - unplug_target_size) + # Check the audit log by ausearch. + utils_sys.check_audit_log(audit_cmd, ausearch_check) + + # Check the libvirtd log. + result = utils_misc.wait_for( + lambda: libvirt.check_logfile(expected_log, libvirtd_log_file), timeout=20) + if not result: + test.fail("Can't get expected log %s in %s" % ( + expected_log, libvirtd_log_file)) + + # Check the memory allocation and memory device config. + check_guest_xml(test, params, hot_unplugged=True) + + # Check the memory info by virsh dominfo. + check_guest_virsh_dominfo(vm, test, params, hot_unplugged=True) + + # Check the guest memory. + session = vm.wait_for_login() + new_memtotal = utils_memory.memtotal(session) + session.close() + expected_memtotal = params.get('old_memtotal') - params.get("curr1") + if new_memtotal != expected_memtotal: + test.fail("Memtotal is %s, should be %s " % (new_memtotal, expected_memtotal)) + test.log.debug("Check guest mem total successfully.") + + +def run(test, params, env): + """ + Verify virtio-mem memory device hot-unplug with different configs. + """ + def setup_test(): + """ + Allocate memory on the host, add kernel parameter to guest. + """ + if case == "source_mib_and_hugepages": + if not libvirt_vmxml.check_guest_machine_type(vmxml, machine_version): + test.fail("Guest config machine should be >= rhel{}".format( + machine_version)) + hpc.setup() + if kernel_params_add: + utils_test.update_boot_option( + vm, args_added=kernel_params_add, guest_arch_name=vm_arch_name) + + def run_test(): + """ + 1. Define vm with virtio memory device. + 2. Hot unplug another virtio memory. + 3. Check audit log, libvirtd log, memory allocation and memory device + config. + """ + test.log.info("TEST_STEP1: Define vm with virtio memory") + memory_base.define_guest_with_memory_device(params, virtio_dict, vm_attrs) + + test.log.info("TEST_STEP2: Start guest") + vm.start() + session = vm.wait_for_login() + + test.log.info("TEST_STEP3: Get the guest memory") + params.update({'old_memtotal': utils_memory.memtotal(session)}) + session.close() + + test.log.info("TEST_STEP4: Check guest xml") + check_guest_xml(test, params) + + test.log.info("TEST_STEP5: Check the memory info by virsh dominfo") + check_guest_virsh_dominfo(vm, test, params) + + if case in ["target_and_address", "source_mib_and_hugepages"]: + test.log.info("TEST_STEP6: Update the requested memory size to 0") + virsh.update_memory_device( + vm_name, options=updated_request_option, wait_for_event=True, + **virsh_dargs) + + test.log.info("TEST_STEP7: Hot unplug one virtio memory device") + memory_base.plug_memory_and_check_result( + test, params, mem_dict=unplug_dict, alias=params.get("alias"), + operation=detach_method, expected_error=unplug_error, + expected_event=unplug_event, event_timeout=15) + + if case in ["target_and_address", "source_mib_and_hugepages"]: + test.log.info("TEST_STEP8: Check audit and libvirt log, " + "memory allocation and memory device config") + check_after_detach(vm, test, params) + + def teardown_test(): + """ + Clean data. + """ + test.log.info("TEST_TEARDOWN: Clean up env.") + bkxml.sync() + hpc.cleanup() + if kernel_params_remove: + if not vm.is_alive(): + vm.start() + utils_test.update_boot_option( + vm, args_removed=kernel_params_remove, guest_arch_name=vm_arch_name) + + vm_name = params.get("main_vm") + vm = env.get_vm(vm_name) + memory_base.check_supported_version(params, test, vm) + + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + bkxml = vmxml.copy() + virtio_dict, unplug_dict = adjust_virtio_dict(params) + case = params.get("case") + machine_version = params.get("machine_version") + allocate_size = int(params.get("allocate_size")) + vm_attrs = eval(params.get("vm_attrs", "{}")) + kernel_hp_file = params.get("kernel_hp_file") + updated_request_option = params.get("updated_request_option") + detach_method = params.get("detach_method") + unplug_error = params.get("unplug_error") + unplug_event = params.get('unplug_event') + kernel_params_add = params.get('kernel_params_add') + kernel_params_remove = params.get('kernel_params_remove') + vm_arch_name = params.get('vm_arch_name') + + params.update({"kernel_hp_file": kernel_hp_file % default_hugepage_size}) + params.update({"target_hugepages": allocate_size / default_hugepage_size}) + hpc = test_setup.HugePageConfig(params) + + try: + setup_test() + run_test() + + finally: + teardown_test() diff --git a/libvirt/tests/src/memory/memory_devices/virtio_mem_hotplug.py b/libvirt/tests/src/memory/memory_devices/virtio_mem_hotplug.py new file mode 100644 index 00000000000..57522f9e2e3 --- /dev/null +++ b/libvirt/tests/src/memory/memory_devices/virtio_mem_hotplug.py @@ -0,0 +1,388 @@ +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Copyright Redhat +# +# SPDX-License-Identifier: GPL-2.0 + +# Author: Nannan Li +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +import os + +from avocado.utils import process +from avocado.utils import memory + +from virttest import utils_misc +from virttest.libvirt_xml import vm_xml +from virttest.staging import utils_memory +from virttest.utils_test import libvirt + +from provider.memory import memory_base + +virsh_dargs = {"ignore_status": False, "debug": True} + + +def adjust_virtio_dict(params): + """ + Adjust virtio memory dict and plugging dict. + + :param params: dictionary with the test parameters. + """ + + default_page_size = utils_memory.getpagesize() + default_hugepage_size = memory.get_huge_page_size() + + case = params.get("case") + source_dict = params.get("source_dict", "") + addr_dict = params.get("addr_dict", "") + plug_addr_dict = params.get("plug_addr_dict", "") + virtio_dict = eval(params.get("virtio_dict", "{}") % default_hugepage_size) + plug_dict = eval(params.get("plug_dict") % default_hugepage_size) + + if source_dict: + if case == "source_mib_and_hugepages": + virtio_dict['source'] = eval(source_dict % default_page_size) + else: + virtio_dict['source'] = eval(source_dict % default_hugepage_size) + plug_dict['source'] = eval(source_dict % default_hugepage_size) + if addr_dict: + target = virtio_dict["target"] + target['address'] = eval(addr_dict) + + plug_target = plug_dict['target'] + plug_target['address'] = eval(plug_addr_dict) + + return virtio_dict, plug_dict + + +def adjust_virtio_size(params): + """ + Adjust all virtio related size to KiB. + + :param params: dict wrapped with params. + """ + plug_target_size = int(params.get('plug_target_size', 0)) + plug_request_size = int(params.get('plug_request_size', 0)) + target_size, request_size = int(params.get('target_size')), int( + params.get('request_size')) + plug_size_unit = params.get('plug_size_unit') + plug_request_unit = params.get('plug_request_unit') + size_unit, request_unit = params.get('size_unit'), params.get( + 'request_unit') + + def _convert_size(curr_size, curr_unit): + if curr_unit != "KiB": + new_size = memory_base.convert_data_size(str(curr_size) + curr_unit) + return int(new_size) + else: + return int(curr_size) + + target_size = _convert_size(target_size, size_unit) + request_size = _convert_size(request_size, request_unit) + plug_target_size = _convert_size(plug_target_size, plug_size_unit) + plug_request_size = _convert_size(plug_request_size, plug_request_unit) + + return target_size, request_size, plug_target_size, plug_request_size + + +def compare_two_values(test, expected, actual, item_name=''): + """ + Compare two value should be equal + + :param test: test object + :param expected, expected value + :param actual, actual value + :param item_name,checking item name, such as memory value, current memory + """ + if actual != expected: + test.fail( + "Expect %s is %s , but got %s" % (item_name, expected, actual)) + else: + test.log.debug("Checked the %s successfully", item_name) + + +def check_source_and_addr_xml(test, params, virtio_mem_xml, mem_index=0): + """ + Check virtio memory source and address xml if existed. + + :param test: test object + :param params: dictionary with the test parameters + :param virtio_mem_xml, virtio memory xml + :param mem_index, Check after or before attaching memory device. + """ + addr_dict = params.get("addr_dict", "") + source_dict = params.get("source_dict", "") + expected_base = params.get("plug_base") if mem_index == 1 \ + else params.get("base") + expected_source_pgsize = memory.get_huge_page_size() if mem_index == 1 \ + else utils_memory.getpagesize() + + if source_dict: + if virtio_mem_xml.source.pagesize != expected_source_pgsize: + test.fail("Got virtio memory source pagesize %s, should be %s" % ( + virtio_mem_xml.source.pagesize, expected_source_pgsize)) + if addr_dict: + actual_base = virtio_mem_xml.target.address.attrs.get("base") + if actual_base != expected_base: + test.fail("Got virtio memory address base %s, should be %s" % ( + actual_base, expected_base)) + + +def check_delayed_current(test, params, mem_index, expected_current_size): + """ + Check the virtio memory current value. + + :param test: test object. + :param params: dictionary with the test parameters. + :param expected_current_size, expected current size value. + :param mem_index, Check after or before attaching memory device. + """ + vm_name = params.get("main_vm") + + def _get_virtio_current(): + return vm_xml.VMXML.new_from_dumpxml( + vm_name).devices.by_device_tag("memory")[ + mem_index].target.current_size + + if not utils_misc.wait_for( + lambda: expected_current_size == _get_virtio_current(), 20): + test.fail( + "Attached virtio memory current size should be %s" % expected_current_size) + test.log.debug("Checked attached virtio memory current size successfully") + + params.update({"second_virtio_curr": _get_virtio_current()}) + params.update({"acutal_curr": vm_xml.VMXML.new_from_dumpxml(vm_name).current_mem}) + + +def check_guest_xml(test, params, mem_index=0): + """ + Check guest xml. + + :param test: test object. + :param params: dictionary with the test parameters. + :param mem_index, the memory order in the guest, set 1 when checking the + plugged virtio memory. + """ + vm_name = params.get("main_vm") + mem_value = int(params.get("mem_value")) + current_mem = int(params.get("current_mem")) + numa_dict = params.get("numa_dict") + + target_size, request_size, plug_target_size, plug_request_size = \ + adjust_virtio_size(params) + default_hugepage_size = memory.get_huge_page_size() + + vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) + virtio_mem_xml = vmxml.devices.by_device_tag("memory")[mem_index] + acutal_mem = vmxml.memory + acutal_curr = vmxml.current_mem + acutal_virtio_target = virtio_mem_xml.target.size + acutal_virtio_block = virtio_mem_xml.target.block_size + acutal_virtio_requested = virtio_mem_xml.target.requested_size + acutal_virtio_current = virtio_mem_xml.target.current_size + + check_source_and_addr_xml(test, params, virtio_mem_xml, mem_index) + if mem_index == 0: + expected_mem0 = mem_value + target_size if numa_dict else mem_value + expected_curr0 = current_mem + acutal_virtio_current if numa_dict else current_mem - \ + target_size + acutal_virtio_current + params.update({"first_virtio_curr": acutal_virtio_current}) + params.update({"expected_mem0": expected_mem0}) + params.update({"expected_curr0": expected_curr0}) + + compare_two_values( + test, params.get("expected_mem0"), acutal_mem, 'memory') + compare_two_values( + test, params.get("expected_curr0"), acutal_curr, 'current memory') + compare_two_values( + test, target_size, acutal_virtio_target, 'virtio memory target size') + compare_two_values( + test, default_hugepage_size, acutal_virtio_block, 'virtio memory block size') + compare_two_values( + test, request_size, acutal_virtio_requested, 'virtio memory requested size') + compare_two_values( + test, acutal_virtio_current, request_size, 'virtio memory current size') + + elif mem_index == 1: + compare_two_values( + test, plug_target_size, acutal_virtio_target, + 'Attached virtio memory target size') + compare_two_values( + test, default_hugepage_size, acutal_virtio_block, + 'Attached virtio memory block size') + compare_two_values( + test, plug_request_size, acutal_virtio_requested, + 'Attached virtio memory requested size') + + check_delayed_current(test, params, mem_index, plug_request_size) + + curr1, curr2 = params.get("first_virtio_curr"), params.get("second_virtio_curr") + expected_mem1 = mem_value + target_size + \ + plug_target_size if numa_dict else mem_value + plug_target_size + expected_curr1 = current_mem + curr1 + \ + curr2 if numa_dict else current_mem - target_size + curr1 + curr2 + params.update( + {"expected_mem1": expected_mem1}) + params.update({"expected_curr1": expected_curr1}) + compare_two_values( + test, params.get("expected_mem1"), acutal_mem, 'memory') + compare_two_values( + test, params.get("expected_curr1"), params.get("acutal_curr"), + 'current memory') + + +def check_guest_virsh_dominfo(vm, test, params, hot_plugged=False): + """ + Check memory value and current memory value in virsh dominfo result. + + :param vm: vm object. + :param test: test object. + :param params: dictionary with the test parameters. + :param hot_plugged: boolean, the flag of hotplugging. + """ + if hot_plugged: + expected_mem = params.get("expected_mem1") + expected_curr = params.get("expected_curr1") + else: + expected_mem = params.get("expected_mem0") + expected_curr = params.get("expected_curr0") + + memory_base.check_dominfo(vm, test, str(expected_mem), str(expected_curr)) + + +def check_after_attach(vm, test, params): + """ + Check the below points after plugging. + + 1. Check the audit log by ausearch. + 2. Check the libvirtd log. + 3. Check the memory allocation and memory device config. + 4. Check the memory info by virsh dominfo. + 5. Check the guest memory. + :param vm: vm object. + :param test: test object. + :param params: dictionary with the test parameters. + :param operation: string, the flag for attaching or detaching. + """ + mem_value = int(params.get("mem_value")) + expected_log = params.get("expected_log") + audit_cmd = params.get("audit_cmd") + numa_dict = params.get("numa_dict") + target_size, request_size, plug_target_size, plug_request_size = \ + adjust_virtio_size(params) + ori_mem = mem_value + target_size if numa_dict else mem_value + pluged_mem = mem_value + target_size + \ + plug_target_size if numa_dict else mem_value + plug_target_size + + libvirtd_log_file = os.path.join(test.debugdir, "libvirtd.log") + ausearch_check = params.get("ausearch_check") % ( + ori_mem, pluged_mem) + + # Check the audit log by ausearch. + ausearch_result = process.run(audit_cmd, shell=True) + libvirt.check_result(ausearch_result, expected_match=ausearch_check) + test.log.debug("Check audit log %s successfully." % ausearch_check) + + # Check the libvirtd log. + result = utils_misc.wait_for( + lambda: libvirt.check_logfile(expected_log, libvirtd_log_file), timeout=20) + if not result: + test.fail("Can't get expected log %s in %s" % ( + expected_log, libvirtd_log_file)) + + # Check the memory allocation and memory device config. + check_guest_xml(test, params, mem_index=1) + + # Check the memory info by virsh dominfo. + check_guest_virsh_dominfo(vm, test, params, hot_plugged=True) + + # Check the guest memory. + session = vm.wait_for_login() + new_memtotal = utils_memory.memtotal(session) + session.close() + expected_memtotal = params.get('old_memtotal') + params.get("second_virtio_curr") + if new_memtotal != expected_memtotal: + test.fail("Memtotal is %s, should be %s " % (new_memtotal, expected_memtotal)) + test.log.debug("Check guest mem total successfully.") + + +def run(test, params, env): + """ + Verify virtio-mem memory device hot-plug with different configs. + """ + + def setup_test(): + """ + Allocate memory on the host. + """ + process.run( + "echo %d > %s" % (allocate_size / default_hugepage_size, + kernel_hp_file % default_hugepage_size), + shell=True) + + def run_test(): + """ + 1. Define vm with virtio memory device. + 2. Hot plug another virtio memory. + 3. Check audit log, libvirtd log, memory allocation and memory device + config. + """ + test.log.info("TEST_STEP1: Define vm with virtio memory") + memory_base.define_guest_with_memory_device(params, virtio_dict, + vm_attrs) + + test.log.info("TEST_STEP2: Start guest") + vm.start() + session = vm.wait_for_login() + + test.log.info("TEST_STEP3: Get the guest memory") + params.update({'old_memtotal': utils_memory.memtotal(session)}) + session.close() + + test.log.info("TEST_STEP4: Check guest xml") + check_guest_xml(test, params) + + test.log.info("TEST_STEP5: Check the memory info by virsh dominfo") + check_guest_virsh_dominfo(vm, test, params) + + test.log.info("TEST_STEP6: Hot plug one virtio memory device") + memory_base.plug_memory_and_check_result( + test, params, mem_dict=plug_dict, operation='attach', + expected_error=plug_error, expected_event=plug_event) + + if case in ["target_and_address", "source_mib_and_hugepages"]: + test.log.info("TEST_STEP7: Check audit and libvirt log, " + "memory allocation and memory device config") + check_after_attach(vm, test, params) + + def teardown_test(): + """ + Clean data. + """ + test.log.info("TEST_TEARDOWN: Clean up env.") + bkxml.sync() + process.run("echo 0 > %s" % (kernel_hp_file % default_hugepage_size), + shell=True) + + vm_name = params.get("main_vm") + original_xml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + bkxml = original_xml.copy() + vm = env.get_vm(vm_name) + + virtio_dict, plug_dict = adjust_virtio_dict(params) + default_hugepage_size = memory.get_huge_page_size() + case = params.get("case") + allocate_size = int(params.get("allocate_size")) + vm_attrs = eval(params.get("vm_attrs", "{}")) + kernel_hp_file = params.get("kernel_hp_file") + plug_error = params.get("plug_error") + plug_event = params.get('plug_event') + + memory_base.check_supported_version(params, test, vm) + + try: + setup_test() + run_test() + + finally: + teardown_test() diff --git a/libvirt/tests/src/memory/memory_devices/virtio_mem_with_memory_allocation_and_numa.py b/libvirt/tests/src/memory/memory_devices/virtio_mem_with_memory_allocation_and_numa.py new file mode 100644 index 00000000000..7c379155970 --- /dev/null +++ b/libvirt/tests/src/memory/memory_devices/virtio_mem_with_memory_allocation_and_numa.py @@ -0,0 +1,195 @@ +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Copyright Redhat +# +# SPDX-License-Identifier: GPL-2.0 + +# Author: Nannan Li +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +import re + +from avocado.utils import memory as avocado_mem + +from virttest import virsh +from virttest.libvirt_xml import vm_xml +from virttest.utils_test import libvirt + +from provider.memory import memory_base + + +def adjust_virtio_mem_size_unit(params, test): + """ + Adjust the virtio memory target size and request size to KiB unit. + + :param params: dict, test parameters + :param test: test object. + """ + target_size = int(memory_base.convert_data_size( + params.get("target_size") + params.get("target_size_unit"))) + request_size = int(memory_base.convert_data_size( + params.get("request_size") + params.get("request_size_unit"))) + + params.update({"target_size": target_size}) + params.update({"request_size": request_size}) + + test.log.debug("Convert params: target_size to be %s, request_size to be %s", + target_size, request_size) + + +def check_guest_xml(vm, params, test): + """ + Check guest xml. + + :param vm: vm object. + :param params: test parameters object + :param test: test object. + """ + expect_mem = int(params.get("mem_value")) + expect_curr = int(params.get("current_mem")) + memory_allocation = params.get("memory_allocation") + numa_topology = params.get("numa_topology") + no_numa_and_max_mem = \ + memory_allocation == "with_maxmemory" and numa_topology == "without_numa" + + vmxml = vm_xml.VMXML.new_from_dumpxml(vm.name) + test.log.debug("Current guest xml is %s\n", vmxml) + memory = vmxml.get_memory() + current_mem = vmxml.get_current_mem() + virtio_mem = vmxml.get_devices("memory")[0] + target = virtio_mem.target + target_size = int(target.get_size()) + if params.get("node"): + target_node = target.get_node() + target_block = target.get_block_size() + target_request = target.get_requested_size() + target_current = int(target.get_current_size()) + + adjust_virtio_mem_size_unit(params, test) + + test.log.debug("Check guest memory and current memory value") + if not no_numa_and_max_mem: + expect_mem = int(params.get("mem_value")) + target_size + expect_curr = int(params.get("current_mem")) + target_current + memory_base.compare_values(test, expect_mem, memory, "memory") + memory_base.compare_values(test, expect_curr, current_mem, "current memory") + + test.log.debug("Check virtio memory size") + memory_base.compare_values(test, params.get("target_size"), + target_size, "virtio mem target size") + memory_base.compare_values(test, params.get('default_hp'), + target_block, "virtio mem block size") + memory_base.compare_values(test, params.get("request_size"), + target_request, "virtio mem request size") + memory_base.compare_values(test, params.get("request_size"), + target_current, "virtio mem current size") + if params.get("node"): + memory_base.compare_values( + test, int(params.get("node")), target_node, "numa node") + if params.get("numa_mem"): + memory_base.compare_values(test, params.get("numa_mem"), + vmxml.cpu.numa_cell[0].memory, "numa memory") + + +def run(test, params, env): + """ + Verify virtio-mem memory device works with various + memory allocation and numa setting. + """ + def run_test_define_guest(): + """ + Define guest with memory allocation and numa, virtio memory. + """ + test.log.info("TEST_STEP1: Define guest with one virtio-mem device") + try: + memory_base.define_guest_with_memory_device( + params, virtio_mem_dict, vm_attrs) + + except Exception as e: + if define_error: + if not re.search(define_error, str(e)): + test.fail("Except %s error msg, but got %s" % (define_error, e)) + else: + test.log.debug("Define guest with expected error:\n%s", e) + return + else: + test.fail("Define guest failed") + + test.log.info("TEST_STEP2: Start guest") + virsh.start(vm_name) + vm.wait_for_login().close() + + test.log.info("TEST_STEP3: Check guest memory xml") + check_guest_xml(vm, params, test) + + def run_test_cold_plug(): + """ + Check guest with various memory allocation and numa setting, + and cold plug virtio-mem memory device successfully. + """ + test.log.info("TEST_STEP1: Define guest without virtio-mem devices") + vmxml.setup_attrs(**vm_attrs) + vmxml.sync() + + test.log.info("TEST_STEP2: Cold-plug one virtio-mem device") + memory_base.plug_memory_and_check_result( + test, params, mem_dict=virtio_mem_dict, operation=operation, + expected_error=cold_plug_error, flagstr=plug_option) + if cold_plug_error: + return + + test.log.info("TEST_STEP3: Start guest and check result") + res = virsh.start(vm_name) + libvirt.check_result(res, expected_fails=coldplug_start_error) + + def run_test_hot_plug(): + """ + Check guest with various memory allocation and numa setting, + and hot plug virtio-mem memory device successfully. + """ + test.log.info("TEST_STEP1: Define guest without virtio-mem devices") + vmxml.setup_attrs(**vm_attrs) + vmxml.sync() + + test.log.info("TEST_STEP2: Start guest") + vm.start() + vm.wait_for_login().close() + + test.log.info("TEST_STEP3: Hot-plug one virtio-mem device") + memory_base.plug_memory_and_check_result( + test, params, mem_dict=virtio_mem_dict, operation=operation, + expected_error=hot_plug_error, flagstr=plug_option) + + def teardown_test(): + """ + Clean data. + """ + test.log.info("TEST_TEARDOWN: Clean up env.") + bkxml.sync() + + vm_name = params.get("main_vm") + vm = env.get_vm(vm_name) + memory_base.check_supported_version(params, test, vm) + + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + bkxml = vmxml.copy() + + default_hugepage_size = avocado_mem.get_huge_page_size() + vm_attrs = eval(params.get('vm_attrs', '{}')) + params.update({"default_hp": default_hugepage_size}) + virtio_mem_dict = eval(params.get("virtio_mem_dict") % default_hugepage_size) + operation = params.get("operation") + plug_option = params.get("plug_option") + plug_type = params.get("plug_type") + define_error = params.get("define_error") + coldplug_start_error = params.get("coldplug_start_error") + hot_plug_error = params.get("hot_plug_error") + cold_plug_error = params.get("cold_plug_error") + + run_test = eval("run_test_%s" % plug_type) + + try: + run_test() + + finally: + teardown_test() diff --git a/libvirt/tests/src/memory/memory_devices/virtio_mem_with_memory_backing_type.py b/libvirt/tests/src/memory/memory_devices/virtio_mem_with_memory_backing_type.py new file mode 100644 index 00000000000..723af71599e --- /dev/null +++ b/libvirt/tests/src/memory/memory_devices/virtio_mem_with_memory_backing_type.py @@ -0,0 +1,247 @@ +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Copyright Redhat +# +# SPDX-License-Identifier: GPL-2.0 + +# Author: Nannan Li +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +import re +import json + +from avocado.utils import cpu +from avocado.utils import memory as avocado_mem + +from virttest import virsh +from virttest.libvirt_xml import vm_xml +from virttest.utils_libvirtd import Libvirtd +from virttest.utils_libvirt import libvirt_memory +from virttest.utils_libvirt import libvirt_vmxml +from virttest.staging import utils_memory + +from provider.memory import memory_base + +VIRSH_ARGS = {'debug': True, 'ignore_status': False} + + +def get_vm_attrs(test, params): + """ + Get vm attrs. + :param test: test object + :param params: dictionary with the test parameters + :return vm_attrs: get updated vm attrs dict. + """ + max_mem = params.get("max_mem") + if cpu.get_arch().startswith("aarch"): + max_mem = params.get("aarch_max_mem") + vm_attrs = eval(params.get("vm_attrs", "{}") % max_mem) + source_attr = params.get("source_attr", "") + alloc_attr = params.get("alloc_attr", "") + hugepages_attr = params.get("hugepages_attr", "") + + mb_value = "" + for item in [source_attr, alloc_attr, hugepages_attr]: + if item != "": + mb_value += item + "," + mb_attrs = eval("{'mb':{%s}}" % mb_value[:-1]) + + vm_attrs.update(mb_attrs) + test.log.debug("Get current vm attrs is :%s", vm_attrs) + + return vm_attrs + + +def get_virtio_objs(test, params): + """ + Get all virtio-mem memory device objects. + + :param test: test object. + :param params: dictionary with the test parameters. + :return mem_objs: virtio memory device object list. + """ + default_pagesize = params.get('default_pagesize') + virtio_config = eval(params.get("virtio_config")) + mem_objs = [] + for item in virtio_config: + single_mem = {'mem_model': 'virtio-mem'} + if item[0] == "huge_page": + single_mem.update({'source': {'pagesize': default_pagesize}}) + single_mem.update( + {'target': {'size': int(params.get('target_size')), + 'requested_size': int(params.get('request_size')), + 'block_size': int(default_pagesize)}}) + if len(item) == 2: + single_mem['target'].update({'node': item[1]}) + test.log.debug("Get the virtio-mem dict: %s", single_mem) + mem_obj = libvirt_vmxml.create_vm_device_by_type('memory', single_mem) + mem_objs.append(mem_obj) + return mem_objs + + +def check_qemu_monitor_json(test, params, mem_names, check_item, check_cmd, + expected_list): + """ + Check virsh qemu_monitor_command result. + + :param test: test object. + :param params: dictionary with the test parameters. + :param mem_names: virtio memory memory name list. + :param check_item: check item, such as memory backing type or path. + :param check_cmd: the command to check qemu monitor. + :param expected_list: expected list. + """ + vm_name = params.get("main_vm") + for index, mem_name in enumerate(mem_names): + res = virsh.qemu_monitor_command( + vm_name, check_cmd % mem_name, **VIRSH_ARGS).stdout_text + + if 'return' in json.loads(res): + actual_value = str(json.loads(res)['return']) + if expected_list[index] in actual_value: + test.log.debug("Check '%s' is '%s' PASS", check_item, actual_value) + else: + test.fail("Expect '%s' for '%s' is '%s', but got '%s'" % ( + check_item, mem_name, expected_list[index], actual_value)) + else: + test.fail("Checking '%s' failed" % res) + + +def check_mb_setting(test, params): + """ + Check memory backing pre-allocated value, memory backing type and + memory backing path. + + :param test: test object. + :param params: dictionary with the test parameters. + """ + virtio_mem_num = int(params.get("virtio_mem_num")) + expected_prealloc_config = eval(params.get("expected_prealloc_config", "[]")) + expected_allocated = eval(params.get("expected_allocated", "[]")) + expected_backing_type = eval(params.get("expected_backing_type", "[]")) + expected_mem_path = eval(params.get("expected_mem_path", "[]")) + memory_backing = params.get("memory_backing") + check_prealloc_config = params.get("check_prealloc_config") + check_backing_type = params.get("check_backing_type") + check_mem_path = params.get("check_mem_path") + allocation_mode = params.get("allocation_mode") + vm_name = params.get("main_vm") + file_backend_scenario =\ + memory_backing == "file" or \ + memory_backing == "undefined" and allocation_mode == "set_hugepage" + + mem_name_list = [] + alias_name_list = [] + # Check virtio memory pre-allocated value + ret = virsh.qemu_monitor_command(vm_name, "info memdev", "--hmp", + debug=True).stdout_text.replace("\r\n", "") + for index in range(virtio_mem_num): + alias_name = "virtiomem%d" % index + mem_name = "memvirtiomem%d" % index + pattern = "memory backend: %s.*prealloc: %s " % ( + mem_name, expected_allocated[index]) + + if not re.search(pattern, ret): + test.fail("Expect '%s' exist, but not found" % pattern) + else: + test.log.debug("Check access pre-allocated value is '%s': PASS", pattern) + mem_name_list.append(mem_name) + alias_name_list.append(alias_name) + + # Check virtio memory device prealloc. + check_qemu_monitor_json(test, params, alias_name_list, + 'memory device prealloc config', check_prealloc_config, + expected_prealloc_config) + + # Check virtio memory backing type. + check_qemu_monitor_json(test, params, mem_name_list, + 'memory backing type', check_backing_type, + expected_backing_type) + + # Check virtio memory backing path. + if file_backend_scenario: + check_qemu_monitor_json(test, params, mem_name_list, + 'memory backing path', check_mem_path, + expected_mem_path) + + +def run(test, params, env): + """ + Verify virtio-mem memory device works with various memory backing type + """ + def setup_test(): + """ + Allocate huge page memory: + """ + test.log.info("TEST_SETUP: Set hugepage and add kernel parameter") + default_pagesize = avocado_mem.get_huge_page_size() + params.update({'default_pagesize': default_pagesize}) + utils_memory.set_num_huge_pages(int(allocate_huge_pages)/default_pagesize) + + def run_test(): + """ + Test virtio-mem memory device under various memory backing types + """ + test.log.info("TEST_STEP1: Define vm with virtio-mem") + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + vm_attrs = get_vm_attrs(test, params) + vmxml.setup_attrs(**vm_attrs) + vmxml.sync() + + mem_objs = get_virtio_objs(test, params) + + if attach_type == "cold_plug": + test.log.info("TEST_STEP2: Cold-plug virtio-mem devices") + for mem in mem_objs: + virsh.attach_device(vm.name, mem.xml, flagstr="--config", + **VIRSH_ARGS) + + test.log.info("TEST_STEP3: Start guest") + vm.start() + vm.wait_for_login().close() + + test.log.info("TEST_STEP4: Restart the service") + Libvirtd().restart() + + if attach_type == "hot_plug": + test.log.info("TEST_STEP5: Hot-plug virtio-mem devices") + for mem in mem_objs: + virsh.attach_device(vm.name, mem.xml, + wait_for_event=True, **VIRSH_ARGS) + test.log.info("TEST_STEP 6-9:Check virtio memory backend pre-allocated " + "value, memory backing type and memory backing path.") + check_mb_setting(test, params) + + test.log.info("TEST_STEP10: Consume guest memory successfully") + session = vm.wait_for_login() + status, output = libvirt_memory.consume_vm_freememory( + session, remain_mem=remain_mem) + if status: + test.fail("Fail to consume guest memory. Error:%s" % output) + session.close() + + def teardown_test(): + """ + Clean data. + """ + test.log.info("TEST_TEARDOWN: Clean up env.") + utils_memory.set_num_huge_pages(0) + bkxml.sync() + + vm_name = params.get("main_vm") + original_xml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + bkxml = original_xml.copy() + vm = env.get_vm(vm_name) + memory_base.adjust_memory_size(params) + + allocate_huge_pages = re.findall(r'\d+', params.get("allocate_huge_pages"))[0] + attach_type = params.get("attach_type") + remain_mem = int(params.get("remain_mem")) + + try: + memory_base.check_supported_version(params, test, vm) + setup_test() + run_test() + + finally: + teardown_test() diff --git a/libvirt/tests/src/memory/memory_devices/virtio_memory_with_numa_node_tuning.py b/libvirt/tests/src/memory/memory_devices/virtio_memory_with_numa_node_tuning.py new file mode 100644 index 00000000000..96be45a0364 --- /dev/null +++ b/libvirt/tests/src/memory/memory_devices/virtio_memory_with_numa_node_tuning.py @@ -0,0 +1,462 @@ +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Copyright Redhat +# +# SPDX-License-Identifier: GPL-2.0 + +# Author: Nannan Li +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +import copy +import re + +from avocado.utils import memory +from avocado.utils import process + +from virttest import virsh +from virttest import test_setup +from virttest.libvirt_xml import vm_xml +from virttest.utils_libvirtd import Libvirtd +from virttest.utils_libvirt import libvirt_vmxml +from virttest.utils_libvirt import libvirt_memory + +from provider.memory import memory_base +from provider.numa import numa_base + +virsh_dargs = {"ignore_status": False, "debug": True} +default_hugepage_size = memory.get_huge_page_size() + + +def get_two_hugepage_sizes(test, params): + """ + Get two huge page sizes + + :param test: test object + :param params: Dictionary with the test parameters + :return default_hugepage_size, current default hugepage size value + max(hugepage_sizes), the max hugepage size that is closed to upper_limit and + different from default hugepage size. + """ + upper_limit = params.get("upper_limit", 1048576) + + hpc = test_setup.HugePageConfig(params) + supported_hugepage_size = hpc.get_multi_supported_hugepage_size() + supported_hugepage_size.remove(str(default_hugepage_size)) + + hugepage_sizes = [] + for size in supported_hugepage_size: + if upper_limit % int(size) == 0: + hugepage_sizes.append(int(size)) + + test.log.debug("Get default huge page size:%s, another huge page size %s", + default_hugepage_size, max(hugepage_sizes)) + + return default_hugepage_size, max(hugepage_sizes) + + +def _allocate_huge_memory(params, test, allocate_mem, + hugepage_size, hugepage_path=None): + """ + Allocate hugepage memory. + + :param params: Dictionary with the test parameters + :param test: test object. + :param allocate_mem, total allocate memory on each numa node. + :param hugepage_size: the hugepage size to allocate. + :param hugepage_path: the hugepage path to allocate. + """ + kernel_hp_file = params.get("kernel_hp_tmpl_file") + cleanup_file = params.get("cleanup_file", []) + + target_nodes = params.get("numa_obj").online_nodes_withmem[:2] + params.update({"all_nodes": target_nodes}) + + test.log.debug("Allocate %sKiB on %s pagesize", allocate_mem, hugepage_size) + params.update({'target_nodes': ' '.join(str(n) for n in target_nodes)}) + for node in target_nodes: + params.update({ + 'target_num_node%s' % node: allocate_mem / hugepage_size}) + params.update( + {"kernel_hp_file": kernel_hp_file % (node, hugepage_size)}) + cleanup_file.append(params.get("kernel_hp_file")) + params.update({"cleanup_file": cleanup_file}) + + hpc = test_setup.HugePageConfig(params) + hpc.hugepage_size = hugepage_size + if hugepage_path: + hpc.hugepage_path = hugepage_path % hugepage_size + params.update({"hg_path": hpc.hugepage_path}) + else: + # Give a always mounted path to avoid mount in HugePageConfig + hpc.hugepage_path = '/' + hpc.setup() + Libvirtd().restart() + + +def allocate_huge_memory(params, test): + """ + Allocate hugepage memory with two hugepage sizes on each numa node. + + :param params: instance of avocado params class + :param test: test object. + """ + hugepage_path = params.get("hugepage_path") + default_hp_size = params.get("default_hp_size") + another_hp_size = params.get("another_hp_size") + allocate_huge_mem = int(re.findall(r"\d+", params.get("allocate_huge_mem"))[0]) + allocate_huge_mem_1 = int(re.findall(r"\d+", params.get("allocate_huge_mem_1"))[0]) + + _allocate_huge_memory( + params, test, allocate_huge_mem, default_hp_size) + _allocate_huge_memory( + params, test, allocate_huge_mem_1, another_hp_size, hugepage_path) + + params.update( + {"allocate_mem_and_hp_match": {default_hp_size: allocate_huge_mem, + another_hp_size: allocate_huge_mem_1}}) + + +def create_vm_attrs(params): + """ + Create vm defined attrs. + + :param params: instance of avocado params class + """ + vm_attrs = params.get('vm_attrs', '{}') + another_hp_size = params.get("another_hp_size") + with_numa_tuning = params.get("numa_tuning") != "undefined" + + if with_numa_tuning: + all_nodes = params.get('all_nodes') + define_attrs = eval( + vm_attrs % (another_hp_size, all_nodes[0], all_nodes[1])) + else: + define_attrs = eval(vm_attrs % another_hp_size) + + return define_attrs + + +def create_mem_objects(params): + """ + create memory objects list. + + :param params: instance of avocado params class + :return mem_obj: memory objects list. + """ + case = params.get("case") + virtio_mem_list = params.get("virtio_mem_list") + default_hp_size = params.get("default_hp_size") + another_hp_size = params.get("another_hp_size") + block_size = max(default_hp_size, another_hp_size) + + if case == "with_source_virtio_mem": + virtio_mem_list = virtio_mem_list % ( + default_hp_size, default_hp_size, another_hp_size, block_size) + elif case == "no_source_virtio_mem": + virtio_mem_list = virtio_mem_list % (default_hp_size, block_size) + elif case == "requested_bigger_than_host_numa": + virtio_mem_list = virtio_mem_list % block_size + + mem_obj = [] + for mem in eval(virtio_mem_list): + obj = libvirt_vmxml.create_vm_device_by_type("memory", mem) + mem_obj.append(obj) + + return mem_obj + + +def plug_virtio_mem(params, vm, operation, mem_obj_list): + """ + Hot plug or Cold plug memory + + :param params: dictionary with the test parameters. + :param vm: vm object. + :param operation: flag for hot plugging or cold plugging. + :param mem_obj_list: memory device object list to plug. + """ + vm_name = params.get("main_vm") + attach_option = params.get("attach_option") + + if operation == "cold_plug": + pass + elif operation == "hot_plug": + vm.start() + vm.wait_for_login().close() + + for mem in mem_obj_list: + virsh.attach_device(vm_name, mem.xml, flagstr=attach_option, + **virsh_dargs) + + +def consume_guest_mem(vm, test): + """ + Consume guest memory + + :param vm, vm object + :param test: test instance. + """ + if not vm.is_alive(): + vm.start() + + session = vm.wait_for_login() + status, output = libvirt_memory.consume_vm_freememory(session) + if status: + test.fail("Fail to consume guest memory. Got error:%s" % output) + session.close() + + +def check_numa_memory_allocation(params, test, dest_size): + """ + Check the numa node memory. + + :param params: dictionary with the test parameters. + :param test: test instance + :param dest_size: target size of virtio mem device + """ + all_nodes = params.get('all_nodes') + + numa_maps = numa_base.get_host_numa_memory_alloc_info(dest_size) + N0_value = re.findall(r'N%s=(\d+)' % all_nodes[0], numa_maps) + N1_value = re.findall(r'N%s=(\d+)' % all_nodes[1], numa_maps) + if not N0_value: + test.fail( + "The numa_maps should include 'N%s=', but not found" % all_nodes[0]) + if N1_value: + test.fail( + "The numa_maps should not include 'N%s=', but found" % all_nodes[1]) + + +def _get_freepages(node, pagesize): + """ + Get virsh freepages for each node and pagesize + + :param node: host numa node value. + :param pagesize: hugepage size value. + :return free pages number + """ + res = virsh.freepages(node, pagesize, debug=True).stdout_text + return int(res.split()[-1]) + + +def _get_another_node(params, node): + """ + Get another numa node except current node + + :param params: dictionary with the test parameters. + :param node: current node. + :return another numa node except current node. + """ + all_nodes = params.get("all_nodes") + nodes = copy.deepcopy(all_nodes) + nodes.remove(node) + + return nodes[0] + + +def _get_left_mem(vm, params, test, host_numa_node, hp_size): + """ + Get specific host numa node left memory value for specific hugepage size + + :param vm: vm object + :param params: dict wrapped with params + :param test: test object + :param host_numa_node: host numa node + :param hp_size: hugepage size + """ + with_numa_tuning = params.get("numa_tuning") != "undefined" + match = params.get("allocate_mem_and_hp_match") + each_node_total_mem = match[hp_size] + used_mem = 0 + vmxml = vm_xml.VMXML.new_from_dumpxml(vm.name) + + # Get memory backing hugepage size + mb_pagesize = int(vmxml.mb.hugepages.pages[0]['size']) + mb_guest_node = int(vmxml.mb.hugepages.pages[0]['nodeset']) + + # Calculate virtio memory used memory. + for mem in vmxml.devices.by_device_tag('memory'): + requested = mem.target.requested_size + mem_attrs = mem.fetch_attrs() + mem_source = mem_attrs.get("source") + if mem_source: + used_host_numa_node = int(mem_source['nodemask']) + used_pagesize = int(mem_source['pagesize']) + else: + guest_node = int(mem_attrs['target']['node']) + used_pagesize = mb_pagesize + used_host_numa_node = '' + if guest_node == mb_guest_node: + if with_numa_tuning: + used_host_numa_node = _get_another_node(params, guest_node) + + else: + used_host_numa_node = guest_node + + if host_numa_node == used_host_numa_node and used_pagesize == hp_size: + used_mem += requested + + # Calculate numa topology used memory. + if with_numa_tuning: + used_host_numa_node = _get_another_node(params, mb_guest_node) + else: + used_host_numa_node = mb_guest_node + if host_numa_node == used_host_numa_node and mb_pagesize == hp_size: + for cell in vmxml.cpu.numa_cell: + if int(cell.id) == mb_guest_node: + used_mem += int(cell.memory) + + test.log.debug("Get left memory:%s for %s hugepage size " + "on host numa node:%s", int(each_node_total_mem - used_mem), + hp_size, host_numa_node) + + return each_node_total_mem - used_mem + + +def get_expected_freepages(vm, params, test, hugepage_size): + """ + Get the expected freepages for two numa nodes. + + :param vm: vm object + :param params: dict wrapped with params + :param test: test object + :param hugepage_size: huge page size + """ + all_nodes = params.get("all_nodes") + vmxml = vm_xml.VMXML.new_from_dumpxml(vm.name) + numa_tuning = params.get("numa_tuning") + numa_memnode = vmxml.numa_memnode[0]['mode'] if numa_tuning != "undefined" else '' + + fp0 = int(_get_left_mem( + vm, params, test, all_nodes[0], hugepage_size) / hugepage_size) + fp1 = int(_get_left_mem( + vm, params, test, all_nodes[1], hugepage_size) / hugepage_size) + + fp_list = [fp0, fp1] + for index, fp in enumerate(fp_list): + if numa_memnode == "strict" and fp < 0: + # Check if used virtio memory over total numa node memory, and with + # strict numa mem mode, it will not use another numa node memory and + # get 0 free pages. + fp_list[index] = 0 + return sum(fp_list) + + +def check_freepages(params, vm, test): + """ + Check host free pages. + + :param params: dict wrapped with params + :param vm: vm object + :param test: test object + """ + all_nodes = params.get('all_nodes') + another_hp_size = params.get("another_hp_size") + no_numa_tuning = params.get("numa_tuning") == "undefined" + bigger_requested = params.get("case") == "requested_bigger_than_host_numa" + + for node, hp in zip(all_nodes+all_nodes, params.get("hp_list")): + if hp == another_hp_size and (no_numa_tuning or bigger_requested): + expected_freepages = get_expected_freepages(vm, params, test, hp) + actual_freepages = _get_freepages(all_nodes[0], hp) + _get_freepages(all_nodes[1], hp) + check_item = f"node{all_nodes} hugepage size:{hp} free pages number" + else: + expected_freepages = int(_get_left_mem(vm, params, test, node, hp) / hp) + actual_freepages = _get_freepages(node, hp) + check_item = f"node{node} hugepage size:{hp} free pages number" + + memory_base.compare_values( + test, + expected_freepages, + actual_freepages, + check_item=check_item + ) + + +def run(test, params, env): + """ + 1.Define guest with virtio-mem devices. + 2.Attach virtio-mem and check memory usage by virsh freepages. + """ + def setup_test(): + """ + Check available numa nodes num. + """ + test.log.info("TEST_SETUP: Check available numa nodes num") + params.get("numa_obj").check_numa_nodes_availability() + + test.log.info("TEST_SETUP: Allocate hugepage memory") + allocate_huge_memory(params, test) + + def run_test(): + """ + Define guest, check xml, check memory + """ + test.log.info("TEST_STEP: Define guest with numa") + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + define_attrs = create_vm_attrs(params) + vmxml.setup_attrs(**define_attrs) + vmxml.sync() + + test.log.info("TEST_STEP: Plug virtio memory devices.") + mem_objs = create_mem_objects(params) + plug_virtio_mem(params, vm, operation, mem_objs) + + test.log.info("TEST_STEP:Login the guest and consume guest memory") + consume_guest_mem(vm, test) + + test.log.info("TEST_STEP: Check the memory usage by virsh freepages") + check_freepages(params, vm, test) + + if case == "no_source_virtio_mem" and numa_tuning != "undefined": + test.log.info("TEST_STEP: Check host numa node memory") + check_numa_memory_allocation(params, test, target_size_1) + + test.log.info("TEST_STEP: Destroy the guest") + virsh.destroy(vm_name, ignore_status=False) + + test.log.info("TEST_STEP: Check freepages after destroying the guest") + all_nodes = params.get("all_nodes") + for node, hp in zip(all_nodes + all_nodes, params.get("hp_list")): + memory_base.compare_values( + test, + expected=params.get("allocate_mem_and_hp_match")[hp]/hp, + actual=_get_freepages(node, hp), + check_item=f"node{node} hugepage size:{hp} free pages number" + ) + + def teardown_test(): + """ + Clean data. + """ + test.log.info("TEST_TEARDOWN: Clean up env.") + bkxml.sync() + for file in params.get("cleanup_file", []): + process.run("echo 0 > %s" % file, ignore_status=True, shell=True) + hg_path = params.get("hg_path") + if hg_path: + process.run("umount %s; rm -r %s" % (hg_path, hg_path), ignore_status=True, shell=True) + + vm_name = params.get("main_vm") + vm = env.get_vm(vm_name) + memory_base.check_supported_version(params, test, vm) + + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + bkxml = vmxml.copy() + case = params.get("case") + numa_tuning = params.get("numa_tuning") + operation = params.get("operation") + target_size_1 = params.get("target_size_1") + + params.update({"numa_obj": numa_base.NumaTest(vm, params, test)}) + default_hp_size, another_hp_size = get_two_hugepage_sizes(test, params) + params.update({"default_hp_size": default_hp_size}) + params.update({"another_hp_size": another_hp_size}) + params.update({"hp_list": [default_hp_size, default_hp_size, + another_hp_size, another_hp_size]}) + + try: + setup_test() + run_test() + + finally: + teardown_test() diff --git a/libvirt/tests/src/memory/memory_misc.py b/libvirt/tests/src/memory/memory_misc.py index f0b7ddf489e..8214a071736 100644 --- a/libvirt/tests/src/memory/memory_misc.py +++ b/libvirt/tests/src/memory/memory_misc.py @@ -14,6 +14,8 @@ from virttest.staging import utils_memory from virttest.utils_test import libvirt +from provider.memory import memory_base + VIRSH_ARGS = {'debug': True, 'ignore_status': False} @@ -176,6 +178,10 @@ def _setup_mbxml(): test.log.debug(virsh.dumpxml(vm_name).stdout_text) if case == 'no_mem_backing': + default_page_size = int(params.get('default_page_size')) + default_hugepage_size = params.get('default_hugepage_size') + memory_base.check_mem_page_sizes( + test, pg_size=default_page_size, hp_size=int(default_hugepage_size)) vm_mem_size = vmxml.memory set_hugepage(vm_mem_size) @@ -190,8 +196,11 @@ def _setup_mbxml(): test.log.debug(virsh.dumpxml(vm_name).stdout_text) if case == 'nodeset_specified': + default_page_size = int(params.get('default_page_size')) pagesize = int(params.get('pagesize')) pagenum = int(params.get('pagenum')) + memory_base.check_mem_page_sizes( + test, pg_size=default_page_size, hp_list=[pagesize]) hp_cfg = test_setup.HugePageConfig(params) params['page_num_bk'] = hp_cfg.get_kernel_hugepages(pagesize) test.log.debug('Current number of pages: %s', params['page_num_bk']) @@ -211,6 +220,9 @@ def _setup_mbxml(): # Setup hugepage pagesize = int(params.get('pagesize')) pagenum = int(params.get('pagenum')) + default_page_size = int(params.get('default_page_size')) + memory_base.check_mem_page_sizes( + test, pg_size=default_page_size, hp_size=pagesize) setup_hugepages(pagesize, pagenum * 2) hp_cfg = test_setup.HugePageConfig(params) @@ -231,7 +243,7 @@ def _setup_mbxml(): if cancel: test.cancel('Setting pagenum of numa nodes failed, ' 'please check log') - + params["hp_cfg"] = hp_cfg # Setup vmxml: Add memory device mem_device = Memory() mem_device_attrs = eval(params.get('mem_device_attrs')) @@ -246,10 +258,17 @@ def _setup_mbxml(): test.log.debug(virsh.dumpxml(vm_name).stdout_text) if case == 'mount_hp_running_vm': + default_page_size = int(params.get('default_page_size')) + pagesize = int(params.get('pagesize')) + mount_pagesize = int(params.get('mount_pagesize')) + mem_device_size = int(params.get('mem_device_size')) + memory_base.check_mem_page_sizes( + test, pg_size=default_page_size, hp_size=pagesize, hp_list=[mount_pagesize]) vm_mem_size = vmxml.memory hp_cfg = test_setup.HugePageConfig(params) - hp_cfg.set_kernel_hugepages(1048576, vm_mem_size // 1048576) - hp_cfg.set_kernel_hugepages(2048, vm_mem_size // 2048) + hp_cfg.set_kernel_hugepages(pagesize, vm_mem_size // pagesize, False) + hp_cfg.set_kernel_hugepages(mount_pagesize, mem_device_size // mount_pagesize, False) + params["hp_cfg"] = hp_cfg set_vmxml(vmxml, params) _setup_mbxml() vmxml.sync() @@ -309,6 +328,9 @@ def run_test_memorybacking(case): if case == 'prealloc_thread': virsh.start(vm_name, ignore_status=False) vm.wait_for_login().close() + nonlocal qemu_check + if scenario == 'memfd_backed': + qemu_check = qemu_check % (utils_memory.get_huge_page_size() * 1024) libvirt.check_qemu_cmd_line(qemu_check) if case == 'no_mem_backing': @@ -386,11 +408,15 @@ def run_test_memorybacking(case): if case == 'mount_hp_running_vm': vm.start() utils_libvirtd.Libvirtd('virtqemud').stop() - hp_path = params.get('hp_path') - if not os.path.exists(hp_path): - os.mkdir(hp_path) - utils_disk.mount('hugetlbfs', hp_path, 'hugetlbfs', - options='pagesize=1G', verbose=True) + mount_path = params.get('mount_path') + mount_option = params.get('mount_option') + + if not os.path.exists(mount_path): + os.mkdir(mount_path) + utils_disk.mount('hugetlbfs', mount_path, 'hugetlbfs', + options=mount_option, verbose=True) + libvirtd = utils_libvirtd.Libvirtd() + libvirtd.restart() vm_state = virsh.domstate(vm_name).stdout_text if 'running' not in vm_state: @@ -405,7 +431,7 @@ def run_test_memorybacking(case): # e.g. 100MiB less than free memory size free_mem = utils_memory.freememtotal(session) test.log.debug('Free mem on vm: %d kB', free_mem) - session.cmd('memhog %dM' % (free_mem // 1024 - 100)) + session.cmd('memhog %dM' % (free_mem // 1024 * 2 // 3)) vm.destroy() utils_libvirtd.Libvirtd('virtqemud').restart() virsh.start(vm_name, **VIRSH_ARGS) @@ -423,11 +449,20 @@ def cleanup_test_memorybacking(case): hp_cfg = test_setup.HugePageConfig(params) hp_cfg.set_kernel_hugepages(pagesize, params['page_num_bk']) if case == 'hp_from_2_numa_nodes': + hp_cfg = params.get("hp_cfg") + if hp_cfg is None: + return restore_hugepages() if case == 'mount_hp_running_vm': - hp_path = params.get('hp_path') - utils_disk.umount('hugetlbfs', hp_path, 'hugetlbfs') - os.rmdir(hp_path) + hp_cfg = params.get("hp_cfg") + if hp_cfg is None: + return + mount_path = params.get('mount_path') + utils_disk.umount('hugetlbfs', mount_path, 'hugetlbfs') + if os.path.exists(mount_path): + os.rmdir(mount_path) + hp_cfg.set_kernel_hugepages(int(params.get('mount_pagesize')), 0) + hp_cfg.cleanup() def run_test_edit_mem(case): """ diff --git a/libvirt/tests/src/memory/memory_tuning/memory_tuning_settings.py b/libvirt/tests/src/memory/memory_tuning/memory_tuning_settings.py new file mode 100644 index 00000000000..0a7aeae965e --- /dev/null +++ b/libvirt/tests/src/memory/memory_tuning/memory_tuning_settings.py @@ -0,0 +1,230 @@ +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Copyright Red Hat +# +# SPDX-License-Identifier: GPL-2.0 +# +# Author: Liang Cong +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +import re + +from virttest import libvirt_cgroup +from virttest import utils_libvirtd +from virttest import virsh + +from virttest.libvirt_xml import vm_xml +from virttest.libvirt_xml import xcepts +from virttest.utils_test import libvirt +from virttest.staging import utils_memory + + +def run(test, params, env): + """ + Verify memory tuning parameters take effect + """ + + def adjust_limit_for_memory_page(limit_dict): + """ + Limit value would be aligned to the default memory page size + + :param params: dict of memory limitation + :return: dict, adjusted memory limitation dict from host page size + """ + default_page_size = utils_memory.getpagesize() + return {key: (value // default_page_size * default_page_size) + if value != -1 else value for key, value in limit_dict.items()} + + def check_limit_by_virsh_memtune(limit_dict): + """ + Check the memtune limit is expected by virsh memtune + + :param params: dict of memory limitation + """ + expected_limit_dict = adjust_limit_for_memory_page(limit_dict) + for key, value in expected_limit_dict.items(): + actual_value = virsh.memtune_get(vm_name, key) + if actual_value != value: + test.fail("memtune limit %s expected %s, but get %s instead" + % (key, value, actual_value)) + + def set_limit_by_virsh_memtune_in_turn(limit_dict): + """ + Set memory limit by virsh memtune one by one + + :param params: dict of memory limitation + """ + vm_pid = vm.get_pid() + cg = libvirt_cgroup.CgroupTest(vm_pid) + for key, value in limit_dict.items(): + options = " --%s %s" % (re.sub('_', '-', key), value) + result = virsh.memtune_set(vm_name, options, debug=True) + if not cg.is_cgroup_v2_enabled() and 'hard_limit' == key and 0 == value: + libvirt.check_result( + result, expected_fails=cgroupv1_error_for_zero_hard_limit) + else: + libvirt.check_exit_status(result) + + def set_limit_by_virsh_memtune_once(limit_dict): + """ + Set memory limit by virsh memtune all together + + :param params: dict of memory limitation + """ + limit_value_list = [str(limit_dict[limit_name]) + for limit_name in memtune_cmd_parameter_seq] + options = " %s" % " ".join(limit_value_list) + virsh.memtune_set(vm_name, options, debug=True, ignore_status=False) + + def check_limit_by_cgroup(limit_dict): + """ + Check the memtune limit is expected by cgroup + + :param params: dict of memory limitation + """ + adjusted_limit_dict = adjust_limit_for_memory_page(limit_dict) + expected_limit_dict = {key: (value*1024) if value != -1 else 'max' + for key, value in adjusted_limit_dict.items()} + vm_pid = vm.get_pid() + cg = libvirt_cgroup.CgroupTest(vm_pid) + limit_cgroup_dict = cg.get_standardized_cgroup_info("memtune") + for key in expected_limit_dict: + if str(expected_limit_dict[key]) != limit_cgroup_dict[key]: + test.fail("cgroup memory limit %s expected %s, but get %s instead" + % (key, expected_limit_dict[key], limit_cgroup_dict[key])) + + def check_limit_by_virsh_dump(limit_dict): + """ + check the memtune limit is expected by virsh dump + + :param params: dict of memory limitation + """ + guest_xml = vm_xml.VMXML.new_from_dumpxml(vm.name) + if len(set(limit_dict.values())) == 1 and list(limit_dict.values())[0] == -1: + try: + if hasattr(guest_xml, "memtune"): + test.fail("memtune should not appear in config xml, " + "but found memtune XML:\n%s" % guest_xml.memtune) + except xcepts.LibvirtXMLNotFoundError as detail: + test.log.debug( + "Did not find the memtune xml, error is:%s", detail) + else: + memtune_element = guest_xml.memtune + for key, value in limit_dict.items(): + if int(getattr(memtune_element, key)) != value: + test.fail("memtune limit %s should be %s " + "in config xml, but found value:%s" + % (key, value, getattr(memtune_element, key))) + + def check_guest_memtune_related_values(limit_dict): + """ + check memtune by cmd virsh memtune, cgroup value and guest config xml + + :param params: dict of memory limitation + """ + test.log.info("Check the memtune value by virsh memtune") + check_limit_by_virsh_memtune(limit_dict) + test.log.info("Check the memtune value by cgroup") + check_limit_by_cgroup(limit_dict) + test.log.info("Check the memtune value by guest config xml") + check_limit_by_virsh_dump(limit_dict) + + def run_test(): + """ + Test steps + """ + + test.log.info("TEST_STEP1: Define the guest") + vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) + vmxml.setup_attrs(**vm_attrs) + virsh.define(vmxml.xml, ignore_status=False, debug=True) + + test.log.info("TEST_STEP2: Start the guest") + if not vm.is_alive(): + vm.start() + vm_pid = vm.get_pid() + cg = libvirt_cgroup.CgroupTest(vm_pid) + + test.log.info("TEST_STEP3: Check the memtune setting") + if "minus" == test_target: + expected_limit_dict = init_limit_dict + else: + expected_limit_dict = max_limit_dict + check_limit_by_virsh_memtune(expected_limit_dict) + + test.log.info("TEST_STEP4: Change the memtune settings one by one") + set_limit_by_virsh_memtune_in_turn(target_limit_dict) + + test.log.info("TEST_STEP5: Check the guest status") + if 'zero' == test_target: + vm.wait_for_shutdown(shutdown_timeout) + actual_state = virsh.domstate( + vm_name, "--reason", debug=True).stdout.strip() + if 'zero' == test_target: + expected_state = "shut off (crashed)" if cg.is_cgroup_v2_enabled( + ) else "running (booted)" + else: + expected_state = "running (booted)" + if expected_state != actual_state: + test.fail("Guest state should be '%s', " + "but get %s instead" % (expected_state, actual_state)) + + if 'zero' != test_target: + test.log.info("TEST_STEP6: For scenarios with running guest, " + "check the memtune values") + check_limit_by_virsh_memtune(target_limit_dict) + + test.log.info("TEST_STEP7: For scenarios with running guest, " + "check the cgroup settings") + check_limit_by_cgroup(target_limit_dict) + + test.log.info("TEST_STEP8: For scenarios with running guest, " + "destroy and start the guest") + vm.destroy() + vm.start() + + test.log.info("TEST_STEP9: For scenarios with running guest, " + "change the memtune setting all together") + set_limit_by_virsh_memtune_once(target_limit_dict) + + test.log.info("TEST_STEP10-12: For scenarios with running guest, " + "check the memtune values") + check_guest_memtune_related_values(target_limit_dict) + + test.log.info("TEST_STEP13: For scenarios with running guest, " + "restart the libvirt daemon") + utils_libvirtd.libvirtd_restart() + + test.log.info("TEST_STEP14: For scenarios with running guest, " + "check the memtune values") + check_guest_memtune_related_values(target_limit_dict) + + def teardown_test(): + """ + Restore guest config xml. + """ + test.log.info("TEST_TEARDOWN: Restore guest config xml.") + bkxml.sync() + + vm_name = params.get('main_vm') + vm = env.get_vm(vm_name) + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + bkxml = vmxml.copy() + vm_attrs = eval(params.get('vm_attrs', '{}')) + test_target = params.get('test_target') + max_limit_dict = eval(params.get('max_limit_dict', '{}')) + init_limit_dict = eval(params.get('init_limit_dict', '{}')) + target_limit_dict = eval(params.get('target_limit_dict', '{}')) + memtune_cmd_parameter_seq = eval( + params.get('memtune_cmd_parameter_seq', '[]')) + cgroupv1_error_for_zero_hard_limit = params.get( + 'cgroupv1_error_for_zero_hard_limit', '') + shutdown_timeout = int(params.get('shutdown_timeout', 0)) + + try: + run_test() + + finally: + teardown_test() diff --git a/libvirt/tests/src/memory/nvdimm.py b/libvirt/tests/src/memory/nvdimm.py index 3eba7f00873..e6ca6a6d66f 100644 --- a/libvirt/tests/src/memory/nvdimm.py +++ b/libvirt/tests/src/memory/nvdimm.py @@ -13,6 +13,7 @@ from virttest.libvirt_xml import vm_xml from virttest.libvirt_xml.devices import memory from virttest.utils_test import libvirt +from virttest.utils_libvirt import libvirt_disk # Using as lower capital is not the best way to do, but this is just a @@ -132,6 +133,18 @@ def check_nvdimm_file(test_str, file_name, vm_session, test): test.fail('"%s" should be in output' % test_str) +def is_pmem_supported(params): + """ + check if pmem is supported by qemu-kvm + + :param params: dict, test parameters + :return: whether pmem is supported + """ + pmem_support_check_cmd = params.get('pmem_support_check_cmd') + cmd_result = process.run(pmem_support_check_cmd, ignore_status=True, shell=True) + return not cmd_result.exit_status + + def setup_test_pmem_alignsize(guest_xml, params): """ Setup steps for pmem and alignsize test @@ -142,6 +155,10 @@ def setup_test_pmem_alignsize(guest_xml, params): """ vm_attrs = eval(params.get('vm_attrs', '{}')) mem_device_attrs = eval(params.get('mem_device_attrs', '{}')) + if not is_pmem_supported(params): + mem_device_attrs['source']['pmem'] = False + params.update({'qemu_checks': params.get('qemu_checks').replace('pmem', '')}) + if vm_attrs: guest_xml.setup_attrs(**vm_attrs) if mem_device_attrs: @@ -339,9 +356,30 @@ def test_with_label(vm, params, test): vm_session = vm.wait_for_login() check_nvdimm_file(test_str, test_file, vm_session, test) vm_session.close() - virsh.snapshot_create_as(vm_name, vm_s1, ignore_status=False, debug=True) - virsh.snapshot_revert(vm_name, vm_s1, ignore_status=False, debug=True) - virsh.snapshot_delete(vm_name, vm_s1, ignore_status=False, debug=True) + virsh.snapshot_create_as(vm_name, "%s --disk-only" % vm_s1, + ignore_status=False, debug=True) + revert_result = virsh.snapshot_revert(vm_name, vm_s1, debug=True) + if libvirt_version.version_compare(9, 9, 0): + libvirt.check_exit_status(revert_result) + else: + libvirt.check_result( + revert_result, + expected_fails=[ + params.get('error_msg_1'), + params.get('error_msg_2') + ] + ) + + if libvirt_version.version_compare(9, 9, 0): + virsh.snapshot_delete(vm_name, vm_s1, + ignore_status=False, debug=True) + else: + virsh.snapshot_delete(vm_name, + "%s --metadata" % vm_s1, + ignore_status=False, debug=True) + snap_file_path = libvirt_disk.get_first_disk_source(vm) + if os.path.exists(snap_file_path): + os.remove(snap_file_path) def test_hotplug(vm, params, test): diff --git a/libvirt/tests/src/memory/secure_dump.py b/libvirt/tests/src/memory/secure_dump.py new file mode 100644 index 00000000000..32bf9dfbc99 --- /dev/null +++ b/libvirt/tests/src/memory/secure_dump.py @@ -0,0 +1,83 @@ +import logging as log +import os + +from virttest.utils_misc import cmd_status_output +from virttest import virsh + +logging = log.getLogger('avocado.' + __name__) +cleanup = [] + + +def get_kernel_cmdline(vm): + """ + Returns /proc/cmdline + + :param vm: VM instance + """ + with vm.wait_for_login() as session: + _, o = cmd_status_output("cat /proc/cmdline", + session=session, + ignore_status=False, + shell=True) + return o.strip() + + +def decrypt(dump_file, decrypted_dump_dir, comm_key): + """ + Decrypt the dumped file with a communication key. + + :param dump_file: path to the memory dump + :param decrypted_dump_dir: where to mount the decrypted + dump + :param comm_key: string with the communication key + """ + cmd = "echo %s > %s" % (comm_key, "comm_key.txt") + cmd_status_output(cmd, ignore_status=False, shell=True) + cmd = "zgetdump -k comm_key.txt %s -m %s" % (dump_file, decrypted_dump_dir) + cmd_status_output(cmd, ignore_status=False, shell=True) + cleanup.append(lambda: cmd_status_output("umount %s" % decrypted_dump_dir)) + + +def confirm_contains(decrypted_dump_file, text, test): + """ + Confirm that given text can be found in file. + This confirms the file has been decrypted correctly. + + :param decrypted_dump_file: The path of the .elf file + of the decrypted dump + :param text: string to be found + :param test: test instance + """ + s, _ = cmd_status_output("strings -d %s|grep -m 1 '%s'" % (decrypted_dump_file, text), + shell=True) + if s: + test.fail("Couldn't find expected text in dump file.") + + +def run(test, params, env): + """ + Decrypt encrypted memory dump. + Assumes the guest is running in with + SE and has been encrypted with the tested + communication key. + """ + + vm_name = params.get('main_vm') + vm = env.get_vm(vm_name) + comm_key = params.get("comm_key") + dump_file = "/tmp/DUMP" + decrypted_dump_dir = "/mnt" + decrypted_dump_file = os.path.join(decrypted_dump_dir, "dump.elf") + + try: + cmdline = get_kernel_cmdline(vm) + virsh.dump(vm_name, dump_file, "--memory-only", + ignore_status=False, debug=True) + cleanup.append(lambda: os.remove(dump_file)) + + decrypt(dump_file, decrypted_dump_dir, comm_key) + confirm_contains(decrypted_dump_file, cmdline, test) + + finally: + for c in reversed(cleanup): + c() diff --git a/libvirt/tests/src/virsh_cmd/domain/virsh_setmem.py b/libvirt/tests/src/memory/virsh_setmem.py similarity index 68% rename from libvirt/tests/src/virsh_cmd/domain/virsh_setmem.py rename to libvirt/tests/src/memory/virsh_setmem.py index 0d5140b8e7b..74d1f04a741 100644 --- a/libvirt/tests/src/virsh_cmd/domain/virsh_setmem.py +++ b/libvirt/tests/src/memory/virsh_setmem.py @@ -1,20 +1,25 @@ import re import os import logging as log +import platform import time from virttest import virsh from virttest import utils_libvirtd from virttest import data_dir from virttest import utils_misc +from virttest import utils_package from virttest import libvirt_version from virttest.utils_test import libvirt from virttest.libvirt_xml import vm_xml +from virttest.staging import utils_memory + +from provider.memory import memory_base # Using as lower capital is not the best way to do, but this is just a # workaround to avoid changing the entire file. -logging = log.getLogger('avocado.' + __name__) +logging = log.getLogger("avocado." + __name__) def manipulate_domain(test, vm_name, action, recover=False): @@ -26,23 +31,27 @@ def manipulate_domain(test, vm_name, action, recover=False): if not recover: if action == "save": save_option = "" - result = virsh.save(vm_name, save_file, save_option, - ignore_status=True, debug=True) + result = virsh.save( + vm_name, save_file, save_option, ignore_status=True, debug=True + ) libvirt.check_exit_status(result) elif action == "managedsave": managedsave_option = "" - result = virsh.managedsave(vm_name, managedsave_option, - ignore_status=True, debug=True) + result = virsh.managedsave( + vm_name, managedsave_option, ignore_status=True, debug=True + ) libvirt.check_exit_status(result) elif action == "s3": suspend_target = "mem" - result = virsh.dompmsuspend(vm_name, suspend_target, - ignore_status=True, debug=True) + result = virsh.dompmsuspend( + vm_name, suspend_target, ignore_status=True, debug=True + ) libvirt.check_exit_status(result) elif action == "s4": suspend_target = "disk" - result = virsh.dompmsuspend(vm_name, suspend_target, - ignore_status=True, debug=True) + result = virsh.dompmsuspend( + vm_name, suspend_target, ignore_status=True, debug=True + ) libvirt.check_exit_status(result) # Wait domain state change: 'in shutdown' -> 'shut off' utils_misc.wait_for(lambda: virsh.is_dead(vm_name), 5) @@ -86,8 +95,7 @@ def get_vm_usable_mem(session): """ cmd = "cat /proc/meminfo" proc_mem = session.cmd_output(cmd) - total_usable_mem = re.search(r'MemTotal:\s+(\d+)\s+[kK]B', - proc_mem).group(1) + total_usable_mem = re.search(r"MemTotal:\s+(\d+)\s+[kK]B", proc_mem).group(1) return int(total_usable_mem) def vm_unusable_mem(session): @@ -97,18 +105,42 @@ def vm_unusable_mem(session): # Get total physical memory from dmidecode cmd = "dmidecode -t 17" dmi_mem = session.cmd_output(cmd) - dmi_mem_size = re.findall(r'Size:\s(\d+\s+[K|M|G]B)', dmi_mem) + dmi_mem_size = re.findall(r"Size:\s(\d+\s+[K|M|G]B)", dmi_mem) if not dmi_mem_size: test.fail("Cannot get memory size info inside VM.") total_physical_mem = 0 for size_info in dmi_mem_size: mem_size = int(size_info.split()[0].strip()) mem_unit = size_info.split()[1].strip() - if mem_unit.lower() == 'kb': + if mem_unit.lower() == "kb": total_physical_mem += mem_size - elif mem_unit.lower() == 'mb': + elif mem_unit.lower() == "mb": total_physical_mem += mem_size * 1024 - elif mem_unit.lower() == 'gb': + elif mem_unit.lower() == "gb": + total_physical_mem += mem_size * 1048576 + return total_physical_mem - get_vm_usable_mem(session) + + def vm_unusable_mem_ppc64(session): + """ + Get the unusable RAM of the VM for Arch PPC64. + """ + # Get total physical memory from lshw + cmd = "lshw -C memory" + lshw_mem = session.cmd_output(cmd) + lshw_mem_size = re.findall(r'\*-\s*memory\s*[\s\S]*?size:\s*(\d+[K|M|G]iB)', lshw_mem) + if not lshw_mem_size: + test.fail("Cannot get memory size info inside VM.") + total_physical_mem = 0 + for mem in lshw_mem_size: + size_value = re.match(r'(\d+)\s*([K|M|G]iB)', mem) + if size_value: + mem_size = int(size_value.group(1)) # Convert the numeric part to an integer + mem_unit = size_value.group(2) + if mem_unit.lower() == "kib": + total_physical_mem += mem_size + elif mem_unit.lower() == "mib": + total_physical_mem += mem_size * 1024 + elif mem_unit.lower() == "gib": total_physical_mem += mem_size * 1048576 return total_physical_mem - get_vm_usable_mem(session) @@ -172,6 +204,7 @@ def cal_deviation(actual, expected): """ Calculate deviation of actual result and expected result """ + logging.debug(f"(actual, expected) = ({actual}, {expected})") numerator = float(actual) denominator = float(expected) if numerator > denominator: @@ -183,39 +216,49 @@ def is_old_libvirt(): """ Check if libvirt is old version """ - regex = r'\s+\[--size\]\s+' - return bool(not virsh.has_command_help_match('setmem', regex)) - - def print_debug_stats(original_inside_mem, original_outside_mem, - test_inside_mem, test_outside_mem, - expected_outside_mem, expected_inside_mem, - delta_percentage, unusable_mem): + regex = r"\s+\[--size\]\s+" + return bool(not virsh.has_command_help_match("setmem", regex)) + + def print_debug_stats( + original_inside_mem, + original_outside_mem, + test_inside_mem, + test_outside_mem, + expected_outside_mem, + expected_inside_mem, + delta_percentage, + unusable_mem, + ): """ Print debug message for test """ # Calculate deviation inside_deviation = cal_deviation(test_inside_mem, expected_inside_mem) outside_deviation = cal_deviation(test_outside_mem, expected_outside_mem) - dbgmsg = ("Unusable memory of VM : %d KiB\n" - "Original inside memory : %d KiB\n" - "Expected inside memory : %d KiB\n" - "Actual inside memory : %d KiB\n" - "Inside memory deviation : %0.2f%%\n" - "Original outside memory : %d KiB\n" - "Expected outside memory : %d KiB\n" - "Actual outside memory : %d KiB\n" - "Outside memory deviation: %0.2f%%\n" - "Acceptable deviation : %0.2f%%" % ( - unusable_mem, - original_inside_mem, - expected_inside_mem, - test_inside_mem, - inside_deviation, - original_outside_mem, - expected_outside_mem, - test_outside_mem, - outside_deviation, - delta_percentage)) + dbgmsg = ( + "Unusable memory of VM : %d KiB\n" + "Original inside memory : %d KiB\n" + "Expected inside memory : %d KiB\n" + "Actual inside memory : %d KiB\n" + "Inside memory deviation : %0.2f%%\n" + "Original outside memory : %d KiB\n" + "Expected outside memory : %d KiB\n" + "Actual outside memory : %d KiB\n" + "Outside memory deviation: %0.2f%%\n" + "Acceptable deviation : %0.2f%%" + % ( + unusable_mem, + original_inside_mem, + expected_inside_mem, + test_inside_mem, + inside_deviation, + original_outside_mem, + expected_outside_mem, + test_outside_mem, + outside_deviation, + delta_percentage, + ) + ) for dbgline in dbgmsg.splitlines(): logging.debug(dbgline) @@ -235,9 +278,11 @@ def print_debug_stats(original_inside_mem, original_outside_mem, vm_name = params.get("main_vm", "avocado-vt-vm1") paused_after_start_vm = "yes" == params.get("paused_after_start_vm", "no") manipulate_dom_before_setmem = "yes" == params.get( - "manipulate_dom_before_setmem", "no") + "manipulate_dom_before_setmem", "no" + ) manipulate_dom_after_setmem = "yes" == params.get( - "manipulate_dom_after_setmem", "no") + "manipulate_dom_after_setmem", "no" + ) manipulate_action = params.get("manipulate_action", "") readonly = "yes" == params.get("setmem_readonly", "no") expect_msg = params.get("setmem_err_msg") @@ -245,19 +290,45 @@ def print_debug_stats(original_inside_mem, original_outside_mem, with_packed = "yes" == params.get("with_packed", "no") expect_xml_line = params.get("expect_xml_line") expect_qemu_line = params.get("expect_qemu_line") + reset_vm_memory = "yes" == params.get("reset_vm_memory", "no") + use_pkg = "yes" == params.get("use_dmidecode", "yes") + arch = platform.machine() vm = env.get_vm(vm_name) # Back up domain XML vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) backup_xml = vmxml.copy() + # filter out reset vm memory on s390x + if reset_vm_memory: + vm_attrs = eval(params.get("vm_attrs")) + memory_size = vm_attrs["memory"] + memory_unit = vm_attrs["memory_unit"] + guest_memory = memory_base.convert_data_size( + str(memory_size) + memory_unit, dest_unit="KiB" + ) + host_free_mem = utils_memory.freememtotal() + logging.debug( + "The allocation memory for guest is %sKiB," + " the total free memory of host is %sKiB.", + guest_memory, + host_free_mem, + ) + if host_free_mem < guest_memory: + test.cancel("There is not enough memory for guest.") + + vmxml.setup_attrs(**vm_attrs) + vmxml.sync() + if with_packed and not libvirt_version.version_compare(6, 3, 0): - test.cancel("The virtio packed attribute is not supported in" - " current libvirt version.") + test.cancel( + "The virtio packed attribute is not supported in" + " current libvirt version." + ) vmosxml = vmxml.os need_mkswap = False - if manipulate_action in ['s3', 's4']: + if manipulate_action in ["s3", "s4"]: vm.destroy() BIOS_BIN = "/usr/share/seabios/bios.bin" if os.path.isfile(BIOS_BIN): @@ -277,8 +348,8 @@ def print_debug_stats(original_inside_mem, original_outside_mem, memballoon_model = params.get("memballoon_model", "") if memballoon_model: vm.destroy() - vmxml.del_device('memballoon', by_tag=True) - memballoon_xml = vmxml.get_device_class('memballoon')() + vmxml.del_device("memballoon", by_tag=True) + memballoon_xml = vmxml.get_device_class("memballoon")() memballoon_xml.model = memballoon_model if with_packed: memballoon_xml.driver = {"packed": driver_packed} @@ -301,8 +372,9 @@ def print_debug_stats(original_inside_mem, original_outside_mem, cmd = "rmmod virtio_balloon" s_rmmod, o_rmmod = session.cmd_status_output(cmd) if s_rmmod != 0: - logging.error("Fail to remove module virtio_balloon in guest:\n%s", - o_rmmod) + logging.error( + "Fail to remove module virtio_balloon in guest:\n%s", o_rmmod + ) session.close() # Get original data domid = vm.get_id() @@ -311,12 +383,26 @@ def print_debug_stats(original_inside_mem, original_outside_mem, if not vm.is_alive(): vm.start() session = vm.wait_for_login() - if session.cmd_status('dmidecode'): - # The physical memory size is in vm xml, use it when dmidecode not - # supported - unusable_mem = int(vmxml.max_mem) - get_vm_usable_mem(session) + if arch != "ppc64le": + if use_pkg: + # try make dmidecode or lshw available if not present + use_pkg &= 0 == session.cmd_status( + "dmidecode" + ) or utils_package.package_install("dmidecode", session) + if use_pkg: + unusable_mem = vm_unusable_mem(session) + else: + unusable_mem = int(vmxml.memory) - get_vm_usable_mem(session) else: - unusable_mem = vm_unusable_mem(session) + if use_pkg: + # try make dmidecode or lshw available if not present + use_pkg &= 0 == session.cmd_status( + "lshw" + ) or utils_package.package_install("lshw", session) + if use_pkg: + unusable_mem = vm_unusable_mem_ppc64(session) + else: + unusable_mem = int(vmxml.memory) - get_vm_usable_mem(session) original_outside_mem = vm.get_used_mem() original_inside_mem = get_vm_usable_mem(session) session.close() @@ -335,10 +421,14 @@ def print_debug_stats(original_inside_mem, original_outside_mem, use_kilobytes = False # Argument pattern is complex, build with dargs - dargs = {'flagstr': flags, - 'use_kilobytes': use_kilobytes, - 'uri': uri, 'ignore_status': True, "debug": True, - 'readonly': readonly} + dargs = { + "flagstr": flags, + "use_kilobytes": use_kilobytes, + "uri": uri, + "ignore_status": True, + "debug": True, + "readonly": readonly, + } dargs.update(make_domref(domarg, vm_ref, domid, vm_name, domuuid)) dargs.update(make_sizeref(sizearg, mem_ref, original_outside_mem)) @@ -357,15 +447,14 @@ def print_debug_stats(original_inside_mem, original_outside_mem, memory_change = True if manipulate_dom_before_setmem: manipulate_domain(test, vm_name, manipulate_action) - if manipulate_action in ['save', 'managedsave', 's4']: + if manipulate_action in ["save", "managedsave", "s4"]: memory_change = False result = virsh.setmem(**dargs) status = result.exit_status if status is 0: - logging.info( - "Waiting %d seconds for VM memory to settle", quiesce_delay) + logging.info("Waiting %d seconds for VM memory to settle", quiesce_delay) # It takes time for kernel to settle on new memory # and current clean pages is not predictable. Therefore, # extremely difficult to determine quiescence, so @@ -427,11 +516,17 @@ def get_vm_mem(): # Don't care about memory comparison on error test def verify_outside_result(): _, test_outside_mem = get_vm_mem() - return (cal_deviation(test_outside_mem, expected_outside_mem) <= delta_percentage) + return ( + cal_deviation(test_outside_mem, expected_outside_mem) + <= delta_percentage + ) def verify_inside_result(): test_inside_mem, _ = get_vm_mem() - return (cal_deviation(test_inside_mem, expected_inside_mem) <= delta_percentage) + return ( + cal_deviation(test_inside_mem, expected_inside_mem) + <= delta_percentage + ) msg = "test conditions not met: " error_flag = 0 @@ -446,10 +541,16 @@ def verify_inside_result(): msg += "Inside memory deviated. " test_inside_mem, test_outside_mem = get_vm_mem() - print_debug_stats(original_inside_mem, original_outside_mem, - test_inside_mem, test_outside_mem, - expected_outside_mem, expected_inside_mem, - delta_percentage, unusable_mem) + print_debug_stats( + original_inside_mem, + original_outside_mem, + test_inside_mem, + test_outside_mem, + expected_outside_mem, + expected_inside_mem, + delta_percentage, + unusable_mem, + ) if error_flag: test.fail(msg) elif not status_error and old_libvirt_fail: @@ -463,7 +564,7 @@ def verify_inside_result(): if status is 0: test.fail("Error test did not result in an error") if expect_msg: - libvirt.check_result(result, expect_msg.split(';')) + libvirt.check_result(result, expect_msg.split(";")) finally: if need_mkswap: vm.cleanup_swap() diff --git a/libvirt/tests/src/migration/abort_precopy_migration/abort_by_domjobabort_on_target.py b/libvirt/tests/src/migration/abort_precopy_migration/abort_by_domjobabort_on_target.py index 7793d3d08b6..5420665be62 100644 --- a/libvirt/tests/src/migration/abort_precopy_migration/abort_by_domjobabort_on_target.py +++ b/libvirt/tests/src/migration/abort_precopy_migration/abort_by_domjobabort_on_target.py @@ -1,3 +1,5 @@ +from virttest import libvirt_version + from provider.migration import base_steps @@ -11,6 +13,8 @@ def run(test, params, env): """ vm_name = params.get("migrate_main_vm") + libvirt_version.is_libvirt_feature_supported(params) + vm = env.get_vm(vm_name) migration_obj = base_steps.MigrationBase(test, vm, params) diff --git a/libvirt/tests/src/migration/async_job/async_job.py b/libvirt/tests/src/migration/async_job/async_job.py new file mode 100644 index 00000000000..c0a8c885405 --- /dev/null +++ b/libvirt/tests/src/migration/async_job/async_job.py @@ -0,0 +1,23 @@ +from provider.migration import base_steps + + +def run(test, params, env): + """ + Test async job: + + 1. abort_migration_with_wrong_api_flag case: To verify that precopy + migration can't be aborted by domjobabort with --postcopy, postcopy + migration can't be aborted by domjobabort without --postcopy. + + """ + vm_name = params.get("migrate_main_vm") + + vm = env.get_vm(vm_name) + migration_obj = base_steps.MigrationBase(test, vm, params) + + try: + migration_obj.setup_connection() + migration_obj.run_migration() + migration_obj.verify_default() + finally: + migration_obj.cleanup_connection() diff --git a/libvirt/tests/src/migration/async_job/migration_domjobinfo.py b/libvirt/tests/src/migration/async_job/migration_domjobinfo.py index 434a7873e70..6a6cea9f17e 100644 --- a/libvirt/tests/src/migration/async_job/migration_domjobinfo.py +++ b/libvirt/tests/src/migration/async_job/migration_domjobinfo.py @@ -16,12 +16,18 @@ def verify_test(): Verify steps """ - expected_domjobinfo_complete = params.get("expected_domjobinfo_complete") + expected_domjobinfo_complete = eval(params.get("expected_domjobinfo_complete")) + remote_ip = params.get("server_ip") + postcopy_options = params.get("postcopy_options") + test.log.info("Verify test.") migration_obj.verify_default() if expected_domjobinfo_complete: - params.update({"domjobinfo_options": "--completed"}) - libvirt_monitor.check_domjobinfo_output(params) + libvirt_monitor.check_domjobinfo_output(vm_name, + expected_domjobinfo_complete=expected_domjobinfo_complete, + options="--completed", + postcopy_options=postcopy_options, + remote_ip=remote_ip) vm_name = params.get("migrate_main_vm") diff --git a/libvirt/tests/src/migration/async_ops/destroy_vm_during_finishphase.py b/libvirt/tests/src/migration/async_ops/destroy_vm_during_finishphase.py new file mode 100644 index 00000000000..661ce0f0925 --- /dev/null +++ b/libvirt/tests/src/migration/async_ops/destroy_vm_during_finishphase.py @@ -0,0 +1,63 @@ +from virttest import utils_misc +from virttest import virsh + +from virttest.utils_test import libvirt + +from provider.migration import base_steps +from provider.migration import migration_base + + +def run(test, params, env): + """ + This case is to verify that if destroying vm during FinishPhase of postcopy + migration, migration will fail. + + :param test: test object + :param params: Dictionary with the test parameters + :param env: Dictionary with test environment. + """ + def verify_test(): + """ + Verify steps + """ + expected_dest_state = params.get("expected_dest_state") + expected_src_state = params.get("expected_src_state") + dest_uri = params.get("virsh_migrate_desturi") + + test.log.info("Verify steps.") + if expected_src_state: + if not libvirt.check_vm_state(vm.name, expected_src_state, uri=migration_obj.src_uri): + test.fail("Check vm state on source host fail.") + if expected_dest_state: + if expected_dest_state == "nonexist": + dest_vm_list = virsh.dom_list(options="--all --persistent", debug=True, uri=dest_uri) + if vm_name in dest_vm_list.stdout.strip(): + test.fail("%s should not exist." % vm_name) + else: + if not libvirt.check_vm_state(vm.name, expected_dest_state, uri=dest_uri): + test.fail("Check vm state on target host fail.") + if expected_dest_state == "running": + virsh.destroy(vm_name, uri=dest_uri) + utils_misc.wait_for(lambda: virsh.domain_exists(vm_name, uri=dest_uri), 10) + vm.destroy() + vm.start() + vm.wait_for_login().close() + + vm_name = params.get("migrate_main_vm") + + virsh_session = None + remote_virsh_session = None + + vm = env.get_vm(vm_name) + migration_obj = base_steps.MigrationBase(test, vm, params) + + try: + migration_obj.setup_connection() + virsh_session, remote_virsh_session = migration_base.monitor_event(params) + migration_obj.run_migration() + verify_test() + migration_obj.run_migration_again() + migration_obj.verify_default() + migration_base.check_event_output(params, test, virsh_session, remote_virsh_session) + finally: + migration_obj.cleanup_connection() diff --git a/libvirt/tests/src/migration/async_ops/destroy_vm_during_performphase.py b/libvirt/tests/src/migration/async_ops/destroy_vm_during_performphase.py new file mode 100644 index 00000000000..96b9d88a7bd --- /dev/null +++ b/libvirt/tests/src/migration/async_ops/destroy_vm_during_performphase.py @@ -0,0 +1,53 @@ +from virttest import virsh + +from virttest.utils_test import libvirt + +from provider.migration import base_steps +from provider.migration import migration_base + + +def run(test, params, env): + """ + This case is to verify that if destroying vm during PerformPhase of precopy + migration, migration will fail. + + :param test: test object + :param params: Dictionary with the test parameters + :param env: Dictionary with test environment. + """ + def verify_test(): + """ + Verify steps + """ + expected_dest_state = params.get("expected_dest_state") + expected_src_state = params.get("expected_src_state") + dest_uri = params.get("virsh_migrate_desturi") + + test.log.info("Verify steps.") + if not libvirt.check_vm_state(vm.name, expected_src_state, uri=migration_obj.src_uri): + test.fail(f"Check of expected VM state ({expected_src_state}) on source host failed.") + dest_vm_list = virsh.dom_list(options="--all --persistent", debug=True, uri=dest_uri) + if expected_dest_state == "nonexist": + if vm_name in dest_vm_list.stdout.strip(): + test.fail("%s should not exist." % vm_name) + + vm_name = params.get("migrate_main_vm") + migrate_again = "yes" == params.get("migrate_again", "no") + + virsh_session = None + remote_virsh_session = None + + vm = env.get_vm(vm_name) + migration_obj = base_steps.MigrationBase(test, vm, params) + + try: + migration_obj.setup_connection() + virsh_session, remote_virsh_session = migration_base.monitor_event(params) + migration_obj.run_migration() + verify_test() + if migrate_again: + migration_obj.run_migration_again() + migration_obj.verify_default() + migration_base.check_event_output(params, test, virsh_session, remote_virsh_session) + finally: + migration_obj.cleanup_connection() diff --git a/libvirt/tests/src/migration/async_ops/migrate_vm_again_during_migration.py b/libvirt/tests/src/migration/async_ops/migrate_vm_again_during_migration.py new file mode 100644 index 00000000000..77024c3184e --- /dev/null +++ b/libvirt/tests/src/migration/async_ops/migrate_vm_again_during_migration.py @@ -0,0 +1,23 @@ +from provider.migration import base_steps + + +def run(test, params, env): + """ + To verify that libvirt can report clear error when migrating vm again + before the last migration completes. + + :param test: test object + :param params: Dictionary with the test parameters + :param env: Dictionary with test environment. + """ + vm_name = params.get("migrate_main_vm") + + vm = env.get_vm(vm_name) + migration_obj = base_steps.MigrationBase(test, vm, params) + + try: + migration_obj.setup_connection() + migration_obj.run_migration() + migration_obj.verify_default() + finally: + migration_obj.cleanup_connection() diff --git a/libvirt/tests/src/migration/async_ops/pause_resume_vm_during_migration.py b/libvirt/tests/src/migration/async_ops/pause_resume_vm_during_migration.py new file mode 100644 index 00000000000..75311f3e2c4 --- /dev/null +++ b/libvirt/tests/src/migration/async_ops/pause_resume_vm_during_migration.py @@ -0,0 +1,31 @@ +from provider.migration import base_steps +from provider.migration import migration_base + + +def run(test, params, env): + """ + This case is to verify that during migration, vm: + can be paused by user on src host during PerformPhase of precopy + can't be resumed by user on src/target host during PerformPhase of precopy + can't be paused by user on target host during FinishPhase of postcopy + can't be resumed by user on src host during FinishPhase of postcopy + + :param test: test object + :param params: Dictionary with the test parameters + :param env: Dictionary with test environment. + """ + vm_name = params.get("migrate_main_vm") + + virsh_session = None + + vm = env.get_vm(vm_name) + migration_obj = base_steps.MigrationBase(test, vm, params) + + try: + migration_obj.setup_connection() + virsh_session, _ = migration_base.monitor_event(params) + migration_obj.run_migration() + migration_obj.verify_default() + migration_base.check_event_output(params, test, virsh_session) + finally: + migration_obj.cleanup_connection() diff --git a/libvirt/tests/src/migration/async_ops/query_info_during_migration.py b/libvirt/tests/src/migration/async_ops/query_info_during_migration.py new file mode 100644 index 00000000000..cd99b0171c3 --- /dev/null +++ b/libvirt/tests/src/migration/async_ops/query_info_during_migration.py @@ -0,0 +1,86 @@ +from avocado.utils import process + +from virttest import remote +from virttest import virsh + +from virttest.utils_test import libvirt + +from provider.migration import base_steps + +source_loop_dev = None +target_loop_dev = None + + +def run(test, params, env): + """ + This case is to verify that readonly commands domblkinfo/domblklist/domstats/dommemstat + can be executed during migration. + + :param test: test object + :param params: Dictionary with the test parameters + :param env: Dictionary with test environment. + """ + def setup_test(): + """ + Setup steps + + """ + def _setup_loop_dev(remote_host=False): + """ + Setup a loop device for test + + :param remote_host: If True, set loop device on remote host + """ + loop_dev = None + cmd = "losetup --find" + if remote_host: + loop_dev = remote.run_remote_cmd(cmd, params, ignore_status=False).stdout_text.strip() + else: + loop_dev = process.run(cmd, shell=True).stdout_text.strip() + test.log.debug(f"loop dev: {loop_dev}") + + cmd = f"losetup {loop_dev} {block_device}" + if remote_host: + remote.run_remote_cmd(cmd, params, ignore_status=False) + else: + process.run(cmd, shell=True) + return loop_dev + + target_dev = params.get("target_dev") + block_device = params.get("block_device") + + migration_obj.setup_connection() + libvirt.create_local_disk("file", block_device, '1', "qcow2") + + global source_loop_dev + source_loop_dev = _setup_loop_dev() + global target_loop_dev + target_loop_dev = _setup_loop_dev(remote_host=True) + + ret = virsh.attach_disk(vm_name, source_loop_dev, target_dev, debug=True) + libvirt.check_exit_status(ret) + + def cleanup_test(): + """ + Cleanup steps + + """ + migration_obj.cleanup_connection() + global source_loop_dev + if source_loop_dev: + process.run(f"losetup -d {source_loop_dev}", shell=True) + global target_loop_dev + if target_loop_dev: + remote.run_remote_cmd(f"losetup -d {target_loop_dev}", 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() + migration_obj.verify_default() + finally: + cleanup_test() diff --git a/libvirt/tests/src/migration/destructive_operations_around_live_migration/kill_qemu_during_finishphase.py b/libvirt/tests/src/migration/destructive_operations_around_live_migration/kill_qemu_during_finishphase.py new file mode 100644 index 00000000000..8436ff452de --- /dev/null +++ b/libvirt/tests/src/migration/destructive_operations_around_live_migration/kill_qemu_during_finishphase.py @@ -0,0 +1,76 @@ +from virttest import virsh + +from virttest.utils_test import libvirt + +from provider.migration import base_steps +from provider.migration import migration_base + + +def run(test, params, env): + """ + This case is to verify that if killing qemu process during FinishPhase of + postcopy migration, migration will fail. + + :param test: test object + :param params: Dictionary with the test parameters + :param env: Dictionary with test environment. + """ + 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) + 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: + if 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") + else: + if not libvirt.check_vm_state(vm.name, expected_dest_state, uri=dest_uri): + test.fail("Migrated VM failed to be in %s state at dest." % expected_dest_state) + + if expected_dest_state == "running": + virsh.destroy(vm_name, uri=dest_uri) + if expected_src_state == "shut off": + vm.start() + vm.wait_for_login().close() + elif expected_src_state == "paused": + vm.destroy() + vm.start() + vm.wait_for_login().close() + + vm_name = params.get("migrate_main_vm") + test_case = params.get("test_case", "") + migrate_again = "yes" == params.get("migrate_again", "no") + + virsh_session = None + remote_virsh_session = None + + vm = env.get_vm(vm_name) + migration_obj = base_steps.MigrationBase(test, vm, params) + setup_test = eval("setup_%s" % test_case) if "setup_%s" % test_case in \ + locals() else migration_obj.setup_connection + migration_test_again = eval("migration_%s_again" % test_case) if "migration_%s_again" % test_case in \ + locals() else migration_obj.run_migration_again + + try: + setup_test() + virsh_session, remote_virsh_session = migration_base.monitor_event(params) + migration_obj.run_migration() + verify_test() + migration_base.check_event_output(params, test, virsh_session, remote_virsh_session) + if migrate_again: + migration_test_again() + migration_obj.verify_default() + finally: + migration_obj.cleanup_connection() diff --git a/libvirt/tests/src/migration/destructive_operations_around_live_migration/kill_qemu_during_performphase.py b/libvirt/tests/src/migration/destructive_operations_around_live_migration/kill_qemu_during_performphase.py new file mode 100644 index 00000000000..6b93af23f58 --- /dev/null +++ b/libvirt/tests/src/migration/destructive_operations_around_live_migration/kill_qemu_during_performphase.py @@ -0,0 +1,71 @@ +from virttest import virsh + +from virttest.utils_test import libvirt + +from provider.migration import base_steps +from provider.migration import migration_base + + +def run(test, params, env): + """ + This case is to verify that if killing qemu process during PerformPhase of + migration, migration will fail. If dst qemu is killed, src qemu will keep + running. If src qemu is killed, dst qemu will be closed. + + :param test: test object + :param params: Dictionary with the test parameters + :param env: Dictionary with test environment. + """ + 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") + # Check disk on source + if test_case == "kill_src_qemu_before_vm_paused": + migration_obj.migration_test.post_migration_check([vm], params) + if expected_src_state == "shut off": + vm.start() + vm.wait_for_login().close() + #migration_base.set_migrate_speed_to_high(params) + + vm_name = params.get("migrate_main_vm") + test_case = params.get("test_case", "") + migrate_again = "yes" == params.get("migrate_again", "no") + + virsh_session = None + remote_virsh_session = None + + vm = env.get_vm(vm_name) + migration_obj = base_steps.MigrationBase(test, vm, params) + setup_test = eval("setup_%s" % test_case) if "setup_%s" % test_case in \ + locals() else migration_obj.setup_connection + migration_test_again = eval("migration_%s_again" % test_case) if "migration_%s_again" % test_case in \ + locals() else migration_obj.run_migration_again + + try: + setup_test() + virsh_session, remote_virsh_session = migration_base.monitor_event(params) + migration_obj.run_migration() + verify_test() + migration_base.check_event_output(params, test, virsh_session, remote_virsh_session) + if migrate_again: + migration_test_again() + migration_obj.verify_default() + finally: + migration_obj.cleanup_connection() 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() diff --git a/libvirt/tests/src/migration/guest_lifecycle_operations_during_migration/migration_poweroff_vm.py b/libvirt/tests/src/migration/guest_lifecycle_operations_during_migration/migration_poweroff_vm.py index e75fea420c2..841eaf826df 100644 --- a/libvirt/tests/src/migration/guest_lifecycle_operations_during_migration/migration_poweroff_vm.py +++ b/libvirt/tests/src/migration/guest_lifecycle_operations_during_migration/migration_poweroff_vm.py @@ -25,6 +25,7 @@ def setup_poweroff_vm(): test.log.info("Setup for poweroff vm.") migrate_desturi_port = params.get("migrate_desturi_port") migrate_desturi_type = params.get("migrate_desturi_type", "tcp") + virsh_migrate_extra = params.get("virsh_migrate_extra") if migrate_desturi_type: migration_obj.conn_list.append(migration_base.setup_conn_obj(migrate_desturi_type, params, test)) @@ -33,6 +34,9 @@ def setup_poweroff_vm(): migration_obj.remote_add_or_remove_port(migrate_desturi_port) libvirt.set_vm_disk(vm, params) + if "copy-storage-all" in virsh_migrate_extra: + base_steps.prepare_disks_remote(params, vm) + if not vm.is_alive(): vm.start() vm_session = vm.wait_for_login() @@ -57,6 +61,17 @@ def verify_poweroff_vm(): test.log.info("Guest state is '%s' at source is as expected", vm_state_src) migration_obj.verify_default() + def cleanup_poweroff_vm(): + """ + Cleanup for poweroff vm + + """ + virsh_migrate_extra = params.get("virsh_migrate_extra") + + if "copy-storage-all" in virsh_migrate_extra: + base_steps.cleanup_disks_remote(params, vm) + migration_obj.cleanup_connection() + test_case = params.get('test_case', '') vm_name = params.get("migrate_main_vm") @@ -67,10 +82,12 @@ def verify_poweroff_vm(): locals() else migration_obj.setup_connection verify_test = eval("verify_%s" % test_case) if "verify_%s" % test_case in \ locals() else migration_obj.verify_default + cleanup_test = eval("cleanup_%s" % test_case) if "cleanup_%s" % test_case in \ + locals() else migration_obj.cleanup_connection try: setup_test() migration_obj.run_migration() verify_test() finally: - migration_obj.cleanup_connection() + cleanup_test() diff --git a/libvirt/tests/src/migration/live_migration.py b/libvirt/tests/src/migration/live_migration.py index c737c838f76..eda5de10fee 100644 --- a/libvirt/tests/src/migration/live_migration.py +++ b/libvirt/tests/src/migration/live_migration.py @@ -325,7 +325,7 @@ def run(test, params, env): do_mig_param = {"vm": vm, "mig_test": migration_test, "src_uri": None, "dest_uri": dest_uri, "options": options, "virsh_options": virsh_options, "extra": extra, "action_during_mig": action_during_mig, "extra_args": extra_args} - migration_base.do_migration(do_mig_param) + migration_base.do_migration(**do_mig_param) func_returns = dict(migration_test.func_ret) migration_test.func_ret.clear() @@ -370,7 +370,7 @@ def run(test, params, env): do_mig_param = {"vm": vm, "mig_test": migration_test, "src_uri": None, "dest_uri": dest_uri, "options": options, "virsh_options": virsh_options, "extra": extra, "action_during_mig": action_during_mig, "extra_args": extra_args} - migration_base.do_migration(do_mig_param) + migration_base.do_migration(**do_mig_param) if return_port: func_returns = dict(migration_test.func_ret) logging.debug("Migration returns function " diff --git a/libvirt/tests/src/migration/memory_copy_mode/memory_copy_mode.py b/libvirt/tests/src/migration/memory_copy_mode/memory_copy_mode.py new file mode 100644 index 00000000000..5d06e056fd6 --- /dev/null +++ b/libvirt/tests/src/migration/memory_copy_mode/memory_copy_mode.py @@ -0,0 +1,51 @@ +from virttest import libvirt_version +from virttest import remote + +from provider.migration import base_steps +from provider.migration import migration_base + + +def run(test, params, env): + """ + Test live migration with precopy/postcopy. + + :param test: test object + :param params: Dictionary with the test parameters + :param env: Dictionary with test environment. + """ + def verify_postcopy(): + """ + Verify for postcopy migration + + """ + test.log.info("Verify steps.") + migration_obj.verify_default() + + if libvirt_version.version_compare(10, 1, 0): + remote.run_remote_cmd("yum install lsof -y", params) + # Check libvirt pass userfaultfd in vm namespace and qemu can access + # this file correctly after postcopy migration on target host. + cmd = "nsenter -a -t `pidof qemu-kvm` lsof /dev/userfaultfd" + remote.run_remote_cmd(cmd, params, ignore_status=False) + + vm_name = params.get("migrate_main_vm") + test_case = params.get('test_case', '') + + virsh_session = None + remote_virsh_session = None + + vm = env.get_vm(vm_name) + migration_obj = base_steps.MigrationBase(test, vm, params) + + verify_test = eval("verify_%s" % test_case) if "verify_%s" % test_case in \ + locals() else migration_obj.verify_default + + try: + migration_obj.setup_connection() + # Monitor event on source/target host + virsh_session, remote_virsh_session = migration_base.monitor_event(params) + migration_obj.run_migration() + verify_test() + migration_base.check_event_output(params, test, virsh_session, remote_virsh_session) + finally: + migration_obj.cleanup_connection() diff --git a/libvirt/tests/src/migration/memory_copy_mode/migration_memory_copy_mode.py b/libvirt/tests/src/migration/memory_copy_mode/migration_memory_copy_mode.py deleted file mode 100644 index 5eff29092b9..00000000000 --- a/libvirt/tests/src/migration/memory_copy_mode/migration_memory_copy_mode.py +++ /dev/null @@ -1,62 +0,0 @@ -import re - -from virttest import libvirt_version -from virttest import virsh - -from provider.migration import base_steps - -event_session = None - - -def run(test, params, env): - """ - Test live migration with precopy/postcopy. - - :param test: test object - :param params: Dictionary with the test parameters - :param env: Dictionary with test environment. - """ - def setup_postcopy_migration(): - """ - Setup for postcopy migration - """ - expected_event_src = params.get("expected_event_src") - if expected_event_src: - cmd = "event --loop --all" - global event_session - event_session = virsh.VirshSession(virsh_exec=virsh.VIRSH_EXEC, - auto_close=True) - event_session.sendline(cmd) - migration_obj.setup_connection() - - def verify_postcopy_migration(): - """ - Verify for postcopy migration - """ - expected_event_src = params.get("expected_event_src") - if expected_event_src: - global event_session - src_output = event_session.get_stripped_output() - test.log.debug("Event output on source: %s", src_output) - if not re.findall(expected_event_src, src_output): - test.fail("Unalbe to find event {}".format(expected_event_src)) - migration_obj.verify_default() - - libvirt_version.is_libvirt_feature_supported(params) - - test_case = params.get('test_case', '') - vm_name = params.get("migrate_main_vm") - - vm = env.get_vm(vm_name) - migration_obj = base_steps.MigrationBase(test, vm, params) - setup_test = eval("setup_%s" % test_case) if "setup_%s" % test_case in \ - locals() else migration_obj.setup_connection - verify_test = eval("verify_%s" % test_case) if "verify_%s" % test_case in \ - locals() else migration_obj.verify_default - - try: - setup_test() - migration_obj.run_migration() - verify_test() - finally: - migration_obj.cleanup_connection() diff --git a/libvirt/tests/src/migration/migrate_ceph.py b/libvirt/tests/src/migration/migrate_ceph.py index 4d6c5d08b72..9eb422fb20a 100644 --- a/libvirt/tests/src/migration/migrate_ceph.py +++ b/libvirt/tests/src/migration/migrate_ceph.py @@ -359,11 +359,22 @@ def prepare_ceph_disk(ceph_params, remote_virsh_dargs, test, runner_on_target): if auth_user and auth_key: disk_path += (":id=%s:key=%s" % (auth_user, auth_key)) - disk_cmd = ("rbd -m %s %s info %s || qemu-img convert" - " -O %s %s %s" % (mon_host, key_opt, - disk_src_name, disk_format, - blk_source, disk_path)) - process.run(disk_cmd, ignore_status=False, shell=True) + + # Convert the image to remote storage + directory = os.path.dirname(blk_source) + filename_with_extension = os.path.basename(blk_source) + + # Get the file name without extension and the extension + filename, _ = os.path.splitext(filename_with_extension) + converted_raw_file = os.path.join(directory, "%s.raw" % filename) + convert_cmd = ("qemu-img convert" + " -O %s %s %s" % (disk_format, blk_source, converted_raw_file)) + process.run(convert_cmd, ignore_status=False, verbose=True, shell=True) + disk_cmd = ("rbd -m %s %s info %s 2> /dev/null|| rbd -m %s %s import " + " %s %s" % (mon_host, key_opt, disk_src_name, mon_host, key_opt, converted_raw_file, + disk_src_name)) + process.run(disk_cmd, ignore_status=False, verbose=True, shell=True) + return (key_opt, secret_uuid) @@ -455,6 +466,7 @@ def run(test, params, env): mon_host = params.get("mon_host") ceph_key_opt = "" attach_disk = False + converted_raw_file = "" # Disk XML file disk_xml = None # Define ceph_disk conditional variable @@ -590,6 +602,8 @@ def run(test, params, env): test.fail("Failed to run '%s' on remote: %s" % (cmd, output)) finally: + if converted_raw_file and os.path.exists(converted_raw_file): + os.remove(converted_raw_file) logging.info("Recovery test environment") # Clean up of pre migration setup for local machine if migrate_vm_back: diff --git a/libvirt/tests/src/migration/migrate_event.py b/libvirt/tests/src/migration/migrate_event.py index 301432a19ff..b5762a4a5a0 100644 --- a/libvirt/tests/src/migration/migrate_event.py +++ b/libvirt/tests/src/migration/migrate_event.py @@ -81,7 +81,7 @@ def run(test, params, env): do_mig_param = {"vm": vm, "mig_test": migration_test, "src_uri": None, "dest_uri": dest_uri, "options": options, "virsh_options": virsh_options, "extra": extra, "action_during_mig": action_during_mig, "extra_args": extra_args} - migration_base.do_migration(do_mig_param) + migration_base.do_migration(**do_mig_param) func_returns = dict(migration_test.func_ret) migration_test.func_ret.clear() diff --git a/libvirt/tests/src/migration/migrate_mem.py b/libvirt/tests/src/migration/migrate_mem.py index b42be712bf3..acc31c58261 100644 --- a/libvirt/tests/src/migration/migrate_mem.py +++ b/libvirt/tests/src/migration/migrate_mem.py @@ -254,6 +254,9 @@ def verify_test_mem_nvdimm(vm, params, test): vm_session.cmd("echo '{}.back' > /mnt/nvdimm_test_back".format(expected_content)) vm_session.cmd('umount /mnt') + # Cleanup nvram file on source host + vm_name = params.get("migrate_main_vm") + process.run(f"rm -rf /var/lib/libvirt/qemu/nvram/{vm_name}_VARS.fd", shell=True, ignore_status=True) def verify_test_back_default(vm, params, test): @@ -333,7 +336,9 @@ def cleanup_test_mem_nvdimm(vm, params, test): """ cleanup_test_default(vm, params, test) test.log.debug("Recover test environment for memory nvdimm device test") - os.remove(params.get('nfs_mount_src') + '/nvdimm') + nvdimm_file_path = params.get("nvdimm_file_path") + if os.path.exists(nvdimm_file_path): + os.remove(nvdimm_file_path) def run_migration_back(params, test): diff --git a/libvirt/tests/src/migration/migrate_network.py b/libvirt/tests/src/migration/migrate_network.py index 3a1bfa3756e..dac8d088b0b 100644 --- a/libvirt/tests/src/migration/migrate_network.py +++ b/libvirt/tests/src/migration/migrate_network.py @@ -15,6 +15,7 @@ from virttest.utils_libvirt import libvirt_network from virttest.libvirt_xml.devices import interface +from provider.virtual_network import network_base # Using as lower capital is not the best way to do, but this is just a # workaround to avoid changing the entire file. @@ -92,17 +93,19 @@ def update_iface_xml(vm_name, iface_dict, virsh_instance=virsh): vm_sync(vmxml, vm_name, virsh_instance=virsh_instance) logging.debug("VM XML after updating interface: %s" % vmxml) - def update_net_dict(net_dict, runner=utils_net.local_runner): + def update_net_dict(net_dict, iface_name, runner=utils_net.local_runner): """ Update network dict :param net_dict: The network dict to be updated + :param iface_name: host iface name to use for direct network :param runner: Command runner :return: Updated network dict """ if net_dict.get("name", "") == "direct-macvtap": logging.info("Updating network iface name") - iface_name = utils_net.get_net_if(runner=runner, state="UP")[0] + if not iface_name: + iface_name = utils_net.get_net_if(runner=runner, state="UP", ip_options='-color=never')[0] net_dict.update({'forward_interface': [{'dev': iface_name}]}) else: # TODO: support other types @@ -204,6 +207,8 @@ def create_fake_tap(remote_session): params.get("migrate_source_host")) src_uri = params.get("virsh_migrate_connect_uri") dest_uri = params.get("virsh_migrate_desturi") + host_iface_src = params.get("host_iface_src") + host_iface_dst = params.get("host_iface_dst") vm_name = params.get("migrate_main_vm") vm = env.get_vm(vm_name) @@ -247,21 +252,21 @@ def create_fake_tap(remote_session): logging.debug("target xml is %s" % target_org_xml) if ovs_bridge_name: - status, stdout = utils_net.create_ovs_bridge(ovs_bridge_name) + status, stdout = utils_net.create_ovs_bridge(ovs_bridge_name, ip_options='-color=never') if status: test.fail("Failed to create ovs bridge on local. Status: %s" "Stdout: %s" % (status, stdout)) status, stdout = utils_net.create_ovs_bridge( - ovs_bridge_name, session=remote_session) + ovs_bridge_name, session=remote_session, ip_options='-color=never') if status: test.fail("Failed to create ovs bridge on remote. Status: %s" "Stdout: %s" % (status, stdout)) if network_dict: - update_net_dict(network_dict, runner=remote_session.cmd) + update_net_dict(network_dict, host_iface_src, runner=remote_session.cmd) libvirt_network.create_or_del_network( network_dict, remote_args=remote_virsh_dargs) logging.info("dest: network created") - update_net_dict(network_dict) + update_net_dict(network_dict, host_iface_dst) libvirt_network.create_or_del_network(network_dict) logging.info("localhost: network created") @@ -315,7 +320,7 @@ def create_fake_tap(remote_session): if not utils_package.package_install('dhcp-client', session=vm_session): test.error("Failed to install dhcp-client on guest.") utils_net.restart_guest_network(vm_session) - vm_ip = utils_net.get_guest_ip_addr(vm_session, mac) + vm_ip = network_base.get_vm_ip(vm_session, mac) logging.debug("VM IP Addr: %s", vm_ip) if direct_mode: @@ -422,8 +427,8 @@ def create_fake_tap(remote_session): network_dict, is_del=True, remote_args=remote_virsh_dargs) libvirt_network.create_or_del_network(network_dict, is_del=True) if ovs_bridge_name: - utils_net.delete_ovs_bridge(ovs_bridge_name) - utils_net.delete_ovs_bridge(ovs_bridge_name, session=remote_session) + utils_net.delete_ovs_bridge(ovs_bridge_name, ip_options='-color=never') + utils_net.delete_ovs_bridge(ovs_bridge_name, session=remote_session, ip_options='-color=never') remote_session.close() if target_vm_session: diff --git a/libvirt/tests/src/migration/migrate_options_shared.py b/libvirt/tests/src/migration/migrate_options_shared.py index 91b28743370..6a0bc83b85c 100644 --- a/libvirt/tests/src/migration/migrate_options_shared.py +++ b/libvirt/tests/src/migration/migrate_options_shared.py @@ -3,7 +3,6 @@ import time import math import re -import threading import platform import tempfile import copy @@ -182,18 +181,6 @@ def cleanup_libvirtd_log(log_file): logging.debug("Delete remote libvirt log file '%s'", log_file) remote.run_remote_cmd(cmd, cmd_parms, runner_on_target) - def run_stress_in_vm(): - """ - The function to load stress in VM - """ - stress_args = params.get("stress_args", "--cpu 8 --io 4 " - "--vm 2 --vm-bytes 128M " - "--timeout 20s") - try: - vm_session.cmd('stress %s' % stress_args) - except Exception as detail: - logging.debug(detail) - def control_migrate_speed(to_speed=1, opts=""): """ Control migration duration @@ -235,7 +222,7 @@ def check_output(output, expected_value_list): logging.debug("Actual output is %s", output) for item in expected_value_list: if not re.findall(item, output): - test.fail("Unalbe to find {}".format(item)) + test.fail("Unable to find {}".format(item)) def check_interval_not_fixed(search_str, log_file, interval=0.05, session=None): @@ -255,7 +242,7 @@ def check_interval_not_fixed(search_str, log_file, interval=0.05, session=session) if cmdStd: - test.fail("Unalbe to get {} from {}.".format(search_str, log_file)) + test.fail("Unable to get {} from {}.".format(search_str, log_file)) date_list = [] for line in cmdStdout.splitlines(): if line: @@ -743,6 +730,23 @@ def check_timeout_postcopy(params): "be 'running', but '%s' found" % (timeout, vm_state)) remote_virsh_session.close_session() + def help_migration_converge(): + """ + This function will allow for more downtime and bandwidth + in order to help the migration converge. + + This is useful in cases like auto-converge check where we + usually lower these values a lot so we can cause the + auto-converge feature to kick in. + """ + one_second = 1000 + virsh.migrate_setmaxdowntime(vm_name, one_second, **virsh_args) + maxspeed = 8796093022207 + opts = "" + if postcopy_options: + opts = postcopy_options + virsh.migrate_setspeed(vm_name, maxspeed, extra=opts, **virsh_args) + def check_converge(params): """ Handle option '--auto-converge --auto-converge-initial @@ -766,6 +770,7 @@ def check_converge(params): "is %s", allow_throttle_list) throttle = 0 + old_throttle = 0 jobtype = "None" while throttle < 100: @@ -789,8 +794,12 @@ def check_converge(params): if key.count("Job type"): jobtype = line.split(':')[-1].strip() elif key.count("Auto converge throttle"): + if throttle > 0: + old_throttle = throttle throttle = int(line.split(':')[-1].strip()) logging.debug("Auto converge throttle:%s", str(throttle)) + if old_throttle > 0 and throttle > old_throttle: + help_migration_converge() if throttle and throttle not in allow_throttle_list: test.fail("Invalid auto converge throttle " "value '%s'" % throttle) @@ -798,6 +807,7 @@ def check_converge(params): logging.debug("'Auto converge throttle' reaches maximum " "allowed value 99") break + if jobtype == "None" or jobtype == "Completed": logging.debug("Jobtype:%s", jobtype) if not throttle: @@ -1047,6 +1057,7 @@ def cancel_bg_migration(): low_speed = params.get("low_speed", None) migrate_vm_back = "yes" == params.get("migrate_vm_back", "no") timer_migration = "yes" == params.get("timer_migration", "no") + armvtimer = eval(params.get("armvtimer", "{}")) concurrent_migration = "yes" == params.get("concurrent_migration", "no") remote_virsh_dargs = {'remote_ip': server_ip, 'remote_user': server_user, @@ -1267,6 +1278,10 @@ def cancel_bg_migration(): .format(loc)) remote_session.close() + if timer_migration and armvtimer: + new_xml.setup_attrs(**armvtimer) + new_xml.sync() + # Change the disk of the vm to shared disk and then start VM libvirt.set_vm_disk(vm, params) @@ -1324,17 +1339,8 @@ def cancel_bg_migration(): test.error("Failed to install tpm2-tools in vm") if stress_in_vm: - pkg_name = 'stress' - logging.debug("Check if stress tool is installed") - pkg_mgr = utils_package.package_manager(vm_session, pkg_name) - if not pkg_mgr.is_installed(pkg_name): - logging.debug("Stress tool will be installed") - if not pkg_mgr.install(): - test.error("Package '%s' installation fails" % pkg_name) - - stress_thread = threading.Thread(target=run_stress_in_vm, - args=()) - stress_thread.start() + params.update({"stress_package": "stress"}) + migration_test.run_stress_in_vm(vm, params) # Check maxdowntime before migration if check_default_maxdowntime: @@ -1400,6 +1406,14 @@ def cancel_bg_migration(): asynch_migration = False params.update({"status_error": "yes"}) + # Disable postcopy + multifd migration in qemu-kvm-8.1.0. + if extra.count("postcopy") and extra.count("parallel"): + if utils_misc.compare_qemu_version(8, 1, 0, is_rhev=False): + asynch_migration = False + params.update({"status_error": "yes"}) + params.update({"err_msg": "Postcopy is not yet compatible with multifd"}) + params.update({"action_during_mig": ""}) + # Execute migration process if not asynch_migration: mig_result = do_migration(vm, dest_uri, options, extra) diff --git a/libvirt/tests/src/migration/migrate_over_unix.py b/libvirt/tests/src/migration/migrate_over_unix.py index 69b8d719382..1d35cf84910 100644 --- a/libvirt/tests/src/migration/migrate_over_unix.py +++ b/libvirt/tests/src/migration/migrate_over_unix.py @@ -46,6 +46,15 @@ def run(test, params, env): :param params: Dictionary with the test parameters :param env: Dictionary with test environment. """ + def get_vm_did_list(session): + """ + Get the list of newly attached disks + + :param session: guest console session + """ + info = libvirt_disk.get_non_root_disk_names(session, ignore_status=True) + return [x[0] for x in info] + def update_disk(vm, params): """ Update disk for testing. @@ -56,7 +65,6 @@ def update_disk(vm, params): """ local_image_list = [] remote_image_list = [] - vm_did_list = [] # Change the disk of the vm if storage_type == "nfs": libvirt.set_vm_disk(vm, params) @@ -103,10 +111,9 @@ def update_disk(vm, params): session=remote_session) remote_image_list.append(disk_path) - vm_did_list.append(target_dev) remote_session.close() - return local_image_list, remote_image_list, vm_did_list + return local_image_list, remote_image_list def check_socket(params): """ @@ -129,7 +136,7 @@ def _check_socket(): global sockets sockets = [x.strip() for x in _res if socket_pattern.match(x)] logging.debug("Found sockets: %s", sockets) - return len(sockets) == int(exp_num) + return len(sockets) >= int(exp_num) found_expected = utils_misc.wait_for(_check_socket, timeout=30) @@ -166,7 +173,6 @@ def _check_socket(): mig_result = None local_image_list = [] remote_image_list = [] - vm_did_list = [] if not libvirt_version.version_compare(6, 6, 0): test.cancel("This libvirt version doesn't support " @@ -214,7 +220,7 @@ def _check_socket(): unix_obj.conn_setup() unix_obj.auto_recover = True - local_image_list, remote_image_list, vm_did_list = update_disk(vm, params) + local_image_list, remote_image_list = update_disk(vm, params) if not vm.is_alive(): vm.start() @@ -224,6 +230,7 @@ def _check_socket(): vm_session = vm.wait_for_login() + vm_did_list = get_vm_did_list(vm_session) for did in vm_did_list: utils_disk.linux_disk_check(vm_session, did) @@ -265,13 +272,13 @@ def _check_socket(): lambda: virsh.is_alive(vm_name, uri=dest_uri_ssh, debug=True), 60): test.fail("The migrated VM should be alive!") - if vm_did_list: - if vm.serial_console is None: - vm.create_serial_console() - vm_session_after_mig = vm.wait_for_serial_login(timeout=240) - for did in vm_did_list: - vm_session_after_mig.cmd( - "echo mytest >> /mnt/%s1/mytest" % did) + if vm.serial_console is None: + vm.create_serial_console() + vm_session_after_mig = vm.wait_for_serial_login(timeout=240) + vm_did_list = get_vm_did_list(vm_session_after_mig) + for did in vm_did_list: + vm_session_after_mig.cmd( + "echo mytest >> /mnt/%s1/mytest" % did) finally: logging.info("Recover test environment") vm.connect_uri = bk_uri diff --git a/libvirt/tests/src/migration/migrate_service_control.py b/libvirt/tests/src/migration/migrate_service_control.py index 201851efd81..acf7882e895 100644 --- a/libvirt/tests/src/migration/migrate_service_control.py +++ b/libvirt/tests/src/migration/migrate_service_control.py @@ -137,7 +137,7 @@ def run(test, params, env): do_mig_param = {"vm": vm, "mig_test": migration_test, "src_uri": None, "dest_uri": dest_uri, "options": options, "virsh_options": virsh_options, "extra": extra, "action_during_mig": action_during_mig, "extra_args": extra_args} - migration_base.do_migration(do_mig_param) + migration_base.do_migration(**do_mig_param) func_returns = dict(migration_test.func_ret) migration_test.func_ret.clear() @@ -157,7 +157,7 @@ def run(test, params, env): do_mig_param = {"vm": vm, "mig_test": migration_test, "src_uri": None, "dest_uri": dest_uri, "options": options, "virsh_options": virsh_options, "extra": extra, "action_during_mig": action_during_mig, "extra_args": extra_args} - migration_base.do_migration(do_mig_param) + migration_base.do_migration(**do_mig_param) if int(migration_test.ret.exit_status) == 0: migration_test.post_migration_check([vm], params, dest_uri=dest_uri) finally: diff --git a/libvirt/tests/src/migration/migrate_vm.py b/libvirt/tests/src/migration/migrate_vm.py index 0eb27ec04fc..0fa30f35d39 100644 --- a/libvirt/tests/src/migration/migrate_vm.py +++ b/libvirt/tests/src/migration/migrate_vm.py @@ -23,7 +23,6 @@ from virttest import utils_config from virttest import utils_libvirtd from virttest import utils_misc -from virttest import utils_netperf from virttest import utils_package from virttest import utils_selinux from virttest import utils_test @@ -507,6 +506,8 @@ def get_same_processor(test, server_ip, server_user, server_pwd, verbose): if status: test.fail("Failed to run '%s' on the remote: %s" % (cmd, output)) remote_processors = re.findall(r'processor\s+: (\d+)', output) + if not remote_processors: + remote_processors = re.findall(r'processor\s+(\d+):', output) if verbose: logging.debug("Local processors: %s", local_processors) logging.debug("Remote processors: %s", remote_processors) @@ -775,83 +776,62 @@ def run_remote_cmd(command, server_ip, server_user, server_pwd, return (session, status, output) -def setup_netsever_and_launch_netperf(test, params): +def run_cmd(cmd, params): """ - Setup netserver and run netperf client + Run cmd on source host and target host + + :param cmd: command + :param params: parameters used + """ + process.run(cmd, shell=True, ignore_status=True) + remote.run_remote_cmd(cmd, params, ignore_status=True) + + +def setup_netperf(test, params): + """ + Setup netserver and run netperf cmd :param test: test object :param params: parameters used - :raise: test.error if automake installation fails """ server_ip = params.get("server_ip") - server_user = params.get("server_user") + server_user = params.get("server_user", "root") server_pwd = params.get("server_pwd") - client_ip = params.get("client_ip") - client_user = params.get("client_user") - client_pwd = params.get("client_pwd") - netperf_source = params.get("netperf_source") - netperf_source = os.path.join(data_dir.get_root_dir(), netperf_source) - client_md5sum = params.get("client_md5sum") - client_path = params.get("client_path", "/var/tmp") - server_md5sum = params.get("server_md5sum") - server_path = params.get("server_path", "/var/tmp") - compile_option_client = params.get("compile_option_client", "") - compile_option_server = params.get("compile_option_server", "") - # Run netperf with message size defined in range. - netperf_test_duration = int(params.get("netperf_test_duration", 60)) - netperf_para_sess = params.get("netperf_para_sessions", "1") - test_protocol = params.get("test_protocols", "TCP_STREAM") - netperf_cmd_prefix = params.get("netperf_cmd_prefix", "") - netperf_output_unit = params.get("netperf_output_unit", " ") - netperf_package_sizes = params.get("netperf_package_sizes") - test_option = params.get("test_option", "") - direction = params.get("direction", "remote") - remote_session = remote.remote_login("ssh", server_ip, "22", server_user, - server_pwd, r'[$#%]') - for loc in ['source', 'target']: - session = None - if loc == 'target': - session = remote_session - if not utils_package.package_install("automake", session): - test.error("Failed to install automake on %s host." % loc) + netperf_cmd_src = params.get("netperf_cmd_src") + netperf_cmd_dst = params.get("netperf_cmd_dst") + + if not utils_package.package_install("netperf"): + test.error("Failed to install netperf on source host.") + + remote_session = remote.wait_for_login('ssh', server_ip, '22', server_user, + server_pwd, r"[\#\$]\s*$") + if not utils_package.package_install("netperf", remote_session): + test.error("Failed to install netperf on target host.") remote_session.close() - n_client = utils_netperf.NetperfClient(client_ip, - client_path, - client_md5sum, - netperf_source, - client="ssh", - port="22", - username=client_user, - password=client_pwd, - compile_option=compile_option_client) - - logging.info("Start netserver on %s", server_ip) - n_server = utils_netperf.NetperfServer(server_ip, - server_path, - server_md5sum, - netperf_source, - client="ssh", - port="22", - username=server_user, - password=server_pwd, - compile_option=compile_option_server) - - n_server.start() - - test_option += " -l %s" % netperf_test_duration - start_time = time.time() - stop_time = start_time + netperf_test_duration - t_option = "%s -t %s" % (test_option, test_protocol) - logging.info("Start netperf on %s", client_ip) - n_client.bg_start(server_ip, t_option, - netperf_para_sess, netperf_cmd_prefix, - package_sizes=netperf_package_sizes) - if utils_misc.wait_for(n_client.is_netperf_running, 10, 0, 1, - "Wait netperf test start"): - logging.info("Start netperf on %s successfully.", client_ip) - return (True, n_client, n_server) - else: - return (False, n_client, n_server) + + run_cmd("systemctl stop firewalld", params) + run_cmd("killall netserver", params) + test.log.debug("Start netserver.") + run_cmd("netserver", params) + + test.log.debug("Run netperf on source host.") + process.run(netperf_cmd_src, shell=True, ignore_bg_processes=True) + + test.log.debug("Run netperf on target host.") + remote.run_remote_cmd(netperf_cmd_dst, params, ignore_status=True) + + +def cleanup_netperf(test, params): + """ + Cleanup netserver and netperf cmd + + :param test: test object + :param params: parameters used + """ + test.log.debug("Cleanup netserver and netperf.") + run_cmd("killall netperf", params) + run_cmd("killall netserver", params) + run_cmd("systemctl start firewalld", params) def cleanup(objs_list): @@ -1277,6 +1257,7 @@ def get_target_hugepage_num(params): block_time = test_dict.get("block_time") restart_vm = "yes" == test_dict.get("restart_vm", "no") diff_cpu_vendor = "yes" == test_dict.get("diff_cpu_vendor", "no") + netperf_network = "yes" == test_dict.get("netperf_network", "no") # Get iothread parameters. driver_iothread = test_dict.get("driver_iothread") @@ -1472,10 +1453,6 @@ def get_target_hugepage_num(params): nfs_cli = None se_obj = None libvirtd_conf = None - n_server_c = None - n_client_c = None - n_server_s = None - n_client_s = None need_mkswap = False LOCAL_SELINUX_ENFORCING = True REMOTE_SELINUX_ENFORCING = True @@ -1871,12 +1848,8 @@ def get_target_hugepage_num(params): local_image_list.append(new_disk_source) if restart_libvirtd_remotely: - cmd = "service libvirtd restart" - status, output = run_remote_cmd(cmd, server_ip, server_user, - server_pwd) - if status: - test.fail("Failed to run '%s' on remote: %s" - % (cmd, output)) + libvirt.remotely_control_libvirtd(server_ip, server_user, + server_pwd, "restart", status_error) if remote_hugetlbfs_path: cmd = "ls %s" % remote_hugetlbfs_path @@ -2205,43 +2178,8 @@ def get_target_hugepage_num(params): result = virsh.migrate_compcache(vm_name, size=set_migr_cache_size) logging.debug(result) - netperf_version = test_dict.get("netperf_version") - if netperf_version: - # Install tar on client - # Note: tar is used to untar netperf package later. - if not utils_package.package_install(["tar"]): - test.error("Failed to install tar on client") - - # Install tar on server - # Note: tar is used to untar netperf package later. - remote_session = remote.wait_for_login('ssh', server_ip, '22', server_user, - server_pwd, r"[\#\$]\s*$") - if not utils_package.package_install(["tar"], remote_session): - test.error("Failed to install tar on server") - - ret, n_client_c, n_server_c = setup_netsever_and_launch_netperf( - test, test_dict) - if not ret: - test.error("Can not start netperf on %s" % client_ip) - - new_args_dict = dict(test_dict) - new_args_dict["server_ip"] = client_ip - new_args_dict["server_user"] = client_user - new_args_dict["server_pwd"] = client_pwd - new_args_dict["client_ip"] = server_ip - new_args_dict["client_user"] = server_user - new_args_dict["client_pwd"] = server_pwd - new_args_dict["server_md5sum"] = test_dict.get("client_md5sum") - new_args_dict["server_path"] = test_dict.get("client_path", "/var/tmp") - new_args_dict["compile_option_server"] = test_dict.get("compile_option_client", "") - new_args_dict["client_md5sum"] = test_dict.get("server_md5sum") - new_args_dict["client_path"] = test_dict.get("server_path", "/var/tmp") - new_args_dict["compile_option_client"] = test_dict.get("compile_option_server", "") - - ret, n_client_s, n_server_s = setup_netsever_and_launch_netperf( - test, new_args_dict) - if not ret: - test.error("Can not start netperf on %s" % client_ip) + if netperf_network: + setup_netperf(test, params) speed = test_dict.get("set_migration_speed") if speed: @@ -2965,14 +2903,15 @@ def get_target_hugepage_num(params): if HUGETLBFS_MOUNT: cmds = ["umount -l %s" % remote_hugetlbfs_path, - "sysctl vm.nr_hugepages=0", - "service libvirtd restart"] + "sysctl vm.nr_hugepages=0"] for cmd in cmds: status, output = run_remote_cmd(cmd, server_ip, server_user, server_pwd) if status: test.fail("Failed to run '%s' on remote: %s" % (cmd, output)) + libvirt.remotely_control_libvirtd(server_ip, server_user, + server_pwd, "restart", status_error) if pool_created: pool_destroyed = create_destroy_pool_on_remote(test, "destroy", test_dict) if not pool_destroyed: @@ -2988,18 +2927,9 @@ def get_target_hugepage_num(params): test.fail("Failed to run '%s' on the remote: %s" % (cmd, output)) - # Stop netserver service and clean up netperf package - if n_server_c: - n_server_c.stop() - n_server_c.package.env_cleanup(True) - if n_client_c: - n_client_c.package.env_cleanup(True) - - if n_server_s: - n_server_s.stop() - n_server_s.package.env_cleanup(True) - if n_client_s: - n_client_s.package.env_cleanup(True) + # Stop netserver service and clean up netperf cmd + if netperf_network: + cleanup_netperf(test, params) if objs_list and len(objs_list) > 0: logging.debug("Clean up the objects") diff --git a/libvirt/tests/src/migration/migrate_vm_in_various_status/migrate_paused_vm.py b/libvirt/tests/src/migration/migrate_vm_in_various_status/migrate_paused_vm.py index 81bba325265..5828f05b889 100644 --- a/libvirt/tests/src/migration/migrate_vm_in_various_status/migrate_paused_vm.py +++ b/libvirt/tests/src/migration/migrate_vm_in_various_status/migrate_paused_vm.py @@ -1,4 +1,5 @@ from virttest import virsh +from virttest.utils_test import libvirt from provider.migration import base_steps @@ -14,6 +15,7 @@ def run(test, params, env): :param env: Dictionary with test environment. """ vm_name = params.get("migrate_main_vm") + migrate_vm_back = "yes" == params.get("migrate_vm_back", "no") vm = env.get_vm(vm_name) migration_obj = base_steps.MigrationBase(test, vm, params) @@ -24,5 +26,10 @@ def run(test, params, env): virsh.suspend(vm.name, debug=True, ignore_status=False) migration_obj.run_migration() migration_obj.verify_default() + if migrate_vm_back: + migration_obj.run_migration_back() + if not libvirt.check_vm_state(vm_name, params.get("src_state"), + uri=migration_obj.src_uri, debug=True): + test.fail("Check vm state failed.") finally: migration_obj.cleanup_connection() diff --git a/libvirt/tests/src/migration/migrate_with_panic_device.py b/libvirt/tests/src/migration/migrate_with_panic_device.py new file mode 100644 index 00000000000..3d3ba30a1d6 --- /dev/null +++ b/libvirt/tests/src/migration/migrate_with_panic_device.py @@ -0,0 +1,96 @@ +import aexpect + +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): + """ + Verify panic device works well after migration. + + :param test: test object + :param params: Dictionary with the test parameters + :param env: Dictionary with test environment. + """ + def setup_test(): + """ + Setup step + + """ + panic_model = params.get("panic_model") + addr_type = params.get("addr_type") + addr_iobase = params.get("addr_iobase") + dump_file_path = params.get("dump_file_path") + crash_action = params.get("crash_action") + panic_dev = eval(params.get("panic_dev")) + + test.log.info("Setup steps.") + migration_obj.setup_connection() + # Cleanup dump file + cmd = "rm -f %s/*" % dump_file_path + remote.run_remote_cmd(cmd, params) + + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + libvirt_vmxml.modify_vm_device(vmxml, 'panic', panic_dev) + vmxml.on_crash = crash_action + vmxml.sync() + test.log.info("Guest xml now is: %s", vmxml) + vm.start() + vm.wait_for_login().close() + + def verify_test(): + """ + Verify step + + """ + dest_uri = params.get("virsh_migrate_desturi") + expected_match = params.get("expected_match") + dump_file_path = params.get("dump_file_path") + + test.log.info("Verify steps.") + migration_obj.verify_default() + + backup_uri, vm.connect_uri = vm.connect_uri, dest_uri + vm.cleanup_serial_console() + vm.create_serial_console() + remote_vm_session = vm.wait_for_serial_login(timeout=360) + try: + remote_vm_session.cmd("systemctl stop kdump", ignore_all_errors=True) + remote_vm_session.cmd("echo 1 > /proc/sys/kernel/sysrq") + remote_vm_session.cmd_status_output("echo c > /proc/sysrq-trigger", timeout=3) + except aexpect.ShellTimeoutError: + # This is expected + pass + except Exception: + # This is unexpected + raise + + remote_vm_session.close() + ret = virsh.domstate(vm_name, extra="--reason", uri=dest_uri, debug=True) + libvirt.check_result(ret, expected_match=expected_match) + + # Check dump file + cmd = "ls %s" % dump_file_path + ret = remote.run_remote_cmd(cmd, params, ignore_status=False) + if vm_name not in ret.stdout_text.strip(): + test.fail("Not found dump file.") + + vm.destroy() + vm.connect_uri = backup_uri + + 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() diff --git a/libvirt/tests/src/migration/migrate_with_various_hostname.py b/libvirt/tests/src/migration/migrate_with_various_hostname.py index 586da396c1a..66ad27b9760 100644 --- a/libvirt/tests/src/migration/migrate_with_various_hostname.py +++ b/libvirt/tests/src/migration/migrate_with_various_hostname.py @@ -197,7 +197,7 @@ def run(test, params, env): do_mig_param = {"vm": vm, "mig_test": migration_test, "src_uri": None, "dest_uri": dest_uri, "options": options, "virsh_options": virsh_options, "extra": extra, "action_during_mig": None, "extra_args": extra_args} - migration_base.do_migration(do_mig_param) + migration_base.do_migration(**do_mig_param) func_returns = dict(migration_test.func_ret) migration_test.func_ret.clear() @@ -215,7 +215,7 @@ def run(test, params, env): do_mig_param = {"vm": vm, "mig_test": migration_test, "src_uri": None, "dest_uri": dest_uri, "options": options, "virsh_options": virsh_options, "extra": extra, "action_during_mig": None, "extra_args": extra_args} - migration_base.do_migration(do_mig_param) + migration_base.do_migration(**do_mig_param) if int(migration_test.ret.exit_status) == 0: migration_test.post_migration_check([vm], params, dest_uri=dest_uri, src_uri=bk_uri) finally: diff --git a/libvirt/tests/src/migration/migrate_with_virtual_devices.py b/libvirt/tests/src/migration/migrate_with_virtual_devices.py index e85ba30e062..b7629a542ed 100644 --- a/libvirt/tests/src/migration/migrate_with_virtual_devices.py +++ b/libvirt/tests/src/migration/migrate_with_virtual_devices.py @@ -552,21 +552,21 @@ def check_rng_in_vm(vm, backend_type, rng_present): """ logging.debug("Check rng device in vm") - check_cmd = "dd if=/dev/hwrng of=/dev/null count=2 bs=2" + check_cmd = "cat /sys/devices/virtual/misc/hw_random/rng_available" timeout = 10 try: status, output = vm.session.cmd_status_output(check_cmd, timeout) - logging.debug("cmd exit status: %s, cmd output: %s", + logging.debug("cmd exit status: %s, current rng available: %s", status, output) - - if status == 0: + status = True if output.count("virtio_rng") else False + if status is True: if rng_present: return else: raise DeviceNotRemovedError("rng") else: - if not rng_present and "No such device" in output: + if not rng_present: return elif rng_present: raise DeviceNotFoundError("rng") diff --git a/libvirt/tests/src/migration/migration_misc/canonical_paths_in_shared_filesystems.py b/libvirt/tests/src/migration/migration_misc/canonical_paths_in_shared_filesystems.py new file mode 100644 index 00000000000..e556abaa2d7 --- /dev/null +++ b/libvirt/tests/src/migration/migration_misc/canonical_paths_in_shared_filesystems.py @@ -0,0 +1,206 @@ +import os + +from avocado.utils import process + +from virttest import libvirt_remote +from virttest import remote +from virttest import utils_config +from virttest import utils_disk +from virttest import utils_misc +from virttest import virsh +from virttest.libvirt_xml import vm_xml +from virttest.utils_test import libvirt +from virttest.utils_libvirt import libvirt_bios +from virttest.utils_test import libvirt + +from provider.guest_os_booting import guest_os_booting_base as guest_os +from provider.migration import base_steps + + +def setup_for_shared_filesystems(params, test): + """ + Setup for shared filesystems + + :param params: dict, test parameters + :param test: test object + """ + export_dir = params.get("export_dir") + nfs_server_ip = params.get("nfs_server_ip") + nfs_images_path = params.get("nfs_images_path") + nfs_nvram_path = params.get("nfs_nvram_path") + nfs_swtpm_path = params.get("nfs_swtpm_path") + images_path = params.get("images_path") + nvram_path = params.get("nvram_path") + swtpm_path = params.get("swtpm_path") + nfs_mount_options = params.get("nfs_mount_options") + server_ip = params.get("server_ip") + server_user = params.get("server_user", "root") + server_pwd = params.get("server_pwd") + mount_images_path = params.get("mount_images_path") + mount_nvram_path = params.get("mount_nvram_path") + mount_swtpm_path = params.get("mount_swtpm_path") + + if not os.path.exists(export_dir): + os.mkdir(export_dir) + + mount_opt = "rw,no_root_squash,sync" + res = libvirt.setup_or_cleanup_nfs(is_setup=True, + is_mount=False, + export_options=mount_opt, + export_dir=export_dir) + + for path in [nfs_images_path, nfs_nvram_path, nfs_swtpm_path]: + if not utils_misc.check_exists(path): + process.run(f"mkdir -p {path}", shell=True, verbose=True) + + utils_disk.mount(nfs_images_path, images_path, options=nfs_mount_options) + utils_disk.mount(nfs_nvram_path, nvram_path, options=nfs_mount_options) + utils_disk.mount(nfs_swtpm_path, swtpm_path, options=nfs_mount_options) + + remote_session = remote.wait_for_login("ssh", server_ip, "22", server_user, server_pwd, r"[\#\$]\s*$") + utils_disk.mount(mount_images_path, images_path, session=remote_session) + utils_disk.mount(mount_nvram_path, nvram_path, session=remote_session) + utils_disk.mount(mount_swtpm_path, swtpm_path, session=remote_session) + remote_session.close() + + remote_obj = None + local_obj = None + qemu_conf_src = eval(params.get("qemu_conf_src", "{}")) + qemu_conf_dest = params.get("qemu_conf_dest", "{}") + qemu_conf_path = utils_config.LibvirtQemuConfig().conf_path + remote_obj = libvirt_remote.update_remote_file(params, qemu_conf_dest, qemu_conf_path) + local_obj = libvirt.customize_libvirt_config(qemu_conf_src, "qemu", remote_host=False, + extra_params=params) + return (local_obj, remote_obj) + + +def cleanup_for_shared_filesystems(params, test): + """ + Cleanup for shared filesystems + + :param params: dict, test parameters + :param test: test object + """ + images_path = params.get("images_path") + nvram_path = params.get("nvram_path") + swtpm_path = params.get("swtpm_path") + server_ip = params.get("server_ip") + server_user = params.get("server_user", "root") + server_pwd = params.get("server_pwd") + export_dir = params.get("export_dir") + mount_images_path = params.get("mount_images_path") + mount_nvram_path = params.get("mount_nvram_path") + mount_swtpm_path = params.get("mount_swtpm_path") + + test.log.info("Cleanup for shared_filesystems.") + remote_session = remote.wait_for_login("ssh", server_ip, "22", server_user, server_pwd, r"[\#\$]\s*$") + utils_disk.umount(mount_images_path, images_path, session=remote_session) + utils_disk.umount(mount_nvram_path, nvram_path, session=remote_session) + utils_disk.umount(mount_swtpm_path, swtpm_path, session=remote_session) + remote_session.close() + + for path in [images_path, nvram_path, swtpm_path]: + process.run(f"umount {path}", shell=True, verbose=True) + + libvirt.setup_or_cleanup_nfs(is_setup=False) + process.run(f"rm -rf {export_dir}", shell=True, ignore_status=True) + + +def run(test, params, env): + """ + Migrate the guests with various tpm and firmware on canonical paths in shared_filesystems. + + :param test: test object + :param params: Dictionary with the test parameters + :param env: Dictionary with test environment. + """ + def setup_test(): + """ + Setup steps for cases + + """ + images_path = params.get("images_path") + tpm_args = eval(params.get("tpm_args", '{}')) + loader_dict = eval(params.get("loader_dict", "{}")) + + test.log.info("Setup steps for cases.") + + nonlocal local_qemu_obj + nonlocal remote_qemu_obj + local_qemu_obj, remote_qemu_obj = setup_for_shared_filesystems(params, test) + + blk_source = vm.get_first_disk_devices()['source'] + process.run(f"cp {blk_source} {images_path}", shell=True, verbose=True) + process.run("setsebool virt_use_nfs 1", shell=True, verbose=True) + remote.run_remote_cmd("setsebool virt_use_nfs 1", params) + + vmxml.remove_all_device_by_type('tpm') + if tpm_args: + tpm_dev = libvirt.create_tpm_dev(tpm_args) + vmxml.add_device(tpm_dev) + vmxml.sync() + + if boot_type == "bios": + os_dict = eval(params.get("os_dict")) + vmxml.del_os() + vmxml.setup_attrs(os=os_dict) + elif boot_type == "statless_uefi": + vmxml.os = libvirt_bios.remove_bootconfig_items_from_vmos(vmxml.os) + vmxml.setup_attrs(os=loader_dict) + else: + vmxml.setup_attrs(os=loader_dict) + vmxml.sync() + virsh.dumpxml(vm_name, debug=True) + migration_obj.setup_connection() + vm.start() + vm.wait_for_login().close() + + def verify_test_again(): + """ + Verify test again + + """ + test.log.info("Verify test again.") + dargs = {"check_disk_on_dest": "no"} + migration_obj.migration_test.post_migration_check([vm], dargs) + + def cleanup_test(): + """ + Cleanup steps for cases + """ + test.log.info("Cleanup steps for cases.") + migration_obj.cleanup_connection() + cleanup_for_shared_filesystems(params, test) + process.run("rm -rf /var/lib/libvirt/swtpm/*", shell=True, ignore_status=True) + process.run("rm -rf /var/lib/libvirt/qemu/nvram/*", shell=True, ignore_status=True) + nonlocal local_qemu_obj + if local_qemu_obj: + libvirt.customize_libvirt_config(None, config_type="qemu", remote_host=False, + is_recover=True, extra_params=params, + config_object=local_qemu_obj) + nonlocal remote_qemu_obj + if remote_qemu_obj: + del remote_qemu_obj + + vm_name = guest_os.get_vm(params) + boot_type = params.get("boot_type") + params.update({"main_vm": vm_name}) + local_qemu_obj = None + remote_qemu_obj = None + + vm = env.get_vm(vm_name) + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + if boot_type == "bios": + bkxml = vmxml.copy() + migration_obj = base_steps.MigrationBase(test, vm, params) + + try: + setup_test() + migration_obj.run_migration() + migration_obj.verify_default() + migration_obj.run_migration_back() + verify_test_again() + finally: + cleanup_test() + if boot_type == "bios": + bkxml.sync() diff --git a/libvirt/tests/src/migration/migration_misc/migration_with_cpu_mode.py b/libvirt/tests/src/migration/migration_misc/migration_with_cpu_mode.py new file mode 100644 index 00000000000..262c0691dde --- /dev/null +++ b/libvirt/tests/src/migration/migration_misc/migration_with_cpu_mode.py @@ -0,0 +1,55 @@ +import os + +from virttest import data_dir +from virttest import virsh +from virttest.libvirt_xml import vm_xml + +from provider.migration import base_steps + + +def run(test, params, env): + """ + Verify that migration can succeed when cpu mode is configured. + + :param test: test object + :param params: Dictionary with the test parameters + :param env: Dictionary with test environment. + """ + def setup_test(): + """ + Setup steps + + """ + cpu_mode = params.get("cpu_mode") + migration_option = params.get("migration_option") + + test.log.info("Setup steps.") + migration_obj.setup_connection() + vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) + if cpu_mode == "host_model": + vm_attrs = eval(params.get('vm_attrs', '{}')) + vmxml.setup_attrs(**vm_attrs) + vmxml.sync() + else: + base_steps.sync_cpu_for_mig(params) + + if not vm.is_alive(): + vm.start() + vm.wait_for_login().close() + + if migration_option == "with_xml": + xmlfile = os.path.join(data_dir.get_tmp_dir(), '%s.xml' % vm_name) + virsh.dumpxml(vm_name, extra="--migratable", to_file=xmlfile, ignore_status=False) + params.update({"virsh_migrate_extra": f"--xml {xmlfile}"}) + + 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() + migration_obj.verify_default() + finally: + migration_obj.cleanup_connection() diff --git a/libvirt/tests/src/migration/migration_misc/migration_with_host_uuid.py b/libvirt/tests/src/migration/migration_misc/migration_with_host_uuid.py new file mode 100644 index 00000000000..a71eb146a01 --- /dev/null +++ b/libvirt/tests/src/migration/migration_misc/migration_with_host_uuid.py @@ -0,0 +1,54 @@ +from virttest.utils_test import libvirt + +from provider.migration import base_steps + +local_obj = None + + +def run(test, params, env): + """ + To verify that migration will fail if source host and target host have + same host_uuid. + + :param test: test object + :param params: Dictionary with the test parameters + :param env: Dictionary with test environment. + """ + def setup_test(): + """ + Setup steps for cases + + """ + test.log.info("Setup steps for cases.") + libvirtd_conf = eval(params.get("libvirtd_conf")) + + local_obj = libvirt.customize_libvirt_config(libvirtd_conf, + remote_host=True, + extra_params=params) + migration_obj.setup_connection() + + def cleanup_test(): + """ + Cleanup steps for cases + + """ + migration_obj.cleanup_connection() + global local_obj + if local_obj: + libvirt.customize_libvirt_config(None, + remote_host=True, + is_recover=True, + extra_params=params, + config_object=local_obj) + + 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() + migration_obj.verify_default() + finally: + cleanup_test() diff --git a/libvirt/tests/src/migration/migration_misc/migration_with_special_cpu.py b/libvirt/tests/src/migration/migration_misc/migration_with_special_cpu.py new file mode 100644 index 00000000000..d1a9a319f9d --- /dev/null +++ b/libvirt/tests/src/migration/migration_misc/migration_with_special_cpu.py @@ -0,0 +1,347 @@ +import os +import shutil + +from aexpect import remote + +from avocado.utils import process + +from virttest import data_dir +from virttest import migration +from virttest import nfs +from virttest import ssh_key +from virttest import utils_conn +from virttest import utils_disk +from virttest import utils_libvirtd +from virttest import utils_iptables +from virttest import utils_misc +from virttest import utils_net +from virttest import virsh + +from virttest.libvirt_xml import vm_xml +from virttest.utils_libvirt import libvirt_nested +from virttest.utils_libvirt import libvirt_vmxml +from virttest.utils_test import libvirt + +tcp_obj = None + + +def prepare_package_in_vm(vm): + """ + Prepare libvirt/qemu package in vm + + :param vm: VM object + """ + if not vm.is_alive(): + vm.start() + vm_session = vm.wait_for_login() + libvirt_nested.install_virt_pkgs(vm_session) + utils_libvirtd.Libvirtd(all_daemons=True, session=vm_session).restart() + vm_session.close() + + +def update_cpu_xml(vm_xml, cpu_mode, test, feature_list=None): + """ + Update cpu xml + + :param vm_xml: VM xml + :param cpu_mode: CPU mode + :param test: Test object + :param feature_list: Feature list + :return: New VM xml + """ + cpu_xml = vm_xml.cpu + cpu_xml.mode = cpu_mode + if feature_list: + for key, value in feature_list.items(): + try: + vmx_index = cpu_xml.get_feature_index(key) + except Exception as detail: + test.log.debug("Got a exception: %s", detail) + cpu_xml.add_feature(name=key, policy=value) + 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) + vm_xml.sync() + return vm_xml + + +def prepare_env_in_vm(vm, vm_hostname, mount_src, mount_dir, desturi_port): + """ + Prepare env in vm + + :param vm: VM object + :param vm_hostname: VM hostname + :param mount_src: Mount source + :param mount_dir: Mount dir + :param desturi_port: Desturi port + """ + vm_session = vm.wait_for_login() + cmd = "mkdir -p %s" % mount_src + vm_session.cmd_status_output(cmd) + + cmd = "mkdir -p %s" % mount_dir + vm_session.cmd_status_output(cmd) + + cmd = "hostnamectl set-hostname %s" % vm_hostname + vm_session.cmd_status_output(cmd) + + cmd = "setsebool virt_use_nfs 1 -P" + vm_session.cmd_status_output(cmd) + + firewall_cmd = utils_iptables.Firewall_cmd(vm_session) + firewall_cmd.add_service('nfs', permanent=True) + firewall_cmd.add_port(desturi_port, 'tcp', permanent=True) + + vm_session.close() + + +def prepare_nfs_server_in_vm(vm_ip, vm, params): + """ + Prepare nfs server in vm + + :param vm_ip: VM ip + :param vm: VM object + :param params: Dictionary with the test parameters + """ + server_user = params.get("server_user", "root") + server_pwd = params.get("server_pwd") + mount_src = params.get("nfs_mount_src") + mount_dir = params.get("nfs_mount_dir") + + vm_session = vm.wait_for_login() + vm_session.cmd("systemctl restart nfs-server; systemctl restart rpcbind") + vm_session.close() + + # prepare nfs server in vm + nfs_server_params = { + "nfs_setup": True, + "nfs_mount_dir": mount_dir, + "nfs_mount_src": mount_src, + "nfs_mount_options": params.get("nfs_mount_options"), + "nfs_server_ip": vm_ip, + "nfs_server_pwd": server_pwd, + "nfs_server_user": server_user, + "run_mount": False, + "setup_remote_nfs": "yes", + "export_options": params.get("export_options") + } + + nfs_server = nfs.Nfs(nfs_server_params) + nfs_server.setup() + + +def prepare_both_vms(params, vm1, vm2, vm1_xml, vm2_xml, test): + """ + Prepare vms + + :param params: Dictionary with the test parameters + :param vm1: VM1 object + :param vm2: VM2 object + :param vm1_xml: VM1 xml + :param vm2_xml: VM2 xml + :param test: Test object + """ + server_user = params.get("server_user", "root") + server_pwd = params.get("server_pwd") + client_user = params.get("client_user", "root") + client_pwd = params.get("client_pwd") + mount_src = params.get("nfs_mount_src") + mount_dir = params.get("nfs_mount_dir") + vm1_hostname = params.get("vm1_hostname") + vm2_hostname = params.get("vm2_hostname") + desturi_port = params.get("migrate_desturi_port") + cpu_mode = params.get("cpu_mode") + l1vm_feature_list = eval(params.get("l1vm_feature_list")) + + 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() + + vm1_ip = prepare_single_vm(vm1, vm1_xml, vm1_hostname, test) + vm2_ip = prepare_single_vm(vm2, vm2_xml, vm2_hostname, test) + + ssh_key.setup_ssh_key(vm1_ip, server_user, server_pwd, 22) + ssh_key.setup_ssh_key(vm2_ip, client_user, client_pwd, 22) + ssh_key.setup_remote_ssh_key(vm1_ip, server_user, server_pwd, vm2_ip, client_user, client_pwd, port=22) + ssh_key.setup_remote_ssh_key(vm2_ip, client_user, client_pwd, vm1_ip, server_user, server_pwd, port=22) + + test.log.debug("Prepare nfs server in %s.", vm1_ip) + prepare_nfs_server_in_vm(vm1_ip, vm1, params) + + 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() + + return vm1_ip, vm2_ip + + +def run(test, params, env): + """ + This case is to verify that migration can succeed in a nested environment + which both source and target host have special CPU. + + :param test: test object + :param params: Dictionary with the test parameters + :param env: Dictionary with test environment. + """ + def setup_test(): + """ + Setup steps for cases + + """ + test.log.info("Setup steps for cases.") + + server_user = params.get("server_user", "root") + server_pwd = params.get("server_pwd") + mount_dir = params.get("nfs_mount_dir") + + nonlocal vm1_ip, vm2_ip + vm1_ip, vm2_ip = prepare_both_vms(params, vm1, vm2, vm1_xml, vm2_xml, test) + + # Prepare TCP connection in vm + params.update({"server_ip": vm2_ip}) + params.update({"client_ip": vm1_ip}) + global tcp_obj + tcp_obj = utils_conn.TCPConnection(params) + tcp_obj.conn_setup() + + test.log.debug("Prepare %s image.", l2vm_name) + disk_dict = {'source': {'attrs': {'file': (os.path.join(mount_dir, l2vm_name) + ".qcow2")}}} + l2vm_xml.vm_name = l2vm_name + libvirt_vmxml.modify_vm_device(l2vm_xml, 'disk', disk_dict, sync_vm=False) + remote.scp_to_remote(vm1_ip, '22', server_user, server_pwd, l2vm_img, mount_dir) + remote.scp_to_remote(vm1_ip, '22', server_user, server_pwd, l2vm_xml.xml, l2vm_xml.xml) + + dest_uri = "qemu+tcp://%s/system" % vm2_ip + migration_test.migrate_pre_setup(dest_uri, params) + + desturi = "qemu+ssh://%s/system" % vm1_ip + virsh.define(l2vm_xml.xml, uri=desturi, debug=True) + virsh.start(l2vm_name, uri=desturi, debug=True) + + def run_migration(): + """ + Run migration + + """ + postcopy_options = params.get("postcopy_options") + options = params.get("virsh_migrate_options") + + test.log.debug("Run migration.") + desturi = "qemu+ssh://%s/system" % vm1_ip + dest_uri = "qemu+tcp://%s/system" % vm2_ip + ret = virsh.migrate(l2vm_name, dest_uri=dest_uri, uri=desturi, option=options, extra=postcopy_options, debug=True) + libvirt.check_exit_status(ret) + + def verify_test(): + """ + Verify steps + + """ + def _check_l2vm_ip(): + ret = virsh.domifaddr(l2vm_name, uri=dest_uri, debug=True) + if "ipv4" in ret.stdout_text.strip(): + return True + else: + return False + + server_user = params.get("server_user", "root") + server_pwd = params.get("server_pwd") + + test.log.debug("Verify steps.") + dest_uri = "qemu+ssh://%s/system" % vm2_ip + utils_misc.wait_for(_check_l2vm_ip, timeout=120, step=5) + ret = virsh.domifaddr(l2vm_name, uri=dest_uri, debug=True) + l2vm_ip = ret.stdout_text.strip().split(" ")[-1].split("/")[0] + test.log.debug("l2vm_ip: %s", l2vm_ip) + + vm2_session = vm2.wait_for_login() + vm2_session.cmd_status_output("yum install sshpass -y") + status, out = vm2_session.cmd_status_output("sshpass -p %s ssh -o StrictHostKeyChecking=no %s@%s 'echo simple_disk_check >> /tmp/simple_disk_check'" % (server_pwd, server_user, l2vm_ip)) + vm2_session.close() + if status != 0: + test.fail("Failed to write l2vm: %s" % out) + + def cleanup_test(): + """ + Cleanup steps + + """ + test.log.debug("Cleanup test.") + global tcp_obj + if tcp_obj: + tcp_obj.auto_recover = True + del tcp_obj + + 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) + + bak_vm2_xml.sync() + if os.path.exists(l2vm_img): + os.remove(l2vm_img) + revert_vm_setup(vm2, vm2_img, vm2_img_bak) + revert_vm_setup(vm1, vm1_img, vm1_img_bak) + + #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")}) + + 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.") + + cpu_mode = params.get("cpu_mode") + l2vm_name = params.get("l2vm_name") + migration_test = migration.MigrationTest() + vm1_ip = vm2_ip = None + + cmd = "virsh domcapabilities |grep vmx- |wc -l" + ret = process.run(cmd, shell=True, verbose=True).stdout_text.strip() + if int(ret) < 76: + test.error(f"Tested CPU capability {eval(params.get('l1vm_feature_list'))} not available on host.") + + vm1 = env.get_vm(vm1_name) + vm2 = env.get_vm(vm2_name) + + vm1_xml = vm_xml.VMXML.new_from_inactive_dumpxml(vm1_name) + vm2_xml = vm_xml.VMXML.new_from_inactive_dumpxml(vm2_name) + bak_vm2_xml = vm2_xml.copy() + + l2vm_xml = vm1_xml.copy() + l2vm_xml = update_cpu_xml(l2vm_xml, cpu_mode, test) + + vm1_img = vm1.get_first_disk_devices()['source'] + vm2_img = vm2.get_first_disk_devices()['source'] + test.log.debug("vm1 img: %s", vm1_img) + test.log.debug("vm2 img: %s", vm2_img) + + # Backup l2vm image + l2vm_img = os.path.join(os.path.join(data_dir.get_data_dir(), 'images'), l2vm_name) + '.qcow2' + test.log.debug("l2vm img: %s", l2vm_img) + shutil.copyfile(vm1_img, l2vm_img) + # Backup vm1 image + vm1_img_bak = vm1_img + ".bak" + shutil.copyfile(vm1_img, vm1_img_bak) + # Backup vm2 image + vm2_img_bak = vm2_img + ".bak" + shutil.copyfile(vm2_img, vm2_img_bak) + + try: + setup_test() + run_migration() + verify_test() + finally: + cleanup_test() diff --git a/libvirt/tests/src/migration/migration_misc/non_canonical_paths_in_shared_filesystems.py b/libvirt/tests/src/migration/migration_misc/non_canonical_paths_in_shared_filesystems.py new file mode 100644 index 00000000000..78c96381c1d --- /dev/null +++ b/libvirt/tests/src/migration/migration_misc/non_canonical_paths_in_shared_filesystems.py @@ -0,0 +1,175 @@ +import os + +from avocado.utils import process + +from virttest import libvirt_remote +from virttest import remote +from virttest import utils_config +from virttest import utils_disk +from virttest import utils_misc +from virttest.utils_test import libvirt + +from provider.migration import base_steps + + +def setup_for_shared_filesystems(params, test): + """ + Setup for shared filesystems + + :param params: dict, test parameters + :param test: test object + """ + export_dir = params.get("export_dir") + nfs_images_path = params.get("nfs_images_path") + nfs_nvram_path = params.get("nfs_nvram_path") + nfs_swtpm_path = params.get("nfs_swtpm_path") + images_path = params.get("images_path") + nvram_path = params.get("nvram_path") + swtpm_path = params.get("swtpm_path") + nfs_mount_options = params.get("nfs_mount_options") + server_ip = params.get("server_ip") + server_user = params.get("server_user", "root") + server_pwd = params.get("server_pwd") + mount_images_path = params.get("mount_images_path") + mount_nvram_path = params.get("mount_nvram_path") + mount_swtpm_path = params.get("mount_swtpm_path") + + if not os.path.exists(export_dir): + os.mkdir(export_dir) + + mount_opt = "rw,no_root_squash,sync" + res = libvirt.setup_or_cleanup_nfs(is_setup=True, + is_mount=False, + export_options=mount_opt, + export_dir=export_dir) + + for path in [nfs_images_path, nfs_nvram_path, nfs_swtpm_path]: + if not utils_misc.check_exists(path): + process.run(f"mkdir -p {path}", shell=True, verbose=True) + + remote_session = remote.wait_for_login("ssh", server_ip, "22", server_user, server_pwd, r"[\#\$]\s*$") + utils_disk.mount(mount_images_path, images_path, session=remote_session) + utils_disk.mount(mount_nvram_path, nvram_path, session=remote_session) + utils_disk.mount(mount_swtpm_path, swtpm_path, session=remote_session) + remote_session.close() + + process.run(f"cd {nfs_images_path}; mkdir nfs; ln -s nfs nfs-link", shell=True, verbose=True) + + utils_disk.mount(nfs_images_path, images_path, options=nfs_mount_options) + utils_disk.mount(nfs_nvram_path, nvram_path, options=nfs_mount_options) + utils_disk.mount(nfs_swtpm_path, swtpm_path, options=nfs_mount_options) + + remote_obj = None + local_obj = None + qemu_conf_src = eval(params.get("qemu_conf_src", "{}")) + qemu_conf_dest = params.get("qemu_conf_dest", "{}") + qemu_conf_path = utils_config.LibvirtQemuConfig().conf_path + remote_obj = libvirt_remote.update_remote_file(params, qemu_conf_dest, qemu_conf_path) + local_obj = libvirt.customize_libvirt_config(qemu_conf_src, "qemu", remote_host=False, + extra_params=params) + return (local_obj, remote_obj) + + +def cleanup_for_shared_filesystems(params, test): + """ + Cleanup for shared filesystems + + :param params: dict, test parameters + :param test: test object + """ + images_path = params.get("images_path") + nvram_path = params.get("nvram_path") + swtpm_path = params.get("swtpm_path") + server_ip = params.get("server_ip") + server_user = params.get("server_user", "root") + server_pwd = params.get("server_pwd") + export_dir = params.get("export_dir") + mount_images_path = params.get("mount_images_path") + mount_nvram_path = params.get("mount_nvram_path") + mount_swtpm_path = params.get("mount_swtpm_path") + + test.log.info("Cleanup for shared_filesystems.") + for path in [images_path, nvram_path, swtpm_path]: + process.run(f"umount {path}", shell=True, verbose=True) + + remote_session = remote.wait_for_login("ssh", server_ip, "22", server_user, server_pwd, r"[\#\$]\s*$") + utils_disk.umount(mount_nvram_path, nvram_path, session=remote_session) + utils_disk.umount(mount_swtpm_path, swtpm_path, session=remote_session) + utils_disk.umount(mount_images_path, images_path, session=remote_session) + remote_session.close() + + libvirt.setup_or_cleanup_nfs(is_setup=False) + process.run(f"rm -rf {export_dir}", shell=True, ignore_status=True) + + +def run(test, params, env): + """ + Use non-canonical paths in shared_filesystems. Then migrate the domain + based on the non-canonical paths. + + :param test: test object + :param params: Dictionary with the test parameters + :param env: Dictionary with test environment. + """ + def setup_test(): + """ + Setup steps for cases + + """ + soft_link = params.get("soft_link") + + test.log.info("Setup steps for cases.") + + nonlocal local_qemu_obj + nonlocal remote_qemu_obj + local_qemu_obj, remote_qemu_obj = setup_for_shared_filesystems(params, test) + + blk_source = vm.get_first_disk_devices()['source'] + process.run(f"cp {blk_source} {soft_link}", shell=True, verbose=True) + process.run("setsebool virt_use_nfs on", shell=True, verbose=True) + remote.run_remote_cmd("setsebool virt_use_nfs on", params) + + migration_obj.setup_connection() + + def verify_test_again(): + """ + Verify test again + + """ + test.log.info("Verify test again.") + dargs = {"check_disk_on_dest": "no"} + migration_obj.migration_test.post_migration_check([vm], dargs) + + def cleanup_test(): + """ + Cleanup steps for cases + """ + test.log.info("Cleanup steps for cases.") + migration_obj.cleanup_connection() + cleanup_for_shared_filesystems(params, test) + process.run("rm -rf /var/lib/libvirt/swtpm/*", shell=True, ignore_status=True) + process.run("rm -rf /var/lib/libvirt/qemu/nvram/*", shell=True, ignore_status=True) + nonlocal local_qemu_obj + if local_qemu_obj: + libvirt.customize_libvirt_config(None, config_type="qemu", remote_host=False, + is_recover=True, extra_params=params, + config_object=local_qemu_obj) + nonlocal remote_qemu_obj + if remote_qemu_obj: + del remote_qemu_obj + + vm_name = params.get("migrate_main_vm") + local_qemu_obj = None + remote_qemu_obj = None + + vm = env.get_vm(vm_name) + migration_obj = base_steps.MigrationBase(test, vm, params) + + try: + setup_test() + migration_obj.run_migration() + migration_obj.verify_default() + migration_obj.run_migration_back() + verify_test_again() + finally: + cleanup_test() diff --git a/libvirt/tests/src/migration/migration_misc/qemu_err_incoming_migration.py b/libvirt/tests/src/migration/migration_misc/qemu_err_incoming_migration.py new file mode 100644 index 00000000000..ec935c3b969 --- /dev/null +++ b/libvirt/tests/src/migration/migration_misc/qemu_err_incoming_migration.py @@ -0,0 +1,68 @@ +from avocado.utils import process + +from virttest import remote + +from virttest.libvirt_xml import vm_xml + +from provider.migration import base_steps + +hugepage_num = None + + +def run(test, params, env): + """ + This case is to verify that libvirt can report reasonable error when QEMU + fails with incoming migration. + + :param test: test object + :param params: Dictionary with the test parameters + :param env: Dictionary with test environment. + """ + def setup_test(): + """ + Setup steps + + """ + memory_backing = eval(params.get("memory_backing", "{}")) + hugepage_file = params.get("kernel_hp_file", "/proc/sys/vm/nr_hugepages") + nr_hugepages_src = params.get("nr_hugepages_src") + nr_hugepages_dest = params.get("nr_hugepages_dest") + + test.log.info("Setup steps for cases.") + migration_obj.setup_connection() + global hugepage_num + with open(hugepage_file, 'r') as fp: + hugepage_num = int(fp.readline().strip()) + + process.run(f"sysctl vm.nr_hugepages={nr_hugepages_src}", shell=True) + remote.run_remote_cmd(f"sysctl vm.nr_hugepages={nr_hugepages_dest}", params) + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + mem_backing = vm_xml.VMMemBackingXML() + mem_backing.setup_attrs(**memory_backing) + vmxml.mb = mem_backing + vmxml.sync() + vm.start() + vm.wait_for_login().close() + + def cleanup_test(): + """ + Cleanup steps for cases + + """ + test.log.info("Cleanup steps for cases.") + global hugepage_num + process.run(f"sysctl vm.nr_hugepages={hugepage_num}", shell=True) + remote.run_remote_cmd(f"sysctl vm.nr_hugepages={hugepage_num}", params) + migration_obj.cleanup_connection() + + 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() + migration_obj.verify_default() + finally: + cleanup_test() diff --git a/libvirt/tests/src/migration/migration_numa/migration_numatune.py b/libvirt/tests/src/migration/migration_numa/migration_numatune.py new file mode 100644 index 00000000000..ed05ec02d88 --- /dev/null +++ b/libvirt/tests/src/migration/migration_numa/migration_numatune.py @@ -0,0 +1,170 @@ +from aexpect import remote + +from virttest import libvirt_version +from virttest import test_setup +from virttest import utils_libvirtd +from virttest import virsh + +from virttest.libvirt_xml import vm_xml + +from provider.migration import base_steps +from provider.numa import numa_base + + +def update_numa_memnode(numatest, node0, node1): + """ + Update numa_memnode values using available numa nodes + + :param numatest: NumaTest object + :param node0: str, available numa node + :param node1: str, available numa node + """ + mem_mode = numatest.params.get("mem_mode") + numa_memnode = numatest.params.get("numa_memnode") + two_nodes = "%d,%d" % (node0, node1) + two_nodes = numa_base.convert_to_string_with_dash(two_nodes) + if mem_mode == "strict": + numa_memnode = numa_memnode % (node0, two_nodes) + elif mem_mode == "interleave": + numa_memnode = numa_memnode % (two_nodes, node1) + elif mem_mode == "preferred": + numa_memnode = numa_memnode % (two_nodes, node0) + elif mem_mode == "restrictive": + numa_memnode = numa_memnode % (node0, node1) + + numatest.params["numa_memnode"] = eval(numa_memnode) + + +def setup_test(numatest_src, numatest_dst, migration_obj): + """ + Setup steps + + :param numatest_src: NumaTest object for source host + :param numatest_dst: NumaTest object for target host + :param migration_obj: MigrationBase object + """ + numatest_src.test.log.info("Setup steps.") + numatest_src.setup(expect_node_free_mem_min=2097152) + src_numanodes = numatest_src.get_available_numa_nodes(expect_node_free_mem_min=2097152) + dst_numanodes = numatest_dst.get_available_numa_nodes(expect_node_free_mem_min=2097152) + same_node_ids = set(src_numanodes).intersection(set(dst_numanodes)) + if len(same_node_ids) < 2: + numatest_src.test.cancel("The two hosts do not have at least 2 numa nodes with same ID") + same_node_ids = list(same_node_ids) + node0 = same_node_ids[0] + node1 = same_node_ids[1] + update_numa_memnode(numatest_src, node0, node1) + vmxml = numatest_src.prepare_vm_xml(required_nodes=same_node_ids) + virsh.define(vmxml.xml, **numatest_src.virsh_dargs) + + if numatest_src.params.get('memory_backing'): + for numa_obj in [numatest_src, numatest_dst]: + session = numatest_dst.session if numa_obj == numatest_dst else None + numa_base.adjust_parameters(numa_obj.params, + hugepage_mem=int(numa_obj.params.get("hugepage_mem")), + target_nodes=f"{node0} {node1}") + hpc = test_setup.HugePageConfig(numa_obj.params, session=session) + hpc.setup() + numa_obj.params['hpc_list'] = [hpc] + utils_libvirtd.Libvirtd(session=session).restart() + numatest_src.test.log.info("Restart libvirt daemon to make hugepage " + "configration take effect.") + migration_obj.setup_connection() + + +def verify_test(numatest, migration_obj): + """ + Verify steps for cases + + :param numatest: NumaTest object for source host + :param migration_obj: MigrationBase object + + """ + numatest.test.log.info("Verify steps.") + desturi = migration_obj.params.get("virsh_migrate_desturi") + backup_uri, migration_obj.vm.connect_uri = migration_obj.vm.connect_uri, desturi + virsh_remote = virsh.VirshPersistent(uri=migration_obj.vm.connect_uri) + vmxml_remote = vm_xml.VMXML.new_from_dumpxml( + migration_obj.vm.name, virsh_instance=virsh_remote + ) + memory_backing = eval(numatest.params.get("memory_backing", "{}")) + if memory_backing: + mb_remote = vmxml_remote.mb + mb_remote_attr = mb_remote.fetch_attrs() + numatest.test.log.info("Memorybacking on remote vm: %s", mb_remote) + if memory_backing != mb_remote_attr: + numatest.test.fail("Expect memory backing to be '%s', " + "but found '%s'" % (memory_backing, mb_remote_attr)) + else: + numatest.test.log.debug("Verify memory backing on remote vm - PASS") + + actual_numa_memnodes = vmxml_remote.numa_memnode + actual_numa_memory = vmxml_remote.numa_memory + conf_numa_memory = numatest.params.get("numa_memory") + conf_numa_memnode = numatest.params.get("numa_memnode") + if actual_numa_memnodes != conf_numa_memnode: + numatest.test.fail("Expect numa memnode to be '%s' on remote vm, " + "but found '%s'" % (conf_numa_memnode, actual_numa_memnodes)) + else: + numatest.test.log.debug("Verify numa memnode on remote vm - PASS") + if actual_numa_memory != conf_numa_memory: + numatest.test.fail("Expect numa memory to be '%s' on remote vm, " + "but found '%s'" % (conf_numa_memory, actual_numa_memory)) + else: + numatest.test.log.debug("Verify numa memory on remote vm - PASS") + migration_obj.vm.connect_uri = backup_uri + migration_obj.verify_default() + + +def teardown_default(numatest_src, numatest_dst, migration_obj): + """ + Default teardown function for the test + + :param numatest_src: NumaTest object for source host + :param numatest_dst: NumaTest object for target host + :param migration_obj: MigrationBase object + """ + migration_obj.cleanup_connection() + for numatest_obj in [numatest_src, numatest_dst]: + numatest_obj.teardown() + numatest_obj.test.log.debug("Step: teardown is done") + + +def run(test, params, env): + """ + Verify that guest with externally launched virtiofs device can be migrated. + + Check numa nodes on both hosts are available and qualified which must + have at least same two IDs of numa nodes with memory. + Check numa memory is enough on both hosts + Setup hugepage if needed on both hosts + Do migration + Check hugepage setting in remote host after migration + + :param test: test object + :param params: Dictionary with the test parameters + :param env: Dictionary with test environment. + """ + libvirt_version.is_libvirt_feature_supported(params) + vm_name = params.get("migrate_main_vm") + server_ip = params.get("server_ip") + server_pwd = params.get("server_pwd") + vm = env.get_vm(vm_name) + migration_obj = base_steps.MigrationBase(test, vm, params) + remote_session = remote.remote_login( + client="ssh", + host=server_ip, + port=22, + username="root", + password=server_pwd, + prompt=r"[$#%]", + ) + numatest_dst = numa_base.NumaTest(None, params.copy(), test, session=remote_session) + numatest_src = numa_base.NumaTest(vm, params, test) + try: + setup_test(numatest_src, numatest_dst, migration_obj) + migration_obj.run_migration() + verify_test(numatest_src, migration_obj) + + finally: + teardown_default(numatest_src, numatest_dst, migration_obj) diff --git a/libvirt/tests/src/migration/migration_performance_tuning/migration_zerocopy.py b/libvirt/tests/src/migration/migration_performance_tuning/migration_zerocopy.py index 81fcb2bc198..b0c9bbf0c47 100644 --- a/libvirt/tests/src/migration/migration_performance_tuning/migration_zerocopy.py +++ b/libvirt/tests/src/migration/migration_performance_tuning/migration_zerocopy.py @@ -1,3 +1,5 @@ +from avocado.utils import distro + from virttest import libvirt_version from virttest import utils_misc from virttest import virsh @@ -20,16 +22,18 @@ def setup_params(): """ According to bug 2169733, multifd and postcopy migration will fail on RHEL 8. So update some parameters for postcopy cases. + Disable postcopy + multifd migration in qemu-kvm-8.1.0. """ postcopy_options = params.get("postcopy_options") - if not utils_misc.compare_qemu_version(8, 0, 0, is_rhev=False): + if (utils_misc.compare_qemu_version(8, 1, 0, is_rhev=False) or + (distro.detect().name == 'rhel' and int(distro.detect().version) == 8)): if postcopy_options: params.update({'action_during_mig': ''}) params.update({'status_error': 'yes'}) params.update({'err_msg': 'Postcopy is not yet compatible with multifd'}) - params.update({'check_str_local_log': ''}) + params.update({'check_str_local_log': '[]'}) params.update({'migrate_again_status_error': 'yes'}) def setup_with_memtune(): diff --git a/libvirt/tests/src/migration/migration_uri/migration_network_data_transport_tcp.py b/libvirt/tests/src/migration/migration_uri/migration_network_data_transport_tcp.py index 6dbeaf1f3a3..dc55dd5e329 100644 --- a/libvirt/tests/src/migration/migration_uri/migration_network_data_transport_tcp.py +++ b/libvirt/tests/src/migration/migration_uri/migration_network_data_transport_tcp.py @@ -7,6 +7,7 @@ from virttest import utils_net from virttest.utils_libvirt import libvirt_config +from virttest.utils_test import libvirt from provider.migration import base_steps from provider.migration import migration_base @@ -174,6 +175,7 @@ def cleanup_migration_host(): global remove_key_remote if remove_key_remote: del remove_key_remote + libvirt.remotely_control_libvirtd(server_ip, server_user, server_pwd, "restart") def cleanup_migration_address(): """ @@ -190,6 +192,7 @@ def cleanup_migration_address(): global remove_key_remote if remove_key_remote: del remove_key_remote + libvirt.remotely_control_libvirtd(server_ip, server_user, server_pwd, "restart") if ipv4_env_on_target: cleanup_ipv4_env(params) @@ -198,6 +201,9 @@ def cleanup_migration_address(): test_case = params.get('test_case', '') vm_name = params.get("migrate_main_vm") migrate_again = "yes" == params.get("migrate_again", "no") + server_ip = params.get("server_ip") + server_user = params.get("server_user", "root") + server_pwd = params.get("server_pwd") vm = env.get_vm(vm_name) migration_obj = base_steps.MigrationBase(test, vm, params) diff --git a/libvirt/tests/src/migration/migration_uri/tcp_migration_port_allocation_port_occupied_by_other_app.py b/libvirt/tests/src/migration/migration_uri/tcp_migration_port_allocation_port_occupied_by_other_app.py index 89ae5afbaf2..fef071955a1 100644 --- a/libvirt/tests/src/migration/migration_uri/tcp_migration_port_allocation_port_occupied_by_other_app.py +++ b/libvirt/tests/src/migration/migration_uri/tcp_migration_port_allocation_port_occupied_by_other_app.py @@ -14,13 +14,19 @@ def run(test, params, env): """ vm_name = params.get("migrate_main_vm") occupy_port_cmd = params.get("occupy_port_cmd") + server_ip = params.get("server_ip") + server_user = params.get("server_user", "root") + server_pwd = params.get("server_pwd") vm = env.get_vm(vm_name) migration_obj = base_steps.MigrationBase(test, vm, params) try: migration_obj.setup_connection() - remote.run_remote_cmd(occupy_port_cmd, params, ignore_status=False) + runner_on_target = remote.RemoteRunner(host=server_ip, + username=server_user, + password=server_pwd) + remote.run_remote_cmd(occupy_port_cmd, params, runner_on_target, ignore_status=False) migration_obj.run_migration() migration_obj.verify_default() finally: diff --git a/libvirt/tests/src/migration/migration_uri/tls_migrate_tls_x509_verify.py b/libvirt/tests/src/migration/migration_uri/tls_migrate_tls_x509_verify.py new file mode 100644 index 00000000000..66453d80b08 --- /dev/null +++ b/libvirt/tests/src/migration/migration_uri/tls_migrate_tls_x509_verify.py @@ -0,0 +1,149 @@ +import os +import shutil + +from virttest import libvirt_remote + +from virttest.utils_test import libvirt +from virttest.utils_libvirt import libvirt_config + +from provider.migration import base_steps + + +def update_qemu_conf_on_src(params, test, local_obj): + """ + Update qemu configure file on source + + :param params: Dictionary with the test parameter + :param test: Test object + :param local_obj: Local qemu conf object + """ + qemu_conf_src = eval(params.get("qemu_conf_src", "{}")) + + local_obj.append(libvirt.customize_libvirt_config(qemu_conf_src, + "qemu", + remote_host=False, + extra_params=params)) + + +def update_qemu_conf_on_target(params, test, remote_obj): + """ + Update qemu configure file on target + + :param params: Dictionary with the test parameter + :param test: Test object + :param remote_obj: Remote qemu conf object + """ + default_qemu_conf = params.get("default_qemu_conf") + qemu_conf_path = params.get("qemu_conf_path") + qemu_conf_dest = params.get("qemu_conf_dest", "{}") + + if default_qemu_conf: + params['file_path'] = qemu_conf_path + remote_obj.append(libvirt_config.remove_key_in_conf(eval(default_qemu_conf), + "qemu", + remote_params=params, + restart_libvirt=True)) + if qemu_conf_dest: + remote_obj.append(libvirt_remote.update_remote_file(params, + qemu_conf_dest, + qemu_conf_path)) + + +def run(test, params, env): + """ + Test default_tls_x509_verify/migrate_tls_x509_verify on source/target host. + + :param test: test object + :param params: Dictionary with the test parameters + :param env: Dictionary with test environment. + """ + def setup_migrate_tls_x509_verify_on_target(): + """ + Setup steps for migrate_tls_x509_verify_on_target + + """ + test.log.info("Setup steps for migrate_tls_x509_verify_on_target.") + cert_path = params.get("cert_path") + tmp_cert_path = params.get("tmp_cert_path") + + update_qemu_conf_on_target(params, test, remote_obj) + migration_obj.setup_connection() + if os.path.exists(tmp_cert_path): + os.remove(tmp_cert_path) + shutil.move(cert_path, tmp_cert_path) + + def setup_migrate_tls_x509_verify_on_src(): + """ + Setup steps for migrate_tls_x509_verify_on_src + + """ + test.log.info("Setup steps for migrate_tls_x509_verify_on_src.") + + update_qemu_conf_on_src(params, test, local_obj) + migration_obj.setup_connection() + + def run_migration_again_migrate_tls_x509_verify_on_target(): + """ + Run migration again for migrate_tls_x509_verify_on_target + + """ + test.log.info("Run migration again for migrate_tls_x509_verify_on_target.") + cert_path = params.get("cert_path") + tmp_cert_path = params.get("tmp_cert_path") + + if os.path.exists(cert_path): + os.remove(cert_path) + shutil.move(tmp_cert_path, cert_path) + migration_obj.run_migration_again() + + def cleanup_migrate_tls_x509_verify_on_target(): + """ + Cleanup steps for migrate_tls_x509_verify_on_target + + """ + test.log.info("Cleanup steps migrate_tls_x509_verify_on_target.") + migration_obj.cleanup_connection() + if remote_obj: + for obj in remote_obj: + del obj + + def cleanup_migrate_tls_x509_verify_on_src(): + """ + Cleanup steps for migrate_tls_x509_verify_on_src + + """ + test.log.info("Cleanup steps migrate_tls_x509_verify_on_src.") + migration_obj.cleanup_connection() + if local_obj: + for obj in local_obj: + libvirt.customize_libvirt_config(None, + config_type="qemu", + remote_host=False, + is_recover=True, + extra_params=params, + config_object=obj) + + migrate_again = "yes" == params.get("migrate_again", "no") + vm_name = params.get("migrate_main_vm") + test_case = params.get('test_case', '') + + vm = env.get_vm(vm_name) + migration_obj = base_steps.MigrationBase(test, vm, params) + setup_test = eval("setup_%s" % test_case) if "setup_%s" % test_case in \ + locals() else migration_obj.setup_connection + run_migration_again_test = eval("run_migration_again_%s" % test_case) if "run_migration_again_%s" % test_case in \ + locals() else migration_obj.run_migration_again + cleanup_test = eval("cleanup_%s" % test_case) if "cleanup_%s" % test_case in \ + locals() else migration_obj.cleanup_connection + + remote_obj = [] + local_obj = [] + + try: + setup_test() + migration_obj.run_migration() + if migrate_again: + run_migration_again_test() + migration_obj.verify_default() + finally: + cleanup_test() diff --git a/libvirt/tests/src/migration/migration_with_numa_topology.py b/libvirt/tests/src/migration/migration_with_numa_topology.py new file mode 100644 index 00000000000..31d36f3a7d8 --- /dev/null +++ b/libvirt/tests/src/migration/migration_with_numa_topology.py @@ -0,0 +1,94 @@ +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Copyright Red Hat +# +# SPDX-License-Identifier: GPL-2.0 +# +# Author: Liang Cong +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +from virttest import utils_misc +from virttest import migration_template as mt +from virttest.libvirt_xml import vm_xml + + +class MigrationWithNumaTopology(mt.MigrationTemplate): + + def __init__(self, test, env, params, *args, **dargs): + super().__init__(test, env, params, *args, **dargs) + + @staticmethod + @mt.vm_session_handler + def check_guest_numa_cpu(vm, test, params): + """ + Check cpu id on each guest numa node + + :param vm: guest vm object + :param test: test object + :param params: test parameters + """ + node_num = int(params.get("node_num")) + exp_nodes_cpu_list = [utils_misc.cpu_str_to_list(params.get( + "node_%s_cpu" % i)) if params.get("node_%s_cpu" % i) else [] for i in range(node_num)] + guest_numa_info = utils_misc.NumaInfo(session=vm.session) + act_nodes_cpu_list = [] + for node_index in range(len(guest_numa_info.nodes)): + cpu_list = list(map(int, guest_numa_info.nodes[node_index].cpus)) + act_nodes_cpu_list.append(cpu_list) + test.log.debug("guest node %s has cpus: %s" % + (node_index, cpu_list)) + if exp_nodes_cpu_list != act_nodes_cpu_list: + test.fail("Expect numa nodes cpu list is %s, but get %s" % + (exp_nodes_cpu_list, act_nodes_cpu_list)) + + def _pre_start_vm(self): + """ + Operation before start guest on source host: + Define the guest + """ + vm_attrs = eval(self.params.get("vm_attrs", "{}")) + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(self.main_vm.name) + vmxml.setup_attrs(**vm_attrs) + vmxml.cpu.topology = eval(self.params.get("topology_dict", "{}")) + vmxml.sync() + + def _post_start_vm(self): + """ + Operation after start guest on source host: + Check guest numa cpu after guest starts + """ + self.check_guest_numa_cpu(self.main_vm, self.test, self.params) + + def _post_migrate(self): + """ + Operation after migration: + Check guest numa cpu after migration + """ + self.check_guest_numa_cpu(self.main_vm, self.test, self.params) + + def _post_migrate_back(self): + """ + Operation after back migration: + Check guest numa cpu after back migration + """ + self.check_guest_numa_cpu(self.main_vm, self.test, self.params) + + +def run(test, params, env): + """ + 1. Assign cpu topology with numa node + 2. Start guest + 3. Verify the guest cpu assignment for numa nodes on src host + 4. Do migration + 5. Verify the guest cpu assignment for numa nodes on dest host + 6. Do back migration + 7. Verify the guest cpu assignment for numa nodes on src host + """ + + migrationobj = MigrationWithNumaTopology(test, env, params) + try: + migrationobj.runtest() + finally: + migrationobj.cleanup() diff --git a/libvirt/tests/src/migration/migration_with_virtiofs/migration_with_externally_launched_virtiofs_dev.py b/libvirt/tests/src/migration/migration_with_virtiofs/migration_with_externally_launched_virtiofs_dev.py new file mode 100644 index 00000000000..d2f2ae99d33 --- /dev/null +++ b/libvirt/tests/src/migration/migration_with_virtiofs/migration_with_externally_launched_virtiofs_dev.py @@ -0,0 +1,114 @@ +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 provider.migration import base_steps + + +def run(test, params, env): + """ + Verify that guest with externally launched virtiofs device can be migrated. + + :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"mkdir -p {mnt_path_name}" + cmd2 = f"nohup /usr/libexec/virtiofsd --socket-path={socket_path} -o source={mnt_path_name} --log-level off > /dev/null 2>&1 & disown" + multi_cmd1 = f"{cmd1}; {cmd2}" + process.run(multi_cmd1, shell=True, ignore_status=False, ignore_bg_processes=True) + remote.run_remote_cmd(multi_cmd1, params, ignore_status=False) + cmd3 = f"chcon -t svirt_image_t {socket_path}" + cmd4 = f"chown qemu:qemu {socket_path}" + multi_cmd2 = f"{cmd3}; {cmd4}" + 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 steps for cases + + """ + test.log.info("Verify steps.") + desturi = params.get("virsh_migrate_desturi") + expect_str = params.get("expect_str") + + backup_uri, vm.connect_uri = vm.connect_uri, desturi + vm.cleanup_serial_console() + vm.create_serial_console() + vm_session = vm.wait_for_serial_login(timeout=120) + 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}') + vm.connect_uri = backup_uri + migration_obj.verify_default() + + def cleanup_test(): + """ + Cleanup steps for cases + + """ + socket_path = params.get("socket_path") + + migration_obj.cleanup_connection() + remote.run_remote_cmd('pkill virtiofsd', params, ignore_status=True) + remote.run_remote_cmd(f"rm -rf {socket_path}", params, ignore_status=True) + process.run("pkill virtiofsd", shell=True, ignore_status=True) + process.run(f"rm -rf {socket_path}", shell=True, ignore_status=True) + + 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: + cleanup_test() diff --git a/libvirt/tests/src/migration/migration_with_virtiofs/migration_with_internally_launched_virtiofs_dev.py b/libvirt/tests/src/migration/migration_with_virtiofs/migration_with_internally_launched_virtiofs_dev.py new file mode 100644 index 00000000000..798b0604d54 --- /dev/null +++ b/libvirt/tests/src/migration/migration_with_virtiofs/migration_with_internally_launched_virtiofs_dev.py @@ -0,0 +1,100 @@ +import re + +from avocado.utils import process + +from virttest import libvirt_version +from virttest import virsh + +from virttest.libvirt_xml import vm_xml +from virttest.utils_libvirt import libvirt_vmxml + +from provider.migration import base_steps + + +def run(test, params, env): + """ + Verify that guest with internally launched virtiofs device can be migrated. + + :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.") + 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") + + 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 steps for cases + + """ + test.log.info("Verify steps.") + desturi = params.get("virsh_migrate_desturi") + expect_str = params.get("expect_str") + test_file = params.get("test_file") + mnt_path_name = params.get("mnt_path_name") + + backup_uri, vm.connect_uri = vm.connect_uri, desturi + vm.cleanup_serial_console() + vm.create_serial_console() + vm_session = vm.wait_for_serial_login(timeout=120) + output = vm_session.cmd_output("df -h") + test.log.debug("output: %s", output) + if not re.search(expect_str, output): + test.fail(f'Expect content "{expect_str}" not in output: {output}') + cmd1 = f"dd if=/dev/zero of={test_file} bs=1M count=10; sync" + vm_session.cmd_output(cmd1) + cmd2 = f"md5sum {test_file}" + ret_in_vm = vm_session.cmd_output(cmd2) + test.log.debug("md5sum result: %s", ret_in_vm) + vm_session.close() + vm.connect_uri = backup_uri + + cmd3 = f"md5sum {mnt_path_name}/test_file" + ret_in_host = process.run(cmd3, shell=True, ignore_status=False) + if ret_in_vm.split()[0] != ret_in_host.stdout_text.split()[0]: + test.fail("md5 value in host is different from in vm.") + + migration_obj.verify_default() + + 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() diff --git a/libvirt/tests/src/migration/migration_with_vtpm/migration_with_external_tpm.py b/libvirt/tests/src/migration/migration_with_vtpm/migration_with_external_tpm.py index bfcb6c0d081..280d4d8ffc6 100644 --- a/libvirt/tests/src/migration/migration_with_vtpm/migration_with_external_tpm.py +++ b/libvirt/tests/src/migration/migration_with_vtpm/migration_with_external_tpm.py @@ -11,7 +11,6 @@ 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 @@ -84,41 +83,35 @@ def launch_external_swtpm(params, test, skip_setup=False, on_remote=False): tpm_dict = eval(params.get('tpm_dict', '{}')) source_socket = tpm_dict['backend']['source']['path'] statedir = params.get("statedir") - swtpm_setup_path = params.get("swtpm_setup_path") - swtpm_path = params.get("swtpm_path") test.log.info("Launch external swtpm process: (on_remote: %s)", on_remote) if not skip_setup: - cmd1 = 'chcon -t virtd_exec_t %s' % swtpm_setup_path - cmd2 = 'chcon -t virtd_exec_t %s' % swtpm_path if on_remote: remote.run_remote_cmd("rm -rf %s" % statedir, params) remote.run_remote_cmd("mkdir %s" % statedir, params) - remote.run_remote_cmd(cmd1, params) - remote.run_remote_cmd(cmd2, params) else: if os.path.exists(statedir): shutil.rmtree(statedir) os.mkdir(statedir) process.run("ls -lZd %s" % statedir) - process.run(cmd1, ignore_status=False, shell=True) - process.run(cmd2, ignore_status=False, shell=True) - cmd3 = "systemd-run %s --tpm2 --tpmstate %s --create-ek-cert --create-platform-cert --overwrite" % (swtpm_setup_path, statedir) - cmd4 = "systemd-run %s socket --ctrl type=unixio,path=%s,mode=0600 --tpmstate dir=%s,mode=0600 --tpm2 --terminate" % (swtpm_path, source_socket, statedir) + cmd1 = "swtpm_setup --tpm2 --tpmstate %s --create-ek-cert --create-platform-cert --overwrite" % statedir try: if not skip_setup: if on_remote: - remote.run_remote_cmd(cmd3, params) + remote.run_remote_cmd(cmd1, params) else: - process.run(cmd3, ignore_status=False, shell=True) + process.run(cmd1, ignore_status=False, shell=True) + cmd2 = ("nohup swtpm socket --ctrl type=unixio,path=%s,mode=0600 --tpmstate" + "dir=%s,mode=0600 --tpm2 --terminate > /dev/null 2>&1 & disown") % (source_socket, statedir) if on_remote: - remote.run_remote_cmd(cmd4, params) + remote.run_remote_cmd(cmd2, params) remote.run_remote_cmd('chcon -t svirt_image_t %s' % source_socket, params) remote.run_remote_cmd('chown qemu:qemu %s' % source_socket, params) else: - process.run(cmd4, ignore_status=False, shell=True) + process.run(cmd2, ignore_status=False, shell=True, ignore_bg_processes=True) + process.run("ps aux|grep 'swtpm socket'|grep -v avocado-runner-avocado-vt|grep -v grep", ignore_status=True, shell=True) # Make sure the socket is created - utils_misc.wait_for(lambda: os.path.isdir(source_socket), timeout=3) + utils_misc.wait_for(lambda: os.path.exists(source_socket), timeout=3) process.run('chcon -t svirt_image_t %s' % source_socket, ignore_status=False, shell=True) process.run('chown qemu:qemu %s' % source_socket, ignore_status=False, shell=True) except Exception as err: @@ -177,7 +170,8 @@ def setup_test(): """ tpm_security_contexts = params.get("tpm_security_contexts") - libvirt.set_vm_disk(vm, params) + test.log.debug("Setup steps.") + migration_obj.setup_connection() launch_external_swtpm(params, test) launch_external_swtpm(params, test, skip_setup=False, on_remote=True) setup_vtpm(params, test, vm) @@ -197,6 +191,9 @@ def verify_test_again(): """ tpm_security_contexts = params.get("tpm_security_contexts") + migrate_vm_back = "yes" == params.get("migrate_vm_back", "yes") + if not migrate_vm_back: + return check_vtpm_func(params, vm, test) vm.shutdown() @@ -208,28 +205,27 @@ def cleanup_test(): Cleanup steps """ - swtpm_setup_path = params.get("swtpm_setup_path") - swtpm_path = params.get("swtpm_path") statedir = params.get("statedir") - cmd1 = "restorecon %s" % swtpm_setup_path - cmd2 = "restorecon %s" % swtpm_path - process.run(cmd1, ignore_status=False, shell=True) - process.run(cmd2, ignore_status=False, shell=True) + remote.run_remote_cmd('pkill swtpm', params, ignore_status=True) + remote.run_remote_cmd("rm -rf /var/lib/swtpm-localca/*", params, ignore_status=True) + process.run("pkill swtpm", shell=True, ignore_status=True) + process.run("rm -rf /var/lib/swtpm-localca/*", shell=True, ignore_status=True) if os.path.exists(statedir): shutil.rmtree(statedir) - remote.run_remote_cmd(cmd1, params) - remote.run_remote_cmd(cmd2, params) remote.run_remote_cmd("rm -rf %s" % statedir, params) migration_obj.cleanup_connection() vm_name = params.get("migrate_main_vm") + desturi = params.get("virsh_migrate_desturi") libvirt_version.is_libvirt_feature_supported(params) vm = env.get_vm(vm_name) migration_obj = base_steps.MigrationBase(test, vm, params) try: + if not base_steps.check_cpu_for_mig(params): + base_steps.sync_cpu_for_mig(params) setup_test() migration_obj.run_migration() verify_test() diff --git a/libvirt/tests/src/migration/migration_with_vtpm/migration_with_shared_tpm.py b/libvirt/tests/src/migration/migration_with_vtpm/migration_with_shared_tpm.py index a920f52a475..6c5e30ed56f 100644 --- a/libvirt/tests/src/migration/migration_with_vtpm/migration_with_shared_tpm.py +++ b/libvirt/tests/src/migration/migration_with_vtpm/migration_with_shared_tpm.py @@ -1,11 +1,10 @@ import os -from avocado.utils import distro from avocado.utils import process -from virttest import ceph from virttest import libvirt_version from virttest import remote +from virttest import utils_disk from virttest import utils_package from virttest import virsh @@ -163,34 +162,6 @@ def setup_vtpm(params, test, vm, migration_obj): vm.wait_for_login().close() -def prepare_ceph_disk(params, test, vm): - """ - Prepare ceph disk - - :param params: dict, test parameters - :param vm: VM object - :param test: test object - """ - mon_host = params.get("mon_host") - disk_source_name = params.get("disk_source_name") - seclabel_dict = eval(params.get("seclabel_dict", "{}")) - vm_name = params.get("migrate_main_vm") - - detected_distro = distro.detect() - rbd_img_prefix = '_'.join(['rbd', detected_distro.name, - detected_distro.version, - detected_distro.release, - detected_distro.arch]) - disk_source_name = os.path.join(disk_source_name, rbd_img_prefix + '.img') - params.update({"disk_source_name": disk_source_name}) - ceph.rbd_image_rm(mon_host, disk_source_name.split("/")[0], - disk_source_name.split("/")[1]) - vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) - vmxml.set_seclabel([seclabel_dict]) - vmxml.sync() - libvirt.set_vm_disk(vm, params) - - def run(test, params, env): """ Test migration with vtpm device with shared TPM state. @@ -206,9 +177,21 @@ def setup_nfs(): """ tpm_security_contexts = params.get("tpm_security_contexts") + swtpm_path = params.get("swtpm_path") + client_ip = params.get("client_ip") + nfs_export_dir = params.get("nfs_export_dir") + server_ip = params.get("server_ip", params.get("remote_ip")) + server_user = params.get("server_user", params.get("remote_user")) + server_pwd = params.get("server_pwd", params.get("remote_pwd")) + src_mount_path = params.get("src_mount_path") test.log.info("Setup for nfs storage type.") - libvirt.set_vm_disk(vm, params) + migration_obj.setup_connection() + if not os.path.exists(swtpm_path): + os.mkdir(swtpm_path) + libvirt.setup_or_cleanup_nfs(True, mount_dir=swtpm_path, is_mount=True, export_dir=nfs_export_dir) + server_session = remote.wait_for_login("ssh", server_ip, "22", server_user, server_pwd, r"[\#\$]\s*$") + utils_disk.mount(src_mount_path, swtpm_path, session=server_session) setup_vtpm(params, test, vm, migration_obj) check_tpm_security_context(params, vm, test, tpm_security_contexts) check_swtpm_process(params, test) @@ -220,18 +203,31 @@ def setup_ceph(): """ tpm_security_contexts = params.get("tpm_security_contexts") - mon_host = params.get("mon_host") set_remote_libvirtd_log = "yes" == params.get("set_remote_libvirtd_log", "no") + swtpm_path = params.get("swtpm_path") + seclabel_dict = eval(params.get("seclabel_dict", "{}")) + ceph_key = params.get("ceph_key") + src_mount_path = params.get("src_mount_path") + server_ip = params.get("server_ip", params.get("remote_ip")) + server_user = params.get("server_user", params.get("remote_user")) + server_pwd = params.get("server_pwd", params.get("remote_pwd")) test.log.info("Setup for ceph storage type.") if set_remote_libvirtd_log: migration_obj.set_remote_log() - cmd = "mount -t ceph %s:6789:/ /var/lib/libvirt/swtpm -o name=admin" % mon_host - process.run(cmd, ignore_status=False, shell=True) - remote.run_remote_cmd(cmd, params) - - prepare_ceph_disk(params, test, vm) + if not os.path.exists(swtpm_path): + os.mkdir(swtpm_path) + utils_disk.mount(src_mount_path, swtpm_path, fstype="ceph", options="name=admin,secret=%s" % ceph_key) + server_session = remote.wait_for_login("ssh", server_ip, "22", server_user, server_pwd, r"[\#\$]\s*$") + utils_disk.mount(src_mount_path, swtpm_path, fstype="ceph", options="name=admin,secret=%s" % ceph_key, session=server_session) + process.run("restorecon -Rv /var/lib/libvirt/swtpm", ignore_status=False, shell=True) + server_session.close() + + vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) + vmxml.set_seclabel([seclabel_dict]) + vmxml.sync() + migration_obj.setup_connection() setup_vtpm(params, test, vm, migration_obj) check_tpm_security_context(params, vm, test, tpm_security_contexts) check_swtpm_process(params, test) @@ -250,35 +246,53 @@ def verify_test_again(): Verify steps for migration back """ + migrate_vm_back = "yes" == params.get("migrate_vm_back", "yes") + if not migrate_vm_back: + return + tpm_security_contexts_restore = params.get("tpm_security_contexts_restore") check_vtpm_func(params, vm, test) vm.shutdown() vm.wait_for_shutdown() check_tpm_security_context(params, vm, test, tpm_security_contexts_restore) - def cleanup_ceph(): + def cleanup_test(): """ - Cleanup steps for ceph case + Cleanup steps """ - cmd = "umount /var/lib/libvirt/swtpm" - process.run(cmd, ignore_status=False, shell=True) - remote.run_remote_cmd(cmd, params) + src_mount_path = params.get("src_mount_path") + swtpm_path = params.get("swtpm_path") + nfs_export_dir = params.get("nfs_export_dir") + server_ip = params.get("server_ip", params.get("remote_ip")) + server_user = params.get("server_user", params.get("remote_user")) + server_pwd = params.get("server_pwd", params.get("remote_pwd")) + + test.log.info("Cleanup steps.") + server_session = remote.wait_for_login("ssh", server_ip, "22", server_user, server_pwd, r"[\#\$]\s*$") + if shared_storage_type == "ceph": + utils_disk.umount(src_mount_path, swtpm_path, fstype="ceph") + utils_disk.umount(src_mount_path, swtpm_path, fstype="ceph", session=server_session) + else: + utils_disk.umount("127.0.0.1:%s" % nfs_export_dir, swtpm_path) + utils_disk.umount(src_mount_path, swtpm_path, session=server_session) + server_session.close() migration_obj.cleanup_connection() vm_name = params.get("migrate_main_vm") shared_storage_type = params.get('shared_storage_type', '') + desturi = params.get("virsh_migrate_desturi") libvirt_version.is_libvirt_feature_supported(params) vm = env.get_vm(vm_name) migration_obj = base_steps.MigrationBase(test, vm, params) setup_test = eval("setup_%s" % shared_storage_type) if "setup_%s" % shared_storage_type in \ locals() else migration_obj.setup_connection - cleanup_test = eval("cleanup_%s" % shared_storage_type) if "cleanup_%s" % shared_storage_type in \ - locals() else migration_obj.cleanup_connection try: set_secret(params) + if not base_steps.check_cpu_for_mig(params): + base_steps.sync_cpu_for_mig(params) setup_test() migration_obj.run_migration() verify_test() diff --git a/libvirt/tests/src/migration/migration_with_vtpm/migration_with_vtpm_dev.py b/libvirt/tests/src/migration/migration_with_vtpm/migration_with_vtpm_dev.py new file mode 100644 index 00000000000..c83f1f9a528 --- /dev/null +++ b/libvirt/tests/src/migration/migration_with_vtpm/migration_with_vtpm_dev.py @@ -0,0 +1,240 @@ +import os + +from avocado.utils import process + +from virttest import remote +from virttest import utils_package +from virttest import virsh + +from virttest.libvirt_xml import vm_xml +from virttest.utils_libvirt import libvirt_secret +from virttest.utils_libvirt import libvirt_vmxml +from virttest.utils_test import libvirt + +from provider.migration import base_steps + +src_sec_uuid = None +dst_sec_uuid = None + + +def check_vtpm_func(params, vm, test, remote=False): + """ + Check vtpm function + + :param params: dict, test parameters + :param vm: VM object + :param test: test object + :param remote: True to check context on remote + """ + tpm_cmd = params.get("tpm_cmd") + dest_uri = params.get("virsh_migrate_desturi") + src_uri = params.get("virsh_migrate_connect_uri") + test.log.debug("Check vtpm func: %s (remote).", remote) + if remote: + if vm.serial_console is not None: + vm.cleanup_serial_console() + vm.connect_uri = dest_uri + if vm.serial_console is None: + vm.create_serial_console() + vm_session = vm.wait_for_serial_login(timeout=240) + if not utils_package.package_install("tpm2-tools", vm_session): + test.error("Failed to install tpm2-tools in vm") + cmd_result = vm_session.cmd_status(tpm_cmd) + vm_session.close() + if remote: + if vm.serial_console is not None: + vm.cleanup_serial_console() + vm.connect_uri = src_uri + if cmd_result: + test.fail("Fail to run '%s': %s." % (tpm_cmd, cmd_result)) + + +def set_secret(params): + """ + Set secret + + :param params: dict, test parameters + """ + auth_sec_dict = eval(params.get("auth_sec_dict")) + src_secret_value = params.get("src_secret_value") + src_secret_value_path = params.get("src_secret_value_path") + dst_secret_value = params.get("dst_secret_value") + dst_secret_value_path = params.get("dst_secret_value_path") + remote_pwd = params.get("migrate_dest_pwd") + remote_ip = params.get("migrate_dest_host") + remote_user = params.get("remote_user", "root") + + def _create_secret(session=None, remote_args=None, secret_value_path=None): + """ + create secret + + :param session: a session object of remote host + :param remote_args: remote host parameters + :param secret_value_path: the path of secret value + """ + libvirt_secret.clean_up_secrets(session) + global dst_sec_uuid + global src_sec_uuid + if remote_args: + dst_sec_uuid = libvirt.create_secret(auth_sec_dict, remote_args=remote_args) + else: + src_sec_uuid = libvirt.create_secret(auth_sec_dict) + auth_sec_dict.update({"sec_uuid": src_sec_uuid}) + if os.path.exists(secret_value_path): + os.remove(secret_value_path) + if session: + cmd = "echo '%s' > %s" % (dst_secret_value, secret_value_path) + process.run(cmd, shell=True) + remote.scp_to_remote(remote_ip, '22', remote_user, remote_pwd, + secret_value_path, secret_value_path, + limit="", log_filename=None, timeout=60, + interface=None) + cmd = f"virsh secret-set-value {dst_sec_uuid} --file {secret_value_path} --plain" + remote.run_remote_cmd(cmd, params) + else: + cmd = "echo '%s' > %s" % (src_secret_value, secret_value_path) + process.run(cmd, shell=True) + cmd = f"virsh secret-set-value {src_sec_uuid} --file {secret_value_path} --plain" + process.run(cmd, shell=True) + + _create_secret(secret_value_path=src_secret_value_path) + params.update({"auth_sec_dict": auth_sec_dict}) + virsh_dargs = {'remote_ip': remote_ip, 'remote_user': remote_user, + 'remote_pwd': remote_pwd, 'unprivileged_user': None, + 'ssh_remote_auth': True} + remote_virsh_session = None + remote_virsh_session = virsh.VirshPersistent(**virsh_dargs) + _create_secret(session=remote_virsh_session, remote_args=virsh_dargs, + secret_value_path=dst_secret_value_path) + + +def setup_vtpm(params, test, vm, migration_obj): + """ + Setup vTPM device in guest xml + + :param params: dict, test parameters + :param vm: VM object + :param test: test object + :param migration_obj: migration object + """ + vm_name = params.get("migrate_main_vm") + tpm_dict = eval(params.get('tpm_dict', '{}')) + auth_sec_dict = params.get("auth_sec_dict") + + test.log.info("Setup vTPM device in guest xml.") + if vm.is_alive(): + vm.destroy(gracefully=False) + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + # Remove all existing tpm devices + vmxml.remove_all_device_by_type('tpm') + + tpm_dict['backend']['encryption_secret'] = auth_sec_dict['sec_uuid'] + libvirt_vmxml.modify_vm_device(vmxml, 'tpm', tpm_dict) + + vm.start() + vm.wait_for_login().close() + + +def check_ownership(swtpm_log, expected_ownership, test): + """ + Check ownership + + :param swtpm_log: swtpm log path + :param expected_ownership: Expected ownership + :param test: test object + """ + cmd = "ls -lZ %s" % swtpm_log + ret = process.run(cmd, shell=True).stdout_text.strip() + if expected_ownership not in ret: + test.fail("Swtpm log ownership not correct: %s" % ret) + + +def run(test, params, env): + """ + Test migration with vtpm device. + + :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.") + set_secret(params) + migration_obj.setup_connection() + setup_vtpm(params, test, vm, migration_obj) + + def verify_test(): + """ + Verify steps + + """ + swtpm_log = params.get("swtpm_log") + + test.log.info("Verify steps.") + check_ownership(swtpm_log, "svirt_image_t", test) + virsh.shutdown(vm_name, debug=True) + if not vm.wait_for_shutdown(): + test.error('VM failed to shutdown in 60s') + check_ownership(swtpm_log, "virt_log_t", test) + + def cleanup_test(): + """ + Cleanup steps + + """ + desturi = params.get("virsh_migrate_desturi") + swtpm_path = params.get("swtpm_path") + dst_secret_value_path = params.get("dst_secret_value_path") + src_secret_value_path = params.get("src_secret_value_path") + + test.log.info("Cleanup steps.") + global src_sec_uuid + if src_sec_uuid: + virsh.secret_undefine(src_sec_uuid, debug=True, ignore_status=True) + global dst_sec_uuid + if dst_sec_uuid: + virsh.secret_undefine(dst_sec_uuid, debug=True, ignore_status=True, uri=desturi) + + migration_obj.cleanup_connection() + cmd = f"rm -rf {swtpm_path}/*" + remote.run_remote_cmd(cmd, params) + cmd = f"rm -rf {dst_secret_value_path}" + remote.run_remote_cmd(cmd, params) + process.run(cmd, shell=True, ignore_status=True) + cmd = f"rm -rf {src_secret_value_path}" + process.run(cmd, shell=True, ignore_status=True) + + vm_name = params.get("migrate_main_vm") + test_case = params.get("test_case", "") + migrate_again = "yes" == params.get("migrate_again", "no") + desturi = params.get("virsh_migrate_desturi") + + vm = env.get_vm(vm_name) + migration_obj = base_steps.MigrationBase(test, vm, params) + + if base_steps.check_cpu_for_mig(params): + if test_case != "diff_secret_on_src_and_dst": + test.cancel("Need to use machines with different cpu to test this case.") + else: + if test_case == "diff_secret_on_src_and_dst": + base_steps.sync_cpu_for_mig(params) + + try: + setup_test() + migration_obj.run_migration() + if test_case != "negative": + verify_test() + base_steps.sync_cpu_for_mig(params) + else: + migration_obj.verify_default() + if migrate_again: + migration_obj.run_migration_again() + migration_obj.verify_default() + check_vtpm_func(params, vm, test, remote=True) + finally: + cleanup_test() diff --git a/libvirt/tests/src/migration/migration_with_vtpm/migration_with_vtpm_state_on_block_dev.py b/libvirt/tests/src/migration/migration_with_vtpm/migration_with_vtpm_state_on_block_dev.py new file mode 100644 index 00000000000..6c7dabb8130 --- /dev/null +++ b/libvirt/tests/src/migration/migration_with_vtpm/migration_with_vtpm_state_on_block_dev.py @@ -0,0 +1,349 @@ +import os +import re + +from avocado.utils import process + +from virttest import libvirt_version +from virttest import remote +from virttest import utils_disk +from virttest import utils_test +from virttest import virsh + +from virttest.utils_test import libvirt + +from provider.migration import base_steps +from provider.migration import migration_vtpm + + +def check_labels(params, dir_name, expected_labels, test, remote_host=False): + """ + Check tpm state files' labels + + :param params: Dictionary with the test parameters + :param dir_name: dir name + :param expected_labels: Expected labels + :param test: test object + :param remote_host: if True, will check dir on target host + """ + test.log.debug(f"expected labels: {expected_labels}") + cmd = "ls -alZ %s" % dir_name + if remote_host: + ret = remote.run_remote_cmd(cmd, params, ignore_status=False).stdout_text.strip() + else: + ret = process.run(cmd, shell=True, verbose=True).stdout_text.strip() + for item in expected_labels: + if not re.findall(item, ret): + test.fail(f"Unable to find {item} in {ret}") + + +def check_dir(params, dir_name, test, remote_host=False): + """ + Check dir + + :param params: Dictionary with the test parameters + :param dir_name: dir name + :param test: test object + :param remote_host: if True, will check dir on target host + """ + if remote_host: + cmd = f"ls -A {dir_name}" + ret = remote.run_remote_cmd(cmd, params, ignore_status=True).stdout_text.strip() + else: + ret = os.listdir(dir_name) + if len(ret) != 0: + test.fail(f"{dir_name} is not empty: {ret}") + + +def check_items(expected_list, log_file, test, str_in_log=True): + """ + Check log in file + + :param expected_list: Expected list + :param log_file: log file name + :param test: test object + :param str_in_log: if true, check string in log + """ + if str_in_log: + for item in expected_list: + if not re.findall(item, log_file): + test.fail(f"Not found '{item}' in log.") + else: + for item in expected_list: + if re.findall(item, log_file): + test.fail(f"Found '{item}' in log.") + + +def check_capability(params, test): + """ + Check capability + + :param params: Dictionary with the test parameters + :param test: test object + """ + with open(params.get("libvirtd_debug_file"), 'r', errors='ignore') as f: + log_file = f.read() + if migration_vtpm.compare_swtpm_version(0, 10): + cmd = "swtpm socket --print-capabilities" + ret = process.run(cmd, shell=True, verbose=True).stdout_text.strip() + if "tpmstate-opt-lock" not in ret: + test.fail(f"Not found 'tpmstate-opt-lock' in {ret}") + + check_items(eval(params.get("unexpected_list_1", "[]")), log_file, test, str_in_log=False) + check_items(eval(params.get("expected_list_1", "[]")), log_file, test) + else: + if libvirt_version.version_compare(11, 0, 0): + check_items(eval(params.get("expected_list_2", "[]")), log_file, test) + else: + check_items(eval(params.get("unexpected_list_3", "[]")), log_file, test, str_in_log=False) + check_items(eval(params.get("expected_list_3", "[]")), log_file, test) + + +def prepare_iscsi_disk(params, test, block_dev): + """ + Prepare iscsi disk for test + + :param params: Dictionary with the test parameters + :param test: test object + :param block_dev: block device + """ + client_ip = params.get("client_ip") + block_path = params.get("block_path") + dev_src = None + dev_target = None + target_luns = None + + test.log.info("prepare iscsi disk") + dev_src = libvirt.setup_or_cleanup_iscsi(is_setup=True, + is_login=True, + image_size="1G", + emulated_image="emulated-iscsi-1", + portal_ip=client_ip) + + target_luns, _ = libvirt.setup_or_cleanup_iscsi(is_setup=True, + is_login=False, + image_size="1G", + emulated_image="emulated-iscsi-2", + portal_ip=client_ip) + test.log.debug(f"target_luns: {target_luns}") + dev_target = block_dev.iscsi_login_setup(client_ip, target_luns) + test.log.debug(f"dev_src: {dev_src}") + test.log.debug(f"dev_target: {dev_target}") + + cmd = f"mkfs.xfs -f {dev_src}" + process.run(cmd, shell=True, verbose=True) + + cmd = f"mkdir -p {block_path}" + process.run(cmd, shell=True, verbose=True) + + cmd = f'semanage fcontext -a -t virt_var_lib_t "{block_path}(/.*)?"' + process.run(cmd, shell=True, verbose=True) + remote.run_remote_cmd(cmd, params, ignore_status=False) + + cmd = f'cat /etc/selinux/targeted/contexts/files/file_contexts.local|grep iscsiswtpm' + process.run(cmd, shell=True, verbose=True) + remote.run_remote_cmd(cmd, params, ignore_status=False) + + cmd = f"mkfs.xfs -f {dev_target}" + remote.run_remote_cmd(cmd, params, ignore_status=False) + + cmd = f"mkdir -p {block_path}" + remote.run_remote_cmd(cmd, params, ignore_status=False) + return (dev_src, dev_target, target_luns) + + +def run(test, params, env): + """ + Test migration for vm with vtpm state on block dev. + + :param test: test object + :param params: Dictionary with the test parameters + :param env: Dictionary with test environment. + """ + def setup_auto_create_dir(): + """ + Setup steps for auto_create_dir case + + """ + server_ip = params.get("server_ip") + server_user = params.get("server_user", "root") + server_pwd = params.get("server_pwd") + + test.log.info("Setup steps for auto_create_dir.") + utils_disk.mount(dev_src, block_path) + process.run(f"restorecon -Rv {block_path}", shell=True, verbose=True) + + server_session = remote.wait_for_login("ssh", server_ip, "22", server_user, server_pwd, r"[\#\$]\s*$") + utils_disk.mount(dev_target, block_path, session=server_session) + remote.run_remote_cmd(f"restorecon -Rv {block_path}", params, ignore_status=False) + server_session.close() + + def setup_manual_create_dir(): + """ + Setup steps for manual_create_dir case + + """ + server_ip = params.get("server_ip") + server_user = params.get("server_user", "root") + server_pwd = params.get("server_pwd") + + test.log.info("Setup steps for manual_create_dir.") + process.run(f"mkdir {block_dir}", shell=True, verbose=True) + utils_disk.mount(dev_src, block_dir) + process.run(f"restorecon -Rv {block_path}", shell=True, verbose=True) + + server_session = remote.wait_for_login("ssh", server_ip, "22", server_user, server_pwd, r"[\#\$]\s*$") + remote.run_remote_cmd(f"mkdir {block_dir}", params, ignore_status=False) + utils_disk.mount(dev_target, block_dir, session=server_session) + remote.run_remote_cmd(f"restorecon -Rv {block_path}", params, ignore_status=False) + server_session.close() + + check_labels(params, block_dir, eval(params.get("check_lables_1")), test) + + def setup_auto_create_file(): + """ + Setup steps for auto_create_file + + """ + server_ip = params.get("server_ip") + server_user = params.get("server_user", "root") + server_pwd = params.get("server_pwd") + + test.log.info("Setup steps for auto_create_file.") + process.run(f"mkdir {block_dir}", shell=True, verbose=True) + utils_disk.mount(dev_src, block_dir) + process.run(f"restorecon -Rv {block_path}", shell=True, verbose=True) + process.run(f"chown tss:tss {block_dir}", shell=True, verbose=True) + + server_session = remote.wait_for_login("ssh", server_ip, "22", server_user, server_pwd, r"[\#\$]\s*$") + remote.run_remote_cmd(f"mkdir {block_dir}", params, ignore_status=False) + utils_disk.mount(dev_target, block_dir, session=server_session) + remote.run_remote_cmd(f"restorecon -Rv {block_path}", params, ignore_status=False) + remote.run_remote_cmd(f"chown tss:tss {block_dir}", params, ignore_status=False) + server_session.close() + + check_labels(params, block_dir, eval(params.get("check_lables_1")), test) + + def setup_test(): + """ + Setup steps + + """ + test.log.info("Setup steps.") + nonlocal dev_src, dev_target, target_luns + dev_src, dev_target, target_luns = prepare_iscsi_disk(params, test, block_dev) + migration_obj.setup_connection() + + if test_case == "auto_create_dir": + setup_auto_create_dir() + elif test_case == "manual_create_dir": + setup_manual_create_dir() + elif test_case == "auto_create_file": + setup_auto_create_file() + + migration_vtpm.setup_vtpm(params, test, vm) + check_labels(params, block_dir, eval(params.get("check_lables_2")), test) + migration_vtpm.check_vtpm_func(params, vm, test) + check_capability(params, test) + + def verify_test(): + """ + Verify steps + + """ + test.log.info("Verify steps.") + check_labels(params, block_dir, eval(params.get("check_lables_2")), test, remote_host=True) + migration_vtpm.check_vtpm_func(params, vm, test, remote_host=True) + + def verify_test_again(): + """ + Verify again + + """ + test.log.info("Verify again.") + if test_case == "auto_create_dir": + check_dir(params, block_path, test, remote_host=True) + + migration_vtpm.check_vtpm_func(params, vm, test) + check_labels(params, block_dir, eval(params.get("check_lables_2")), test) + + virsh.destroy(vm_name, debug=True) + if not vm.wait_for_shutdown(): + test.error('VM failed to shutdown in 60s') + check_labels(params, block_dir, eval(params.get("check_lables_3")), test) + virsh.undefine(vm_name, options='--nvram', debug=True) + if test_case == "auto_create_dir": + check_dir(params, block_path, test) + + def cleanup_test(): + """ + Cleanup steps + + """ + desturi = params.get("virsh_migrate_desturi") + dst_secret_value_path = params.get("dst_secret_value_path") + src_secret_value_path = params.get("src_secret_value_path") + 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") + + test.log.info("Cleanup steps.") + + def _umount_dir(dir_path): + utils_disk.umount(dev_src, dir_path) + server_session = remote.wait_for_login("ssh", server_ip, "22", server_user, server_pwd, r"[\#\$]\s*$") + utils_disk.umount(dev_target, dir_path, session=server_session) + server_session.close() + + if test_case == "auto_create_dir": + _umount_dir(block_path) + else: + _umount_dir(block_dir) + + block_dev.iscsi_login_setup(client_ip, target_luns, is_login=False) + libvirt.setup_or_cleanup_iscsi(is_setup=False, emulated_image="emulated-iscsi-2", portal_ip=client_ip) + libvirt.setup_or_cleanup_iscsi(is_setup=False, emulated_image="emulated-iscsi-1", portal_ip=client_ip) + + if src_sec_uuid: + virsh.secret_undefine(src_sec_uuid, debug=True, ignore_status=True) + if dst_sec_uuid: + virsh.secret_undefine(dst_sec_uuid, debug=True, ignore_status=True, uri=desturi) + + migration_obj.cleanup_connection() + cmd = f"rm -rf {dst_secret_value_path}" + remote.run_remote_cmd(cmd, params) + process.run(cmd, shell=True, ignore_status=True) + cmd = f"rm -rf {src_secret_value_path}" + process.run(cmd, shell=True, ignore_status=True) + cmd = f"rm -rf {block_path}" + remote.run_remote_cmd(cmd, params) + process.run(cmd, shell=True, ignore_status=True) + + vm_name = params.get("migrate_main_vm") + test_case = params.get("test_case") + block_dir = params.get("block_dir") + block_path = params.get("block_path") + new_ownership = params.get("new_ownership") + src_sec_uuid = None + dst_sec_uuid = None + dev_src = None + dev_target = None + target_luns = None + + libvirt_version.is_libvirt_feature_supported(params) + + vm = env.get_vm(vm_name) + migration_obj = base_steps.MigrationBase(test, vm, params) + block_dev = utils_test.RemoteDiskManager(params) + + try: + src_sec_uuid, dst_sec_uuid = migration_vtpm.set_secret(params) + if not base_steps.check_cpu_for_mig(params): + base_steps.sync_cpu_for_mig(params) + setup_test() + migration_obj.run_migration() + verify_test() + migration_obj.run_migration_back() + verify_test_again() + finally: + cleanup_test() diff --git a/libvirt/tests/src/migration/migration_xml_update.py b/libvirt/tests/src/migration/migration_xml_update.py new file mode 100644 index 00000000000..650a55a9742 --- /dev/null +++ b/libvirt/tests/src/migration/migration_xml_update.py @@ -0,0 +1,102 @@ +import logging as log +import tempfile +from xml.etree import ElementTree + +from virttest import data_dir +from virttest import virsh + +from virttest.libvirt_xml import vm_xml +from virttest.utils_libvirt import libvirt_vmxml + +from provider.migration import base_steps + +logging = log.getLogger('avocado.' + __name__) + + +def prepare_vm(vm, vm_name, vmxml, params): + """ + Prepares the VM by adding the device under test + + :param vm: The VM object + :param vm_name: The VM name + :param vmxml: The VM XML + :param params: The test parameters + """ + + if vm.is_alive(): + vm.destroy() + dev_type = params.get("remove_all") + vmxml.remove_all_device_by_type(dev_type) + vmxml.sync() + dev_dir = eval(params.get("add_device")) + dev = libvirt_vmxml.create_vm_device_by_type(dev_type, dev_dir) + virsh.attach_device(vm_name, dev.xml, flagstr="--config", debug="True") + + +def create_migration_xml(test, vm_name, params): + """ + Creates the xml to be passed to '--xml' option + + :param test: The test object + :param vm_name: The VM name + :param params: The Test parameters + """ + tmp_file = xml_file = tempfile.mktemp(dir=data_dir.get_tmp_dir()) + params['virsh_migrate_extra'] = "--xml %s" % tmp_file + xmlout = virsh.dumpxml(vm_name, "--migratable", debug=True).stdout_text.strip() + vmxml = ElementTree.fromstring(xmlout) + modify = params.get("modify") + dev = vmxml.find(".//" + params.get("remove_all")) + if modify == "alias": + alias = ElementTree.SubElement(dev, "alias") + alias.attrib['name'] = "ua-otherName" + elif modify == "address": + new_address = ElementTree.fromstring(params.get("new_address")) + old_address = dev.find("address") + dev.remove(old_address) + dev.append(new_address) + ElementTree.ElementTree(vmxml).write(tmp_file) + + +def check_alias(vm_name, params, test): + """ + Checks if the alias on the destination is as set + in migration xml. + + :param vm_name: The VM name + :param params: The test parameters + :param test: The test object + """ + dest_xml = virsh.dumpxml(vm_name, uri=params.get("virsh_migrate_desturi")).stdout_text + if "ua-otherName" not in dest_xml: + test.fail("Expected rng alias 'ua-otherName' not found in " + "destination xml: %s" % dest_xml) + + +def run(test, params, env): + """ + Tests migration behavior when the destination xml + is altered for a device. + + :param test: test object + :param params: Dictionary with the test parameters + :param env: Dictionary with test environment. + """ + + vm_name = params.get("migrate_main_vm") + vm = env.get_vm(vm_name) + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + backup_xml = vmxml.copy() + + prepare_vm(vm, vm_name, vmxml, params) + migration_obj = base_steps.MigrationBase(test, vm, params) + + try: + migration_obj.setup_connection() + create_migration_xml(test, vm_name, params) + migration_obj.run_migration() + if params.get("modify") == "alias": + check_alias(vm_name, params, test) + finally: + migration_obj.cleanup_connection() + backup_xml.sync() diff --git a/libvirt/tests/src/migration/non_live_migration/non_live_migration.py b/libvirt/tests/src/migration/non_live_migration/non_live_migration.py new file mode 100644 index 00000000000..d650cbb7aa3 --- /dev/null +++ b/libvirt/tests/src/migration/non_live_migration/non_live_migration.py @@ -0,0 +1,30 @@ +from provider.migration import base_steps +from provider.migration import migration_base + + +def run(test, params, env): + """ + This case is to verify that non-live vm migration can succeed. + "non-live migration" means vm is paused before its memory is migrated. + To start a non-live migration, don't add "--live" in virsh migrate option. + + :param test: test object + :param params: Dictionary with the test parameters + :param env: Dictionary with test environment. + """ + vm_name = params.get("migrate_main_vm") + + virsh_session = None + remote_virsh_session = None + + vm = env.get_vm(vm_name) + migration_obj = base_steps.MigrationBase(test, vm, params) + + try: + migration_obj.setup_connection() + virsh_session, remote_virsh_session = migration_base.monitor_event(params) + migration_obj.run_migration() + migration_obj.verify_default() + migration_base.check_event_output(params, test, virsh_session, remote_virsh_session) + finally: + migration_obj.cleanup_connection() diff --git a/libvirt/tests/src/migration/p2p_keepalive/p2p_keepalive.py b/libvirt/tests/src/migration/p2p_keepalive/p2p_keepalive.py new file mode 100644 index 00000000000..913cc242f15 --- /dev/null +++ b/libvirt/tests/src/migration/p2p_keepalive/p2p_keepalive.py @@ -0,0 +1,215 @@ +from virttest import libvirt_remote +from virttest import remote +from virttest import utils_config +from virttest import virsh + +from virttest.utils_test import libvirt +from virttest.utils_libvirt import libvirt_config +from virttest.utils_libvirt import libvirt_network + +from provider.migration import base_steps +from provider.migration import migration_base + + +def update_conf_on_src(params, test, local_obj): + """ + Update configure file on source host + + :param params: Dictionary with the test parameters + :param test: test object + :param local_obj: local conf object + """ + default_conf_on_src = eval(params.get("default_conf_on_src", "[]")) + src_conf_type = params.get("src_conf_type") + conf_on_src = eval(params.get("conf_on_src", "{}")) + + if default_conf_on_src: + local_obj.append(libvirt_config.remove_key_in_conf(default_conf_on_src, + conf_type=src_conf_type, + restart_libvirt=True)) + + if conf_on_src: + local_obj.append(libvirt.customize_libvirt_config(conf_on_src, + config_type=src_conf_type, + remote_host=False, + extra_params=params)) + + +def update_conf_on_target(params, test, remote_obj): + """ + Update configure file on target host + + :param params: Dictionary with the test parameters + :param test: test object + :param remote_obj: remote conf object + """ + default_conf_on_target = eval(params.get("default_conf_on_target", "[]")) + target_conf_type = params.get("target_conf_type") + conf_on_target = params.get("conf_on_target") + + if default_conf_on_target: + file_path = utils_config.get_conf_obj(target_conf_type).conf_path + params["file_path"] = file_path + remote_obj.append(libvirt_config.remove_key_in_conf(default_conf_on_target, + conf_type=target_conf_type, + remote_params=params, + restart_libvirt=True)) + if conf_on_target: + file_path = utils_config.get_conf_obj(target_conf_type).conf_path + remote_obj.append(libvirt_remote.update_remote_file(params, + conf_on_target, + file_path)) + + +def add_port_for_ssh(params): + """ + Add new port for sshd + + :param params: Dictionary with the test parameters + """ + new_ssh_port = params.get("new_ssh_port") + server_ip = params.get("server_ip") + server_user = params.get("server_user") + server_pwd = params.get("server_pwd") + + remote_session = remote.remote_login("ssh", server_ip, "22", + server_user, server_pwd, + r'[$#%]') + cmd = "echo 'Port 22' >> /etc/ssh/sshd_config; echo 'Port %s' >> /etc/ssh/sshd_config" % new_ssh_port + remote_session.cmd(cmd) + cmd = "semanage port -a -t ssh_port_t -p tcp %s" % new_ssh_port + remote_session.cmd(cmd) + cmd = "firewall-cmd --add-port=%s/tcp" % new_ssh_port + remote_session.cmd(cmd) + cmd = "systemctl restart sshd" + remote_session.cmd(cmd) + remote_session.close() + + +def del_port_for_ssh(params): + """ + Delete new port for sshd + + :param params: Dictionary with the test parameters + """ + new_ssh_port = params.get("new_ssh_port") + server_ip = params.get("server_ip") + server_user = params.get("server_user") + server_pwd = params.get("server_pwd") + + remote_session = remote.remote_login("ssh", server_ip, "22", + server_user, server_pwd, + r'[$#%]') + cmd = "sed -i '/^Port .*/d' /etc/ssh/sshd_config" + remote_session.cmd(cmd) + cmd = "firewall-cmd --remove-port=%s/tcp" % new_ssh_port + remote_session.cmd(cmd) + cmd = "systemctl restart sshd" + remote_session.cmd(cmd) + remote_session.close() + + +def run(test, params, env): + """ + Test P2P migration with different keepalive configuration. + + :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.") + new_ssh_port = params.get("new_ssh_port") + + if new_ssh_port: + add_port_for_ssh(params) + migration_obj.setup_connection() + update_conf_on_src(params, test, local_obj) + update_conf_on_target(params, test, remote_obj) + + def verify_test(): + """ + Verify steps + + """ + migrate_dest_state = params.get("migrate_dest_state") + migrate_src_state = params.get("migrate_src_state") + dest_uri = params.get("virsh_migrate_desturi") + keepalive_timeout = params.get("keepalive_timeout") + + test.log.info("Verify steps.") + if keepalive_timeout == "after_keepalive_timeout": + libvirt_network.cleanup_firewall_rule(params) + 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) + if int(migration_obj.migration_test.ret.exit_status) == 0: + test.fail("Expected failed, but migrate successfully.") + if not libvirt.check_vm_state(vm.name, migrate_src_state, uri=migration_obj.src_uri): + test.faile("Check vm state on source host fail.") + dest_vm_list = virsh.dom_list(options="--all --persistent", debug=True, uri=dest_uri) + if migrate_dest_state == "nonexist": + if vm_name in dest_vm_list.stdout.strip(): + test.fail("%s should not exist." % vm_name) + else: + migration_obj.verify_default() + + def cleanup_test(): + """ + Cleanup steps + + """ + test.log.info("Cleanup steps.") + src_conf_type = params.get("src_conf_type") + new_ssh_port = params.get("new_ssh_port") + dest_uri = params.get("virsh_migrate_desturi") + + libvirt_network.cleanup_firewall_rule(params) + if new_ssh_port: + if virsh.is_alive(vm_name, uri=dest_uri): + virsh.destroy(vm_name, uri=dest_uri) + del_port_for_ssh(params) + migration_obj.cleanup_connection() + if remote_obj: + for obj in remote_obj: + del obj + if local_obj: + for obj in local_obj: + libvirt.customize_libvirt_config(None, + config_type=src_conf_type, + remote_host=False, + is_recover=True, + extra_params=params, + config_object=obj) + + test_case = params.get('test_case', '') + migrate_again = "yes" == params.get("migrate_again", "no") + vm_name = params.get("migrate_main_vm") + + virsh_session = None + remote_virsh_session = None + + vm = env.get_vm(vm_name) + migration_obj = base_steps.MigrationBase(test, vm, params) + + remote_obj = [] + local_obj = [] + + try: + setup_test() + if test_case != "src_and_dest_keepalive_disabled": + # Monitor event on source/target host + virsh_session, remote_virsh_session = migration_base.monitor_event(params) + migration_obj.run_migration() + verify_test() + if test_case != "src_and_dest_keepalive_disabled": + migration_base.check_event_output(params, test, virsh_session, remote_virsh_session) + if migrate_again: + migration_obj.run_migration_again() + migration_obj.verify_default() + finally: + cleanup_test() diff --git a/libvirt/tests/src/migration/pause_postcopy_migration_and_recover/pause_and_io_error_and_recover.py b/libvirt/tests/src/migration/pause_postcopy_migration_and_recover/pause_and_io_error_and_recover.py index b85b2e317f0..148eb33c78b 100644 --- a/libvirt/tests/src/migration/pause_postcopy_migration_and_recover/pause_and_io_error_and_recover.py +++ b/libvirt/tests/src/migration/pause_postcopy_migration_and_recover/pause_and_io_error_and_recover.py @@ -26,8 +26,6 @@ def do_io_error(): test.log.debug("Do I/O Error.") shutil.chown(disk_source, "root", "root") - vm_session.cmd("echo 'do disk I/O error test' > /tmp/disk_io_error_test") - vm_session.close() def verify_test(): """ diff --git a/libvirt/tests/src/migration/pause_postcopy_migration_and_recover/pause_and_recover_and_disruptive.py b/libvirt/tests/src/migration/pause_postcopy_migration_and_recover/pause_and_recover_and_disruptive.py index 0494973f2b2..436b0e646cf 100644 --- a/libvirt/tests/src/migration/pause_postcopy_migration_and_recover/pause_and_recover_and_disruptive.py +++ b/libvirt/tests/src/migration/pause_postcopy_migration_and_recover/pause_and_recover_and_disruptive.py @@ -21,7 +21,7 @@ def setup_pause_by_network(): """ test.log.info("Setup for pause_by_network") tcp_config_list = eval(params.get("tcp_config_list")) - libvirt_network.change_tcp_config(tcp_config_list) + libvirt_network.change_tcp_config(tcp_config_list, params) migration_obj.setup_connection() def cleanup_pause_by_network(): @@ -31,7 +31,7 @@ def cleanup_pause_by_network(): """ test.log.info("Cleanup for pause_by_network") recover_tcp_config_list = eval(params.get("recover_tcp_config_list")) - libvirt_network.change_tcp_config(recover_tcp_config_list) + libvirt_network.change_tcp_config(recover_tcp_config_list, params) migration_obj.cleanup_connection() libvirt_version.is_libvirt_feature_supported(params) diff --git a/libvirt/tests/src/migration/pause_postcopy_migration_and_recover/pause_and_recover_twice.py b/libvirt/tests/src/migration/pause_postcopy_migration_and_recover/pause_and_recover_twice.py index 9880d25eb3f..b52dcd2ce16 100644 --- a/libvirt/tests/src/migration/pause_postcopy_migration_and_recover/pause_and_recover_twice.py +++ b/libvirt/tests/src/migration/pause_postcopy_migration_and_recover/pause_and_recover_twice.py @@ -21,7 +21,7 @@ def setup_network_issue(): """ test.log.info("Setup for network issue") tcp_config_list = eval(params.get("tcp_config_list")) - libvirt_network.change_tcp_config(tcp_config_list) + libvirt_network.change_tcp_config(tcp_config_list, params) migration_obj.setup_connection() def cleanup_network_issue(): @@ -31,7 +31,7 @@ def cleanup_network_issue(): """ test.log.info("Cleanup for network issue") recover_tcp_config_list = eval(params.get("recover_tcp_config_list")) - libvirt_network.change_tcp_config(recover_tcp_config_list) + libvirt_network.change_tcp_config(recover_tcp_config_list, params) migration_obj.cleanup_connection() libvirt_version.is_libvirt_feature_supported(params) diff --git a/libvirt/tests/src/migration/pause_postcopy_migration_and_recover/pause_by_network_and_recover.py b/libvirt/tests/src/migration/pause_postcopy_migration_and_recover/pause_by_network_and_recover.py index a0bb401dd43..13e7834c528 100644 --- a/libvirt/tests/src/migration/pause_postcopy_migration_and_recover/pause_by_network_and_recover.py +++ b/libvirt/tests/src/migration/pause_postcopy_migration_and_recover/pause_by_network_and_recover.py @@ -30,12 +30,11 @@ def verify_test(): dominfo = virsh.dominfo(vm_name, ignore_status=True, debug=True, uri=dest_uri) libvirt.check_result(dominfo, expected_match=dominfo_check) + migration_obj.verify_default() # check qemu-guest-agent command result = virsh.domtime(vm_name, ignore_status=True, debug=True, uri=dest_uri) libvirt.check_exit_status(result) - migration_obj.verify_default() - # Check event output migration_base.check_event_output(params, test, virsh_session, remote_virsh_session) @@ -45,6 +44,7 @@ def verify_test(): migrate_again = "yes" == params.get("migrate_again", "no") tcp_config_list = eval(params.get("tcp_config_list")) recover_tcp_config_list = eval(params.get("recover_tcp_config_list")) + remove_firewall_rule = False virsh_session = None remote_virsh_session = None @@ -55,14 +55,19 @@ def verify_test(): try: base_steps.setup_network_data_transport(params) - libvirt_network.change_tcp_config(tcp_config_list) + libvirt_network.change_tcp_config(tcp_config_list, params) migration_obj.setup_connection() # Monitor event on source/target host virsh_session, remote_virsh_session = migration_base.monitor_event(params) migration_obj.run_migration() + migration_base.do_common_check(params) + libvirt_network.cleanup_firewall_rule(params) + remove_firewall_rule = True if migrate_again: migration_obj.run_migration_again() verify_test() finally: - libvirt_network.change_tcp_config(recover_tcp_config_list) + if not remove_firewall_rule: + libvirt_network.cleanup_firewall_rule(params) + libvirt_network.change_tcp_config(recover_tcp_config_list, params) migration_obj.cleanup_connection() diff --git a/libvirt/tests/src/migration/pause_postcopy_migration_and_recover/unattended_migration.py b/libvirt/tests/src/migration/pause_postcopy_migration_and_recover/unattended_migration.py index 39642226150..44eaa2d56a7 100644 --- a/libvirt/tests/src/migration/pause_postcopy_migration_and_recover/unattended_migration.py +++ b/libvirt/tests/src/migration/pause_postcopy_migration_and_recover/unattended_migration.py @@ -39,7 +39,7 @@ def setup_network_issue_libvirt_layer(): """ test.log.info("Setup for network_issue_libvirt_layer.") tcp_config_list = eval(params.get("tcp_config_list")) - libvirt_network.change_tcp_config(tcp_config_list) + libvirt_network.change_tcp_config(tcp_config_list, params) migration_obj.setup_connection() def verify_test(): @@ -51,6 +51,9 @@ def verify_test(): dominfo_check = params.get("dominfo_check") migration_options = params.get("migration_options") + if make_unattended == "network_issue_libvirt_layer": + libvirt_network.cleanup_firewall_rule(params) + remote_firewall_rule = True # check domain persistence if dominfo_check: dominfo = virsh.dominfo(vm_name, ignore_status=True, debug=True, uri=dest_uri) @@ -61,7 +64,8 @@ def verify_test(): 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) - if not libvirt.check_vm_state(vm_name, virsh_migrate_src_state, uri=migration_obj.src_uri): + if not libvirt.check_vm_state(vm_name, virsh_migrate_src_state, + uri=migration_obj.src_uri, debug=True): test.fail("Migrated VMs failed to be in %s state at source" % virsh_migrate_src_state) if int(migration_obj.migration_test.ret.exit_status) == 0: migration_obj.migration_test.post_migration_check([vm], params, @@ -76,13 +80,16 @@ def cleanup_network_issue_libvirt_layer(): """ test.log.info("Cleanup for network_issue_libvirt_layer") recover_tcp_config_list = eval(params.get("recover_tcp_config_list")) - libvirt_network.change_tcp_config(recover_tcp_config_list) + if not remote_firewall_rule: + libvirt_network.cleanup_firewall_rule(params) + libvirt_network.change_tcp_config(recover_tcp_config_list, params) migration_obj.cleanup_connection() libvirt_version.is_libvirt_feature_supported(params) vm_name = params.get("migrate_main_vm") make_unattended = params.get("make_unattended") + remote_firewall_rule = False virsh_session = None remote_virsh_session = None diff --git a/libvirt/tests/src/migration/pause_postcopy_migration_and_recover/unattended_migration_and_disruptive.py b/libvirt/tests/src/migration/pause_postcopy_migration_and_recover/unattended_migration_and_disruptive.py index 3074ff219b6..1bdb01ed647 100644 --- a/libvirt/tests/src/migration/pause_postcopy_migration_and_recover/unattended_migration_and_disruptive.py +++ b/libvirt/tests/src/migration/pause_postcopy_migration_and_recover/unattended_migration_and_disruptive.py @@ -22,7 +22,7 @@ def setup_pause_by_network(): """ test.log.info("Setup for pause_by_network.") tcp_config_list = eval(params.get("tcp_config_list")) - libvirt_network.change_tcp_config(tcp_config_list) + libvirt_network.change_tcp_config(tcp_config_list, params) migration_obj.setup_connection() def cleanup_pause_by_network(): @@ -32,7 +32,7 @@ def cleanup_pause_by_network(): """ test.log.info("Cleanup for pause_by_network") recover_tcp_config_list = eval(params.get("recover_tcp_config_list")) - libvirt_network.change_tcp_config(recover_tcp_config_list) + libvirt_network.change_tcp_config(recover_tcp_config_list, params) migration_obj.cleanup_connection() libvirt_version.is_libvirt_feature_supported(params) diff --git a/libvirt/tests/src/migration_with_copy_storage/async_job/abort_job.py b/libvirt/tests/src/migration_with_copy_storage/async_job/abort_job.py new file mode 100644 index 00000000000..22b24b22b14 --- /dev/null +++ b/libvirt/tests/src/migration_with_copy_storage/async_job/abort_job.py @@ -0,0 +1,41 @@ +from provider.migration import base_steps +from provider.migration import migration_base + + +def run(test, params, env): + """ + To verify that vm live migration with copying storage can be aborted + successfully, and related resource can be cleaned up so next migration + can succeed. + + """ + def verify_test(): + """ + Verify test + + """ + migration_obj.verify_default() + # Check event output + migration_base.check_event_output(params, test, virsh_session, remote_virsh_session) + + vm_name = params.get("migrate_main_vm") + migrate_again = "yes" == params.get("migrate_again", "no") + + virsh_session = None + remote_virsh_session = None + + vm = env.get_vm(vm_name) + migration_obj = base_steps.MigrationBase(test, vm, params) + + try: + migration_obj.setup_connection() + base_steps.prepare_disks_remote(params, vm) + # Monitor event on source/target host + virsh_session, remote_virsh_session = migration_base.monitor_event(params) + migration_obj.run_migration() + if migrate_again: + migration_obj.run_migration_again() + verify_test() + finally: + base_steps.cleanup_disks_remote(params, vm) + migration_obj.cleanup_connection() diff --git a/libvirt/tests/src/migration_with_copy_storage/async_job/query_domain_job_info.py b/libvirt/tests/src/migration_with_copy_storage/async_job/query_domain_job_info.py new file mode 100644 index 00000000000..a7c15f9575f --- /dev/null +++ b/libvirt/tests/src/migration_with_copy_storage/async_job/query_domain_job_info.py @@ -0,0 +1,49 @@ +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Copyright Red Hat +# +# SPDX-License-Identifier: GPL-2.0 + +# Author: Liping Cheng +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +from virttest.utils_libvirt import libvirt_monitor + +from provider.migration import base_steps + + +def run(test, params, env): + """ + To verify that domain job info can be queried during and after live + migration with copy storage. + + """ + def verify_test(): + """ + Verify test + + """ + expected_domjobinfo_complete = eval(params.get("expected_domjobinfo_complete")) + remote_ip = params.get("server_ip") + + test.log.info("Verify test.") + libvirt_monitor.check_domjobinfo_output(vm_name, + expected_domjobinfo_complete=expected_domjobinfo_complete, + options="--completed", + remote_ip=remote_ip) + migration_obj.verify_default() + + vm_name = params.get("migrate_main_vm") + vm = env.get_vm(vm_name) + migration_obj = base_steps.MigrationBase(test, vm, params) + + try: + migration_obj.setup_connection() + base_steps.prepare_disks_remote(params, vm) + migration_obj.run_migration() + verify_test() + finally: + migration_obj.cleanup_connection() + base_steps.cleanup_disks_remote(params, vm) diff --git a/libvirt/tests/src/migration_with_copy_storage/autoskipped_disks.py b/libvirt/tests/src/migration_with_copy_storage/autoskipped_disks.py new file mode 100644 index 00000000000..699e2af16b9 --- /dev/null +++ b/libvirt/tests/src/migration_with_copy_storage/autoskipped_disks.py @@ -0,0 +1,117 @@ +import os + +from avocado.utils import process + +from virttest import data_dir +from virttest import remote +from virttest import utils_misc + +from virttest.libvirt_xml import vm_xml +from virttest.utils_libvirt import libvirt_disk +from virttest.utils_libvirt import libvirt_vmxml + +from provider.migration import base_steps +from provider.migration import migration_base + + +def run(test, params, env): + """ + To verify that libvirt will skip specific disks when do vm live migration + with copy storage. This case starts vm with specific disks, then do vm live + migration with copy storage; migration may fail or succeed according to the + disk configuration. + + """ + def setup_common(): + """ + Common setup step. + + """ + migrate_desturi_port = params.get("migrate_desturi_port") + migrate_desturi_type = params.get("migrate_desturi_type", "tcp") + + test.log.info("Common setup step.") + migration_obj.conn_list.append(migration_base.setup_conn_obj(migrate_desturi_type, params, test)) + migration_obj.remote_add_or_remove_port(migrate_desturi_port) + + first_image_path = os.path.join(data_dir.get_data_dir(), 'images') + first_disk_dict = {'source': {'attrs': {'file': os.path.join(first_image_path, + os.path.basename(vm.get_first_disk_devices()['source']))}}} + + libvirt_vmxml.modify_vm_device( + vm_xml.VMXML.new_from_inactive_dumpxml(vm_name), + 'disk', first_disk_dict) + + def setup_test(): + """ + Setup step. + + """ + second_disk_dict = eval(params.get("second_disk_dict")) + nfs_mount_dir = params.get("nfs_mount_dir") + second_disk_name = params.get("second_disk_name") + + test.log.info("Setup step.") + source_file = vm.get_first_disk_devices()['source'] + if test_case in ["disk_with_shareable", "disk_with_readonly", "cdrom_with_startuppolicy"]: + if nfs_mount_dir: + second_disk_img = os.path.join(nfs_mount_dir, second_disk_name) + else: + second_disk_img = os.path.join(os.path.dirname(source_file), second_disk_name) + if os.path.exists(second_disk_img): + os.remove(second_disk_img) + if test_case in ["disk_with_shareable", "disk_with_readonly"]: + libvirt_disk.create_disk("file", disk_format="raw", path=second_disk_img) + second_disk_dict.update({"source": {"attrs": {"file": "%s" % second_disk_img}}}) + else: + startup_policy = eval(params.get("startup_policy")) + if nfs_mount_dir: + cdrom_iso = nfs_mount_dir + "/test.iso" + else: + cdrom_iso = os.path.dirname(source_file) + "/test.iso" + process.run("dd if=/dev/urandom of=%s bs=1M count=10" % cdrom_iso, shell=True) + process.run("mkisofs -o %s %s" % (second_disk_img, cdrom_iso), shell=True) + startup_policy.update({"file": "%s" % second_disk_img}) + second_disk_dict.update({"source": {"attrs": startup_policy}}) + + if test_case == "disk_with_shareable": + base_steps.prepare_disks_remote(params, vm) + else: + server_ip = params.get("server_ip") + server_user = params.get("server_user") + server_pwd = params.get("server_pwd") + + remote_session = remote.remote_login("ssh", server_ip, "22", + server_user, server_pwd, + r'[$#%]') + + image_info = utils_misc.get_image_info(source_file) + disk_size = image_info.get("vsize") + disk_format = image_info.get("format") + utils_misc.make_dirs(os.path.dirname(source_file), remote_session) + libvirt_disk.create_disk("file", path=source_file, + size=disk_size, disk_format=disk_format, + session=remote_session) + remote_session.close() + + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + vmxml.add_device(libvirt_vmxml.create_vm_device_by_type("disk", second_disk_dict)) + vmxml.sync() + + vm.start() + vm.wait_for_login().close() + + vm_name = params.get("migrate_main_vm") + test_case = params.get("test_case") + + vm = env.get_vm(vm_name) + migration_obj = base_steps.MigrationBase(test, vm, params) + + try: + setup_common() + setup_test() + migration_obj.run_migration() + migration_obj.verify_default() + finally: + base_steps.cleanup_disks_remote(params, vm) + migration_obj.cleanup_connection() diff --git a/libvirt/tests/src/migration_with_copy_storage/disk_io_load_in_vm.py b/libvirt/tests/src/migration_with_copy_storage/disk_io_load_in_vm.py new file mode 100644 index 00000000000..509e53e8631 --- /dev/null +++ b/libvirt/tests/src/migration_with_copy_storage/disk_io_load_in_vm.py @@ -0,0 +1,80 @@ +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Copyright Redhat +# +# SPDX-License-Identifier: GPL-2.0 +# +# Author: Liping Cheng +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +from virttest import remote +from virttest import utils_package + +from provider.migration import base_steps + + +def run(test, params, env): + """ + To verify that vm migration can succeed when there is heavy disk I/O load + in vm. + + :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.") + migration_obj.setup_connection() + session = vm.wait_for_login() + utils_package.package_install(["gcc", "fio"], session, 360) + shell_file = "/tmp/fio_test.sh" + fio_cmd = ['while true', + 'do', + ' fio -name=aaa -direct=1 -iodepth=32 -rw=randrw -ioengine=libaio -bs=16k -size=1G -numjobs=2 -group_reporting -directory=/ &>/dev/null', + 'done'] + remote_file = remote.RemoteFile(vm.get_address(), 'scp', 'root', + params.get('password'), 22, + shell_file) + remote_file.truncate() + remote_file.add(fio_cmd) + session.cmd('chmod 777 %s' % shell_file) + session.cmd('%s &' % shell_file) + session.close() + + def verify_test(): + """ + Verify steps + + """ + dest_uri = params.get("virsh_migrate_desturi") + + test.log.info("Verify steps.") + backup_uri, vm.connect_uri = vm.connect_uri, dest_uri + vm.cleanup_serial_console() + vm.create_serial_console() + remote_vm_session = vm.wait_for_serial_login(timeout=360) + remote_vm_dmesg = remote_vm_session.cmd_output("dmesg") + if "I/O error" in remote_vm_dmesg: + test.fail(f"Found I/O error in guest dmesg: {remote_vm_dmesg}") + remote_vm_session.close() + vm.connect_uri = backup_uri + + migration_obj.verify_default() + + vm_name = params.get("migrate_main_vm") + vm = env.get_vm(vm_name) + migration_obj = base_steps.MigrationBase(test, vm, params) + + try: + setup_test() + base_steps.prepare_disks_remote(params, vm) + migration_obj.run_migration() + verify_test() + finally: + migration_obj.cleanup_connection() + base_steps.cleanup_disks_remote(params, vm) diff --git a/libvirt/tests/src/migration_with_copy_storage/disk_type_coverage/block_disk.py b/libvirt/tests/src/migration_with_copy_storage/disk_type_coverage/block_disk.py new file mode 100644 index 00000000000..9bf306b360d --- /dev/null +++ b/libvirt/tests/src/migration_with_copy_storage/disk_type_coverage/block_disk.py @@ -0,0 +1,99 @@ +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Copyright Redhat +# +# SPDX-License-Identifier: GPL-2.0 +# +# Author: Liping Cheng +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +import re + +from virttest import remote +from virttest import utils_disk +from virttest import virsh + +from virttest.utils_test import libvirt + +from provider.migration import base_steps + + +def setup_block_device_on_remote(params): + """ + Setup block device on remote host + + :param params: Dictionary with the test parameters + """ + cmd = "modprobe scsi_debug lbpu=1 lbpws=1 dev_size_mb=2048" + remote.run_remote_cmd(cmd, params, ignore_status=False) + + +def cleanup_block_device_on_remote(params): + """ + Cleanup block device on remote host + + :param params: Dictionary with the test parameters + """ + ret = remote.run_remote_cmd("lsscsi | grep scsi_debug", params, ignore_status=False) + if ret.exit_status == 0: + scsi_addr_pattern = '[0-9]+:[0-9]+:[0-9]+:[0-9]+' + for addr in re.findall(scsi_addr_pattern, ret.stdout_text): + remote.run_remote_cmd("echo 1>/sys/class/scsi_device/{}/device/delete".format(addr), + params, ignore_status=False) + + remote.run_remote_cmd("modprobe -r scsi_debug", params, ignore_status=False) + + +def run(test, params, env): + """ + To verify that live migration with copying storage can succeed for block + disk. + + :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.") + attach_disk_args = params.get("attach_disk_args") + scsi_disk_option = params.get("scsi_disk_option") + target_type = params.get("target_type") + + migration_obj.setup_connection() + base_steps.prepare_disks_remote(params, vm) + setup_block_device_on_remote(params) + + disk_source = libvirt.create_scsi_disk(scsi_disk_option) + virsh.attach_disk(vm_name, disk_source, target_type, + attach_disk_args, debug=True, ignore_status=False) + vm.start() + vm_session = vm.wait_for_login() + utils_disk.linux_disk_check(vm_session, target_type) + vm_session.close() + + def cleanup_test(): + """ + Cleanup steps + + """ + test.log.info("Cleanup steps.") + migration_obj.cleanup_connection() + libvirt.delete_scsi_disk() + cleanup_block_device_on_remote(params) + base_steps.cleanup_disks_remote(params, vm) + + 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() + migration_obj.verify_default() + finally: + cleanup_test() diff --git a/libvirt/tests/src/migration_with_copy_storage/migrate_disks.py b/libvirt/tests/src/migration_with_copy_storage/migrate_disks.py new file mode 100644 index 00000000000..b9593fd43e8 --- /dev/null +++ b/libvirt/tests/src/migration_with_copy_storage/migrate_disks.py @@ -0,0 +1,202 @@ +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Copyright Redhat +# +# SPDX-License-Identifier: GPL-2.0 +# +# Author: Liping Cheng +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +import os + +from virttest import data_dir +from virttest import remote +from virttest import utils_misc + +from virttest.libvirt_xml import vm_xml +from virttest.utils_libvirt import libvirt_disk +from virttest.utils_libvirt import libvirt_vmxml + +from provider.migration import base_steps +from provider.migration import migration_base + + +def update_vm_with_additional_disk(disk_dict, disk_format, vm_name, disk_path=None): + """ + Update vm with additional disk + + :param disk_dict: disk parameter + :param disk_format: disk format + :param vm_name: vm name + :param disk_path: disk path + """ + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + if disk_path: + disk_dict.update({"source": {"attrs": {"file": "%s" % disk_path}}}) + if os.path.exists(disk_path): + os.remove(disk_path) + libvirt_disk.create_disk("file", disk_format=disk_format, path=disk_path) + vmxml.add_device(libvirt_vmxml.create_vm_device_by_type("disk", disk_dict)) + vmxml.sync() + + +def prepare_disk_local(blk_source, vm_name): + """ + Prepare disk on local host + + :param blk_source: first disk path + :param vm_name: vm name + """ + default_image_path = os.path.join(data_dir.get_data_dir(), 'images') + disk_dict = {'source': {'attrs': {'file': os.path.join(default_image_path, + os.path.basename(blk_source))}}} + libvirt_vmxml.modify_vm_device( + vm_xml.VMXML.new_from_inactive_dumpxml(vm_name), + 'disk', disk_dict) + + +def prepare_disk_remote(params, blk_source): + """ + Prepare disk on remote host + + :param params: dictionary with the test parameter + :param blk_source: first disk path + """ + server_ip = params.get("server_ip") + server_user = params.get("server_user") + server_pwd = params.get("server_pwd") + + remote_session = remote.remote_login("ssh", server_ip, "22", + server_user, server_pwd, + r'[$#%]') + + image_info = utils_misc.get_image_info(blk_source) + disk_size = image_info.get("vsize") + disk_format = image_info.get("format") + utils_misc.make_dirs(os.path.dirname(blk_source), remote_session) + libvirt_disk.create_disk("file", path=blk_source, + size=disk_size, disk_format=disk_format, + session=remote_session) + remote_session.close() + + +def prepare_disks(params, blk_source, vm_name): + """ + Prepare disk on local and remote host + + :param params: dictionary with the test parameter + :param blk_source: first disk path + :param vm_name: vm name + """ + disk2_dict = eval(params.get("disk2_dict")) + disk2_name = params.get("disk2_name") + disk_format = params.get("disk_format", "qcow2") + + disk2_path = os.path.join(os.path.dirname(blk_source), disk2_name) + update_vm_with_additional_disk(disk2_dict, disk_format, vm_name, disk2_path) + + prepare_disk_remote(params, blk_source) + prepare_disk_remote(params, disk2_path) + + +def run(test, params, env): + """ + To verify that libvirt can specifies which disks to migrate during + migration. + + :param test: test object + :param params: dictionary with the test parameters + :param env: dictionary with test environment. + """ + def setup_common(): + """ + Common setup steps + + """ + test.log.info("Common setup steps.") + migration_obj.setup_connection() + prepare_disks(params, blk_source, vm_name) + vm.start() + vm.wait_for_login().close() + + def setup_disk1_disk2_disk3(): + """ + Setup steps for disk1_disk2_disk3 case + + """ + disk3_dict = eval(params.get("disk3_dict")) + disk3_name = params.get("disk3_name") + nfs_mount_dir = params.get("nfs_mount_dir") + migrate_desturi_port = params.get("migrate_desturi_port") + migrate_desturi_type = params.get("migrate_desturi_type", "tcp") + + migration_obj.conn_list.append(migration_base.setup_conn_obj(migrate_desturi_type, params, test)) + migration_obj.remote_add_or_remove_port(migrate_desturi_port) + + test.log.info("Setup steps for disk1_disk2_disk3 case.") + prepare_disk_local(blk_source, vm_name) + prepare_disks(params, blk_source, vm_name) + + disk3_path = os.path.join(nfs_mount_dir, disk3_name) + update_vm_with_additional_disk(disk3_dict, disk_format, vm_name, disk3_path) + + vm.start() + vm.wait_for_login().close() + + def setup_disk1_disk2_disk4(): + """ + Setup steps for disk1_disk2_disk4 case + + """ + disk4_dict = eval(params.get("disk4_dict")) + disk4_name = params.get("disk4_name") + nfs_mount_dir = params.get("nfs_mount_dir") + migrate_desturi_port = params.get("migrate_desturi_port") + migrate_desturi_type = params.get("migrate_desturi_type", "tcp") + + migration_obj.conn_list.append(migration_base.setup_conn_obj(migrate_desturi_type, params, test)) + migration_obj.remote_add_or_remove_port(migrate_desturi_port) + + test.log.info("Setup steps for disk1_disk2_disk4 case.") + prepare_disk_local(blk_source, vm_name) + prepare_disks(params, blk_source, vm_name) + + disk4_path = os.path.join(nfs_mount_dir, disk4_name) + update_vm_with_additional_disk(disk4_dict, disk_format, vm_name, disk4_path) + + vm.start() + vm.wait_for_login().close() + + def setup_disk1_disk2_disk5(): + """ + Setup steps for disk1_disk2_disk5 case + + """ + disk5_dict = eval(params.get("disk5_dict")) + + test.log.info("Setup steps for disk1_disk2_disk5 case.") + migration_obj.setup_connection() + prepare_disks(params, blk_source, vm_name) + update_vm_with_additional_disk(disk5_dict, disk_format, vm_name) + + vm.start() + vm.wait_for_login().close() + + disks = params.get("disks") + vm_name = params.get("migrate_main_vm") + disk_format = params.get("disk_format", "qcow2") + + vm = env.get_vm(vm_name) + blk_source = vm.get_first_disk_devices()['source'] + migration_obj = base_steps.MigrationBase(test, vm, params) + setup_test = eval("setup_%s" % disks) if "setup_%s" % disks in \ + locals() else setup_common + + try: + setup_test() + migration_obj.run_migration() + migration_obj.verify_default() + finally: + migration_obj.cleanup_connection() + base_steps.cleanup_disks_remote(params, vm) diff --git a/libvirt/tests/src/migration_with_copy_storage/migration_bandwidth_limit.py b/libvirt/tests/src/migration_with_copy_storage/migration_bandwidth_limit.py new file mode 100644 index 00000000000..85655ac5c7c --- /dev/null +++ b/libvirt/tests/src/migration_with_copy_storage/migration_bandwidth_limit.py @@ -0,0 +1,59 @@ +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Copyright Redhat +# +# SPDX-License-Identifier: GPL-2.0 +# +# Author: Liping Cheng +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +from virttest import virsh + +from provider.migration import base_steps + + +def run(test, params, env): + """ + To verify that bandwidth limit can take effect for storage copying during + migration. + + :param test: test object + :param params: Dictionary with the test parameters + :param env: Dictionary with test environment. + """ + def setup_setspeed_before_migration(): + """ + Setup for setspeed_before_migration + + """ + bandwidth = params.get("bandwidth") + + test.log.info("Setup bandwidth limit before migration.") + migration_obj.setup_connection() + virsh.migrate_setspeed(vm_name, bandwidth, debug=True) + + def cleanup_test(): + """ + Cleanup steps + + """ + migration_obj.cleanup_connection() + base_steps.cleanup_disks_remote(params, vm) + + set_bandwidth = params.get('set_bandwidth', '') + vm_name = params.get("migrate_main_vm") + + vm = env.get_vm(vm_name) + params.update({'vm_obj': vm}) + migration_obj = base_steps.MigrationBase(test, vm, params) + setup_test = eval("setup_%s" % set_bandwidth) if "setup_%s" % set_bandwidth in \ + locals() else migration_obj.setup_connection + + try: + setup_test() + base_steps.prepare_disks_remote(params, vm) + migration_obj.run_migration() + migration_obj.verify_default() + finally: + cleanup_test() diff --git a/libvirt/tests/src/migration_with_copy_storage/migration_retain_sparsity.py b/libvirt/tests/src/migration_with_copy_storage/migration_retain_sparsity.py new file mode 100644 index 00000000000..c475e739d79 --- /dev/null +++ b/libvirt/tests/src/migration_with_copy_storage/migration_retain_sparsity.py @@ -0,0 +1,348 @@ +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Copyright Redhat +# +# SPDX-License-Identifier: GPL-2.0 +# +# Author: Liping Cheng +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +import os +import shutil + +from avocado.utils import process + +from virttest import ceph +from virttest import data_dir +from virttest import remote +from virttest import utils_misc + +from virttest.libvirt_xml import vm_xml +from virttest.utils_libvirt import libvirt_disk +from virttest.utils_libvirt import libvirt_vmxml +from virttest.libvirt_xml.devices import disk + +from provider.migration import base_steps + + +def prepare_disks_local(params, vm_name): + """ + Prepare disks on local host + + :param params: dictionary with the test parameter + :param vm_name: vm name + :return: rbd device name on source host + """ + src_disk1_dict = eval(params.get("src_disk1_dict")) + src_driver_type_1 = params.get("src_driver_type_1") + src_disk1_name = params.get("src_disk1_name") + disk_size = params.get("disk_size") + disk_path = params.get("disk_path") + disk2_name = params.get("disk2_name") + src_rbd_dev = None + + def _prepare_disk_xml(disk_name, disk_format, disk_dict): + """ + Prepare disk xml + + :param disk_name: disk name + :param disk_format: disk format + :param disk_dict: disk dict + """ + disk_file = os.path.join(disk_path, disk_name) + if os.path.exists(disk_file): + os.remove(disk_file) + libvirt_disk.create_disk("file", size=disk_size, disk_format=disk_format, path=disk_file) + vmxml.add_device(libvirt_vmxml.create_vm_device_by_type("disk", disk_dict)) + vmxml.sync() + + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + if src_driver_type_1 == "rbd": + ceph_pool_name = params.get("ceph_pool_name") + cmd1 = f"rbd create {ceph_pool_name}/{src_disk1_name} --size={disk_size}" + process.run(cmd1, shell=True, verbose=True) + cmd2 = f"rbd device map --pool {ceph_pool_name} {src_disk1_name}" + src_rbd_dev = process.run(cmd2, shell=True, verbose=True).stdout_text.strip() + src_disk1_dict.update({'source': {'attrs': {'dev': src_rbd_dev}}}) + vmxml.add_device(libvirt_vmxml.create_vm_device_by_type("disk", src_disk1_dict)) + vmxml.sync() + else: + _prepare_disk_xml(src_disk1_name, src_driver_type_1, src_disk1_dict) + + if disk2_name: + _prepare_disk_xml(disk2_name, params.get("src_driver_type_2"), eval(params.get("src_disk2_dict"))) + return src_rbd_dev + + +def prepare_disks_remote(params): + """ + Prepare disks on remote host + + :param params: dictionary with the test parameter + :return: rbd device name on target host and updated disk dict + """ + dest_disk1_dict = eval(params.get("dest_disk1_dict")) + dest_driver_type_1 = params.get("dest_driver_type_1") + dest_disk1_name = params.get("dest_disk1_name") + disk_size = params.get("disk_size") + disk_path = params.get("disk_path") + disk2_name = params.get("disk2_name") + server_ip = params.get("server_ip") + server_user = params.get("server_user") + server_pwd = params.get("server_pwd") + dest_rbd_dev = None + + remote_session = remote.remote_login("ssh", server_ip, "22", + server_user, server_pwd, + r'[$#%]') + if dest_driver_type_1 == "rbd": + ceph_pool_name = params.get("ceph_pool_name") + cmd1 = f"rbd create {ceph_pool_name}/{dest_disk1_name} --size={disk_size}" + remote.run_remote_cmd(cmd1, params) + cmd2 = f"rbd device map --pool {ceph_pool_name} {dest_disk1_name}" + dest_rbd_dev = remote.run_remote_cmd(cmd2, params).stdout_text.strip() + dest_disk1_dict.update({'source': {'attrs': {'dev': dest_rbd_dev}}}) + else: + disk_file = os.path.join(disk_path, dest_disk1_name) + utils_misc.make_dirs(disk_path, remote_session) + libvirt_disk.create_disk("file", path=disk_file, + size=disk_size, disk_format=dest_driver_type_1, + session=remote_session) + + if disk2_name: + disk2_file = os.path.join(disk_path, disk2_name) + libvirt_disk.create_disk("file", path=disk2_file, + size=disk_size, disk_format=params.get("dest_driver_type_2"), + session=remote_session) + remote_session.close() + return dest_rbd_dev, dest_disk1_dict + + +def prepare_migratable_xml(vm_name, device_type, disk1_dict, test, disk2_dict=None): + """ + Prepare migratable xml + + :param vm_name: vm name + :param device_type: device type + :param disk1_dict: disk1 dict + :param test: test object + :param disk2_dict: disk2 dict + """ + test.log.debug("Prepare migratable xml.") + mig_disk1 = disk.Disk(type_name=device_type) + mig_disk1.setup_attrs(**disk1_dict) + if disk2_dict: + mig_disk2 = disk.Disk(type_name="file") + mig_disk2.setup_attrs(**eval(disk2_dict)) + + guest_xml = vm_xml.VMXML.new_from_dumpxml(vm_name, options="--migratable") + guest_xml.add_device(mig_disk1) + if disk2_dict: + guest_xml.add_device(mig_disk2) + guest_xml.xmltreefile.write() + tmp_dir = data_dir.get_tmp_dir() + xmlfile = os.path.join(tmp_dir, "xml_file") + shutil.copyfile(guest_xml.xml, xmlfile) + test.log.debug(f"migratable xml: {xmlfile}") + return xmlfile + + +def get_disk_size(disk_file, remote_host=False, params=False): + """ + Get disk size + + :param disk_file: disk file + :param remote_host: if true, get disk size on target host + :param params: dictionary with the test parameters + :return: disk size + """ + cmd = f"qemu-img info {disk_file} -U" + if remote_host: + ret = remote.run_remote_cmd(cmd, params).stdout_text.strip() + else: + ret = process.run(cmd, shell=True).stdout_text.strip() + return ret.split('\n')[3].split(':')[1].strip() + + +def copy_file_to_remote(params, file_list): + """ + Copy files from source host to target host + + :param params: dictionary with the test parameter + :param file_list: list, the list of files + """ + server_ip = params.get("server_ip") + server_user = params.get("server_user") + server_pwd = params.get("server_pwd") + + remote_session = remote.remote_login("ssh", server_ip, "22", + server_user, server_pwd, + r'[$#%]') + for f in file_list: + utils_misc.make_dirs(os.path.dirname(f), remote_session) + remote.copy_files_to(server_ip, 'scp', server_user, server_pwd, + '22', f, f) + remote_session.close() + + +def run(test, params, env): + """ + To verify that live migration with copying storage can retain sparsity with + option --migrate-disks-detect-zeroes. + + :param test: test object + :param params: dictionary with the test parameters + :param env: dictionary with test environment. + """ + def setup_test(): + """ + Setup steps + + """ + src_disk1_name = params.get("src_disk1_name") + dest_disk1_dict = eval(params.get("dest_disk1_dict")) + ceph_pool_name = params.get("ceph_pool_name") + target_dev_1 = params.get("target_dev_1") + target_dev_2 = params.get("target_dev_2") + disk2_name = params.get("disk2_name") + + test.log.info("Setup steps.") + migration_obj.setup_connection() + base_steps.prepare_disks_remote(params, vm) + + nonlocal dest_rbd_dev + dest_rbd_dev, dest_disk1_dict = prepare_disks_remote(params) + test.log.debug(f"dest_disk1_dict: {dest_disk1_dict}") + test.log.debug(f"dest_rbd_dev: {dest_rbd_dev}") + xmlfile = prepare_migratable_xml(vm_name, params.get("dest_device_type_1"), + dest_disk1_dict, test, + disk2_dict=params.get("dest_disk2_dict")) + params.update({"virsh_migrate_extra": "--xml %s" % xmlfile}) + + nonlocal src_rbd_dev + src_rbd_dev = prepare_disks_local(params, vm_name) + test.log.debug(f"src_rbd_dev: {src_rbd_dev}") + + vm.start() + vm_session = vm.wait_for_serial_login(timeout=120) + vm_session.cmd(f"mkfs.xfs /dev/{target_dev_1}", timeout=600) + vm_session.cmd(f"dd if=/dev/random of=/dev/{target_dev_1} bs=1048576 count={params.get('dd_count')}") + if disk2_name: + vm_session.cmd(f"mkfs.xfs /dev/{target_dev_2}", timeout=100) + vm_session.cmd(f"dd if=/dev/random of=/dev/{target_dev_2} bs=1048576 count={params.get('dd_count')}") + vm_session.close() + + nonlocal old_disk_size + if params.get("src_driver_type_1") == "rbd": + cmd = f"rbd du --pool={ceph_pool_name} | grep {src_disk1_name}" + old_disk_size.append(process.run(cmd, shell=True).stdout_text.strip().split(" ")[-1]) + else: + old_disk_size.append(get_disk_size(os.path.join(disk_path, src_disk1_name))) + if disk2_name: + old_disk_size.append(get_disk_size(os.path.join(disk_path, disk2_name))) + test.log.debug(f"old disk size: {old_disk_size}") + + def verify_test(): + """ + Verify steps + + """ + dest_disk1_name = params.get("dest_disk1_name") + disk2_name = params.get("disk2_name") + ceph_pool_name = params.get("ceph_pool_name") + disk_size = params.get("disk_size") + + test.log.info("Verify steps.") + if params.get("dest_driver_type_1") == "rbd": + cmd = f"rbd du --pool={ceph_pool_name} | grep {dest_disk1_name}" + new_disk_size = remote.run_remote_cmd(cmd, params).stdout_text.strip().split(' ')[-1].split(' ') + else: + new_disk_size = get_disk_size(os.path.join(disk_path, dest_disk1_name), remote_host=True, params=params).split(' ') + if new_disk_size[1][0] == disk_size[-1]: + if float(new_disk_size[0]) == float(disk_size[:-1]): + test.fail(f"Disk1 usage should not be {disk_size}: before migrate: {old_disk_size[0]}, after migrate: {new_disk_size}") + if disk2_name: + disk2_size = get_disk_size(os.path.join(disk_path, disk2_name), remote_host=True, params=params).split(' ') + if disk2_size[1][0] == disk_size[-1]: + if float(disk2_size[0]) == float(disk_size[:-1]): + test.fail(f"Disk2 usage should not be {disk_size}: before migrate: {old_disk_size[1]}, after migrate: {disk2_size}") + migration_obj.verify_default() + + def cleanup_test(): + """ + Cleanup steps + + """ + src_disk1_name = params.get("src_disk1_name") + dest_disk1_name = params.get("dest_disk1_name") + disk2_name = params.get("disk2_name") + ceph_pool_name = params.get("ceph_pool_name") + + def _remove_disk_local(disk_name): + """ + Remove disk on local + + :param disk_name: disk name + """ + disk_file = os.path.join(disk_path, disk_name) + if os.path.exists(disk_file): + os.remove(disk_file) + + def _remove_disk_remote(disk_name): + """ + Remove disk on remote + + :param disk_name: disk name + """ + disk_file = os.path.join(disk_path, disk_name) + remote.run_remote_cmd(f"rm -f {disk_file}", params, ignore_status=False) + + test.log.info("Cleanup steps.") + migration_obj.cleanup_connection() + if params.get("dest_driver_type_1") == "rbd": + cmd = f"rbd unmap {dest_rbd_dev}" + remote.run_remote_cmd(cmd, params) + cmd2 = f"rbd remove --pool {ceph_pool_name} {dest_disk1_name}" + remote.run_remote_cmd(cmd2, params) + else: + _remove_disk_remote(dest_disk1_name) + if disk2_name: + _remove_disk_remote(disk2_name) + + if params.get("src_driver_type_1") == "rbd": + cmd = f"rbd unmap {src_rbd_dev}" + process.run(cmd, shell=True, verbose=True) + cmd2 = f"rbd remove --pool {ceph_pool_name} {src_disk1_name}" + process.run(cmd2, shell=True, verbose=True) + else: + _remove_disk_local(src_disk1_name) + if disk2_name: + _remove_disk_local(disk2_name) + for rm_file in [ceph_cfg, keyring_file]: + if os.path.exists(rm_file): + os.remove(rm_file) + remote.run_remote_cmd(f"rm -f {rm_file}", params, ignore_status=True) + base_steps.cleanup_disks_remote(params, vm) + + vm_name = params.get("migrate_main_vm") + disk_path = params.get("disk_path") + old_disk_size = [] + src_rbd_dev = None + dest_rbd_dev = None + ceph_cfg = '' + keyring_file = '' + + vm = env.get_vm(vm_name) + migration_obj = base_steps.MigrationBase(test, vm, params) + # Create config file if it doesn't exist + ceph_cfg = ceph.create_config_file(params.get("mon_host")) + keyring_file = ceph.create_keyring_file(params.get("client_name"), params.get('client_key')) + copy_file_to_remote(params, [ceph_cfg, keyring_file]) + + try: + setup_test() + migration_obj.run_migration() + verify_test() + finally: + cleanup_test() diff --git a/libvirt/tests/src/migration_with_copy_storage/migration_with_backingchain.py b/libvirt/tests/src/migration_with_copy_storage/migration_with_backingchain.py index f942ceb2ef6..1a600b0e896 100644 --- a/libvirt/tests/src/migration_with_copy_storage/migration_with_backingchain.py +++ b/libvirt/tests/src/migration_with_copy_storage/migration_with_backingchain.py @@ -1,4 +1,3 @@ -import math import os import time @@ -123,7 +122,7 @@ def get_remote_disk_info(params, disk_img, test): return disk_info_dict -def check_disk_info(params, old_disk_info, disk_img, test, disk_diff_rate=None): +def check_disk_info(params, old_disk_info, disk_img, test): """ Check disk information @@ -131,18 +130,10 @@ def check_disk_info(params, old_disk_info, disk_img, test, disk_diff_rate=None): :param old_disk_info: disk information on source host :param disk_img: disk image path :param test: test object - :param disk_diff_rate: the different rate for disk image """ new_disk_info = get_remote_disk_info(params, disk_img, test) if old_disk_info['vsize'] != new_disk_info['vsize']: test.fail("Check virtual size failed: old: %s, new: %s." % (old_disk_info['vsize'], new_disk_info['vsize'])) - if disk_diff_rate: - if (math.fabs(float(new_disk_info['dsize']) - float(old_disk_info['dsize'])) // - float(old_disk_info['dsize']) > disk_diff_rate): - test.fail("Check disk size failed: old: %s, new: %s." % (old_disk_info['dsize'], new_disk_info['dsize'])) - else: - if old_disk_info['dsize'] != new_disk_info['dsize']: - test.fail("Check disk size failed: old: %s, new: %s." % (old_disk_info['dsize'], new_disk_info['dsize'])) def check_disk(params, vm): @@ -284,13 +275,12 @@ def verify_with_backing_chain(): top_img = params.get("top_img") top1_img = params.get("top1_img") top2_img = params.get("top2_img") - disk_diff_rate = float(params.get("disk_diff_rate")) test.log.debug("Verify step for backing chain case.") migration_obj.verify_default() - check_disk_info(params, old_disk_info["old_vda_info"], top_img, test, disk_diff_rate) - check_disk_info(params, old_disk_info["old_vdb_info"], top1_img, test, disk_diff_rate) - check_disk_info(params, old_disk_info["old_vdc_info"], top2_img, test, disk_diff_rate) + check_disk_info(params, old_disk_info["old_vda_info"], top_img, test) + check_disk_info(params, old_disk_info["old_vdb_info"], top1_img, test) + check_disk_info(params, old_disk_info["old_vdc_info"], top2_img, test) check_disk(params, vm) def verify_without_backing_chain(): @@ -299,14 +289,13 @@ def verify_without_backing_chain(): """ mig_disk1 = params.get("mig_disk1") mig_disk2 = params.get("mig_disk2") - disk_diff_rate = float(params.get("disk_diff_rate")) test.log.debug("Verify step for without backing chain case.") migration_obj.verify_default() source_file = vm.get_first_disk_devices()['source'] - check_disk_info(params, old_disk_info["old_vda_info"], source_file, test, disk_diff_rate=disk_diff_rate) - check_disk_info(params, old_disk_info["old_vdb_info"], mig_disk1, test, disk_diff_rate) - check_disk_info(params, old_disk_info["old_vdc_info"], mig_disk2, test, disk_diff_rate) + check_disk_info(params, old_disk_info["old_vda_info"], source_file, test) + check_disk_info(params, old_disk_info["old_vdb_info"], mig_disk1, test) + check_disk_info(params, old_disk_info["old_vdc_info"], mig_disk2, test) check_disk(params, vm) def cleanup_with_backing_chain(): diff --git a/libvirt/tests/src/migration_with_copy_storage/migration_with_vhostvdpa.py b/libvirt/tests/src/migration_with_copy_storage/migration_with_vhostvdpa.py new file mode 100644 index 00000000000..dfad2fbb944 --- /dev/null +++ b/libvirt/tests/src/migration_with_copy_storage/migration_with_vhostvdpa.py @@ -0,0 +1,118 @@ +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Copyright Redhat +# +# SPDX-License-Identifier: GPL-2.0 +# +# Author: Liping Cheng +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +from virttest import libvirt_version +from virttest import remote +from virttest import utils_vdpa + +from virttest.libvirt_xml import vm_xml +from virttest.utils_libvirt import libvirt_disk +from virttest.utils_libvirt import libvirt_vmxml + +from provider.migration import base_steps + + +def setup_vhost_vdpa_simulator_disk(params, run_on_target, vdpa_obj): + """ + Setup vhostvdpa disk + + :param params: dictionary with the test parameters + :param run_on_target: remote runner object + :param vdpa_obj: vdpa simulator object + """ + vdpa_obj.setup() + + cmd = "modprobe vhost-vdpa" + remote.run_remote_cmd(cmd, params, run_on_target) + + cmd = "modprobe vdpa-sim-blk" + remote.run_remote_cmd(cmd, params, run_on_target) + + cmd = "vdpa dev add mgmtdev vdpasim_blk name blk0" + remote.run_remote_cmd(cmd, params, run_on_target) + + +def cleanup_vhost_vdpa_simulator_disk(params, run_on_target, vdpa_obj): + """ + Cleanup vhostvdpa disk + + :param params: dictionary with the test parameters + :param run_on_target: remote runner object + :param vdpa_obj: vdpa simulator object + """ + vdpa_obj.cleanup() + + cmd = "modprobe -r vdpa-sim-blk" + remote.run_remote_cmd(cmd, params, run_on_target) + + cmd = "modprobe -r vhost-vdpa" + remote.run_remote_cmd(cmd, params, run_on_target) + + +def run(test, params, env): + """ + To verify that migrate vm with copying vhostvdpa backend disk can succeed. + + :param test: test object + :param params: dictionary with the test parameters + :param env: dictionary with test environment. + """ + def setup_test(): + """ + Setup steps + + """ + vhost_vdpa_disk = params.get("vhost_vdpa_disk") + disk_dict = eval(params.get("disk_dict")) + + test.log.info("Setup steps.") + migration_obj.setup_connection() + + setup_vhost_vdpa_simulator_disk(params, run_on_target, vdpa_obj) + # Set shared memory + vm_xml.VMXML.set_memoryBacking_tag(vm_name, access_mode="shared", hpgs=False) + vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) + vmxml.add_device(libvirt_vmxml.create_vm_device_by_type("disk", disk_dict)) + vmxml.sync() + vm.start() + vm_session = vm.wait_for_login() + new_disk = libvirt_disk.get_non_root_disk_name(vm_session)[0] + vm_session.close() + if not libvirt_disk.check_virtual_disk_io(vm, new_disk): + test.fail("Failed to check disk io for %s!" % new_disk) + + def cleanup_test(): + """ + Cleanup steps + + """ + test.log.info("Cleanup steps.") + if vm.is_alive(): + vm.destroy() + cleanup_vhost_vdpa_simulator_disk(params, run_on_target, vdpa_obj) + migration_obj.cleanup_connection() + + vm_name = params.get("migrate_main_vm") + server_ip = params.get("server_ip") + server_user = params.get("server_user", "root") + server_pwd = params.get("server_pwd") + + libvirt_version.is_libvirt_feature_supported(params) + run_on_target = remote.RemoteRunner(host=server_ip, username=server_user, password=server_pwd) + vm = env.get_vm(vm_name) + migration_obj = base_steps.MigrationBase(test, vm, params) + vdpa_obj = utils_vdpa.VDPASimulatorTest(sim_dev_module="vdpa_sim_blk", mgmtdev="vdpasim_blk") + + try: + setup_test() + migration_obj.run_migration() + migration_obj.verify_default() + finally: + cleanup_test() diff --git a/libvirt/tests/src/migration_with_copy_storage/network_data_transport/tcp.py b/libvirt/tests/src/migration_with_copy_storage/network_data_transport/tcp.py new file mode 100644 index 00000000000..83b3174afb6 --- /dev/null +++ b/libvirt/tests/src/migration_with_copy_storage/network_data_transport/tcp.py @@ -0,0 +1,34 @@ +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Copyright Redhat +# +# SPDX-License-Identifier: GPL-2.0 +# +# Author: Liping Cheng +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +from provider.migration import base_steps + + +def run(test, params, env): + """ + Test VM live migration with copy storage - network data transport - TCP. + + :param test: test object + :param params: Dictionary with the test parameters + :param env: Dictionary with test environment. + """ + vm_name = params.get("migrate_main_vm") + + vm = env.get_vm(vm_name) + migration_obj = base_steps.MigrationBase(test, vm, params) + + try: + migration_obj.setup_connection() + base_steps.prepare_disks_remote(params, vm) + migration_obj.run_migration() + migration_obj.verify_default() + finally: + migration_obj.cleanup_connection() + base_steps.cleanup_disks_remote(params, vm) diff --git a/libvirt/tests/src/migration_with_copy_storage/network_data_transport/tcp_migrateuri_and_disks_port.py b/libvirt/tests/src/migration_with_copy_storage/network_data_transport/tcp_migrateuri_and_disks_port.py new file mode 100644 index 00000000000..807a90df9a7 --- /dev/null +++ b/libvirt/tests/src/migration_with_copy_storage/network_data_transport/tcp_migrateuri_and_disks_port.py @@ -0,0 +1,38 @@ +from provider.migration import base_steps + + +def run(test, params, env): + """ + To verify that the ip and port for copying storage can be specified by + --migrateuri and --disks-port respectively. + This cases starts vm with local storage, then do live migration with + copying storage with virsh options --migrateuri and --disks-port, + and checks the migration ip and port during migration. + + :param test: test object + :param params: Dictionary with the test parameters + :param env: Dictionary with test environment. + """ + vm_name = params.get("migrate_main_vm") + migrateuri_port = params.get("migrateuri_port") + disks_port = params.get("disks_port") + + vm = env.get_vm(vm_name) + migration_obj = base_steps.MigrationBase(test, vm, params) + + try: + migration_obj.setup_connection() + if migrateuri_port: + migration_obj.remote_add_or_remove_port(migrateuri_port) + if disks_port: + migration_obj.remote_add_or_remove_port(disks_port) + base_steps.prepare_disks_remote(params, vm) + migration_obj.run_migration() + migration_obj.verify_default() + finally: + if migrateuri_port: + migration_obj.remote_add_or_remove_port(migrateuri_port, add=False) + if disks_port: + migration_obj.remote_add_or_remove_port(disks_port, add=False) + migration_obj.cleanup_connection() + base_steps.cleanup_disks_remote(params, vm) diff --git a/libvirt/tests/src/migration_with_copy_storage/network_data_transport/tcp_port_reuse.py b/libvirt/tests/src/migration_with_copy_storage/network_data_transport/tcp_port_reuse.py index 219603ef794..eef6894489d 100644 --- a/libvirt/tests/src/migration_with_copy_storage/network_data_transport/tcp_port_reuse.py +++ b/libvirt/tests/src/migration_with_copy_storage/network_data_transport/tcp_port_reuse.py @@ -28,17 +28,22 @@ def run_migration_again(): vm_name = params.get("migrate_main_vm") migrate_again = "yes" == params.get("migrate_again", "no") + disks_port = params.get("disks_port") vm = env.get_vm(vm_name) migration_obj = base_steps.MigrationBase(test, vm, params) try: migration_obj.setup_connection() + if disks_port: + migration_obj.remote_add_or_remove_port(disks_port) base_steps.prepare_disks_remote(params, vm) migration_obj.run_migration() if migrate_again: run_migration_again() migration_obj.verify_default() finally: + if disks_port: + migration_obj.remote_add_or_remove_port(disks_port, add=False) migration_obj.cleanup_connection() base_steps.cleanup_disks_remote(params, vm) diff --git a/libvirt/tests/src/migration_with_copy_storage/precreate_none_target_disk.py b/libvirt/tests/src/migration_with_copy_storage/precreate_none_target_disk.py new file mode 100644 index 00000000000..2f66a87f747 --- /dev/null +++ b/libvirt/tests/src/migration_with_copy_storage/precreate_none_target_disk.py @@ -0,0 +1,137 @@ +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Copyright Redhat +# +# SPDX-License-Identifier: GPL-2.0 +# +# Author: Liping Cheng +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +import os +import re + +from avocado.utils import process + +from virttest import remote +from virttest import virsh + +from virttest.utils_test import libvirt + +from provider.migration import base_steps +from provider.migration import migration_base + +src_image_info = None + + +def check_image_info(params, test): + """ + Check image info + + :param params: Dictionary with the test parameters + :param test: test object + """ + disk_source_name = params.get("disk_source_name") + disk_format = params.get("disk_format") + + cmd = "qemu-img info %s -U" % disk_source_name + target_image_info = remote.run_remote_cmd(cmd, params, + ignore_status=False).stdout_text.strip() + global src_image_info + for src_line in src_image_info.splitlines(): + if "disk size:" in src_line: + continue + if disk_format == "qcow2" and "file length:" in src_line: + continue + if (disk_format == "raw" and ("Format specific information:" in src_line or "extent size hint" in src_line)): + continue + if "virtual size:" in src_line or "file length:" in src_line: + src_line = re.sub('\(.*?\)', '', src_line) + if not re.search(src_line, target_image_info): + test.fail(f"Not found '{src_line}' in {target_image_info}") + + +def run(test, params, env): + """ + To verify that libvirt can create target image automatically when do live + migration with copying storage. + + :param test: test object + :param params: Dictionary with the test parameters + :param env: Dictionary with test environment. + """ + def setup_test(): + """ + Setup steps + + """ + pool_name = params.get("target_pool_name") + pool_type = params.get("target_pool_type") + pool_target = params.get("target_pool_target") + dest_uri = params.get("virsh_migrate_desturi") + disk_format = params.get("disk_format") + disk_source_name = params.get("disk_source_name") + migrate_desturi_port = params.get("migrate_desturi_port") + migrate_desturi_type = params.get("migrate_desturi_type", "tcp") + + test.log.info("Setup steps.") + disk_source = os.path.dirname(disk_source_name) + if not os.path.exists(disk_source): + os.mkdir(disk_source) + cmd = "qemu-img convert -f qcow2 -O %s %s %s" % (disk_format, blk_source, disk_source_name) + process.run(cmd, shell=True) + + migration_obj.conn_list.append(migration_base.setup_conn_obj(migrate_desturi_type, params, test)) + migration_obj.remote_add_or_remove_port(migrate_desturi_port) + libvirt.set_vm_disk(vm, params) + + global src_image_info + cmd = "qemu-img info %s -U" % disk_source_name + src_image_info = process.run(cmd, ignore_status=True, shell=True).stdout_text.strip() + + remote.run_remote_cmd("mkdir -p %s" % pool_target, params) + virsh.pool_create_as(pool_name, pool_type, pool_target, uri=dest_uri, + ignore_status=True, debug=True) + + def verify_test(): + """ + Verify steps + + """ + disk_source_name = params.get("disk_source_name") + disk_format = params.get("disk_format") + copy_storage_option = params.get("copy_storage_option") + + test.log.info("Verify steps.") + migration_obj.verify_default() + if "copy-storage-all" in copy_storage_option: + check_image_info(params, test) + + def cleanup_test(): + """ + Cleanup steps + + """ + pool_name = params.get("target_pool_name") + dest_uri = params.get("virsh_migrate_desturi") + disk_source_name = params.get("disk_source_name") + + test.log.info("Cleanup steps.") + virsh.pool_destroy(pool_name, ignore_status=True, debug=True, uri=dest_uri) + cmd = "rm -rf %s" % disk_source_name + process.run(cmd, shell=True) + remote.run_remote_cmd(cmd, params) + migration_obj.cleanup_connection() + + vm_name = params.get("migrate_main_vm") + vm = env.get_vm(vm_name) + first_disk = vm.get_first_disk_devices() + blk_source = first_disk['source'] + migration_obj = base_steps.MigrationBase(test, vm, params) + + try: + setup_test() + migration_obj.run_migration() + verify_test() + finally: + cleanup_test() diff --git a/libvirt/tests/src/migration_with_copy_storage/target_image_larger_than_source.py b/libvirt/tests/src/migration_with_copy_storage/target_image_larger_than_source.py new file mode 100644 index 00000000000..3829e3e7169 --- /dev/null +++ b/libvirt/tests/src/migration_with_copy_storage/target_image_larger_than_source.py @@ -0,0 +1,272 @@ +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Copyright Redhat +# +# SPDX-License-Identifier: GPL-2.0 +# +# Author: Liping Cheng +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +import os +import shutil + +from avocado.utils import process + +from virttest import data_dir +from virttest import remote +from virttest import utils_misc +from virttest import utils_test +from virttest import virsh + +from virttest.libvirt_xml import vm_xml +from virttest.libvirt_xml.devices import disk +from virttest.staging import lv_utils +from virttest.utils_libvirt import libvirt_disk +from virttest.utils_libvirt import libvirt_vmxml +from virttest.utils_test import libvirt + +from provider.migration import base_steps +from provider.migration import migration_base + +dev_target = None + + +def setup_disk_on_source(vm, params, test): + """ + Setup disk on source host + + :param vm: VM object + :param params: dictionary with the test parameters + :param test: test object + """ + disk_size = params.get("disk_size") + disk_format = params.get("disk_format") + src_iscsi_size = params.get("src_iscsi_size") + src_lv_name = params.get("src_lv_name") + src_vg_name = params.get("src_vg_name") + disk_type = params.get("disk_type") + disk_source_name = params.get("disk_source_name") + src_block_path = params.get("src_block_path") + client_ip = params.get("client_ip") + slice_offset = params.get("slice_offset") + slice_size = params.get("slice_size") + + test.log.info("Prepare disk on source.") + blk_source = vm.get_first_disk_devices()['source'] + if disk_type == "block": + dev_src = libvirt.setup_or_cleanup_iscsi(is_setup=True, is_login=True, image_size=src_iscsi_size, emulated_image="emulated-iscsi1", portal_ip=client_ip) + if not lv_utils.vg_check(src_vg_name): + lv_utils.vg_create(src_vg_name, dev_src) + if not lv_utils.lv_check(src_vg_name, src_lv_name): + lv_utils.lv_create(src_vg_name, src_lv_name, disk_size) + cmd = "qemu-img convert -f qcow2 -O %s %s %s" % (disk_format, blk_source, src_block_path) + else: + cmd = "qemu-img convert -f qcow2 -O %s %s %s" % (disk_format, blk_source, disk_source_name) + process.run(cmd, shell=True) + + +def setup_migratable_xml(vm_name, params): + """ + Set migratable xml + + :param vm_name: vm name + :param params: dictionary with the test parameters + """ + target_disk_type = params.get("target_disk_type") + target_disk_dict = eval(params.get("target_disk_dict")) + + mig_disk = disk.Disk(type_name=target_disk_type) + mig_disk.setup_attrs(**target_disk_dict) + + guest_xml = vm_xml.VMXML.new_from_dumpxml(vm_name, options="--migratable") + guest_xml.remove_all_device_by_type("disk") + guest_xml.add_device(mig_disk) + guest_xml.xmltreefile.write() + tmp_dir = data_dir.get_tmp_dir() + xmlfile = os.path.join(tmp_dir, "xml_file") + shutil.copyfile(guest_xml.xml, xmlfile) + params.update({"virsh_migrate_extra": "--xml %s" % xmlfile}) + + +def setup_disk_on_target(params, test, block_dev): + """ + Setup disk on target host + + :param params: dictionary with the test parameters + :param test: test object + :param block_dev: remote disk manager object + """ + disk_format = params.get("disk_format") + target_iscsi_size = params.get("target_iscsi_size") + target_lv_name = params.get("target_lv_name") + target_vg_name = params.get("target_vg_name") + target_disk_size = params.get("target_disk_size") + target_disk_type = params.get("target_disk_type") + disk_source_name = params.get("disk_source_name") + target_block_path = params.get("target_block_path") + 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") + + test.log.info("Prepare disk on target.") + if target_disk_type == "block": + dev_target, _ = libvirt.setup_or_cleanup_iscsi(is_setup=True, is_login=False, image_size=target_iscsi_size, emulated_image="emulated-iscsi2", portal_ip=client_ip) + remote_dev = block_dev.iscsi_login_setup(client_ip, dev_target) + block_dev.create_vg(target_vg_name, remote_dev) + block_dev.create_image("lvm", size=target_disk_size, vgname=target_vg_name, lvname=target_lv_name, sparse=False, timeout=60) + else: + test.log.info("Prepare a raw format image on target.") + remote_session = remote.remote_login("ssh", server_ip, "22", + server_user, server_pwd, + r'[$#%]') + utils_misc.make_dirs(os.path.dirname(disk_source_name), remote_session) + libvirt_disk.create_disk("file", path=disk_source_name, + size=target_disk_size, disk_format=disk_format, + session=remote_session) + remote_session.close() + + +def cleanup_disk_on_source(params, test): + """ + Cleanup disk on source host + + :param params: dictionary with the test parameters + :param test: test object + """ + src_lv_name = params.get("src_lv_name") + src_vg_name = params.get("src_vg_name") + disk_type = params.get("disk_type") + disk_source_name = params.get("disk_source_name") + client_ip = params.get("client_ip") + + test.log.info("Cleanup disk on source.") + if disk_type == "block": + if lv_utils.lv_check(src_vg_name, src_lv_name): + lv_utils.lv_remove(src_vg_name, src_lv_name) + if lv_utils.vg_check(src_vg_name): + lv_utils.vg_remove(src_vg_name) + libvirt.setup_or_cleanup_iscsi(is_setup=False, emulated_image="emulated-iscsi1", portal_ip=client_ip) + cmd = "dmsetup ls" + ret = process.run(cmd, shell=True).stdout_text.strip() + dev_name = "%s-%s" % (src_vg_name, src_lv_name) + if dev_name in ret: + cmd = "dmsetup remove %s" % dev_name + process.run(cmd, shell=True) + else: + cmd = "rm -rf %s" % disk_source_name + process.run(cmd, shell=True) + + +def cleanup_disk_on_target(params, test, block_dev): + """ + Cleanup disk on target host + + :param params: dictionary with the test parameters + :param test: test object + :param block_dev: remote disk manager object + """ + target_lv_name = params.get("target_lv_name") + target_vg_name = params.get("target_vg_name") + target_disk_type = params.get("target_disk_type") + disk_source_name = params.get("disk_source_name") + 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") + + test.log.info("Cleanup disk on target.") + run_on_target = remote.RemoteRunner(host=server_ip, username=server_user, password=server_pwd) + if target_disk_type == "block": + block_dev.remove_path("lvm", "/dev/%s/%s" % (target_vg_name, target_lv_name)) + block_dev.remove_vg(target_vg_name) + block_dev.iscsi_login_setup(client_ip, dev_target, is_login=False) + libvirt.setup_or_cleanup_iscsi(is_setup=False, emulated_image="emulated-iscsi2", portal_ip=client_ip) + cmd = "dmsetup ls" + ret = remote.run_remote_cmd(cmd, params, run_on_target, ignore_status=False).stdout_text.strip() + dev_name = "%s-%s" % (target_vg_name, target_lv_name) + if dev_name in ret: + cmd = "dmsetup remove %s" % dev_name + remote.run_remote_cmd(cmd, params, run_on_target, ignore_status=False) + else: + cmd = "rm -rf %s" % disk_source_name + remote.run_remote_cmd(cmd, params, run_on_target, ignore_status=False) + + +def run(test, params, env): + """ + To verify that live migration with copying storage when target image size + is larger than source image size. + + :param test: test object + :param params: dictionary with the test parameters + :param env: dictionary with test environment. + """ + def setup_test(): + """ + Setup steps + + """ + migrate_desturi_port = params.get("migrate_desturi_port") + migrate_desturi_type = params.get("migrate_desturi_type", "tcp") + src_disk_dict = eval(params.get("src_disk_dict")) + + test.log.info("Setup steps.") + migration_obj.conn_list.append(migration_base.setup_conn_obj(migrate_desturi_type, params, test)) + migration_obj.remote_add_or_remove_port(migrate_desturi_port) + + setup_disk_on_source(vm, params, test) + + new_xml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + new_xml.remove_all_device_by_type('disk') + libvirt_vmxml.modify_vm_device(new_xml, 'disk', src_disk_dict) + + vm.start() + vm.wait_for_login().close() + + setup_disk_on_target(params, test, block_dev) + setup_migratable_xml(vm_name, params) + + def verify_test(): + """ + Verify steps + + """ + test.log.info("Verify steps.") + target_disk_size = params.get("target_disk_size") + desturi = params.get("virsh_migrate_desturi") + + virsh.blockresize(vm_name, "vda", target_disk_size, ignore_status=False, uri=desturi) + migration_obj.verify_default() + + def cleanup_test(): + """ + Cleanup steps + + """ + test.log.info("Cleanup steps.") + srcuri = params.get("virsh_migrate_connect_uri") + desturi = params.get("virsh_migrate_desturi") + + vm.connect_uri = desturi + if vm.is_alive(): + vm.destroy() + vm.connect_uri = srcuri + + cleanup_disk_on_target(params, test, block_dev) + cleanup_disk_on_source(params, test) + + vm_name = params.get("migrate_main_vm") + + vm = env.get_vm(vm_name) + migration_obj = base_steps.MigrationBase(test, vm, params) + block_dev = utils_test.RemoteDiskManager(params) + + try: + setup_test() + migration_obj.run_migration() + verify_test() + finally: + cleanup_test() + migration_obj.cleanup_connection() diff --git a/libvirt/tests/src/migration_with_copy_storage/target_image_smaller_than_source.py b/libvirt/tests/src/migration_with_copy_storage/target_image_smaller_than_source.py new file mode 100644 index 00000000000..775ecd5e6a1 --- /dev/null +++ b/libvirt/tests/src/migration_with_copy_storage/target_image_smaller_than_source.py @@ -0,0 +1,62 @@ +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Copyright Redhat +# +# SPDX-License-Identifier: GPL-2.0 +# +# Author: Liping Cheng +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +import os + +from virttest import remote +from virttest import utils_misc + +from virttest.utils_libvirt import libvirt_disk + +from provider.migration import base_steps + + +def run(test, params, env): + """ + To verify that live migration with copying storage will fail when target + image size is smaller than source image size. + + :param test: test object + :param params: dictionary with the test parameters + :param env: dictionary with test environment. + """ + def setup_test(): + """ + Setup steps + + """ + server_ip = params.get("server_ip") + server_user = params.get("server_user") + server_pwd = params.get("server_pwd") + disk_size = params.get("disk_size") + + migration_obj.setup_connection() + remote_session = remote.remote_login("ssh", server_ip, "22", + server_user, server_pwd, + r'[$#%]') + first_disk = vm.get_first_disk_devices() + disk_path = first_disk["source"] + utils_misc.make_dirs(os.path.dirname(disk_path), remote_session) + libvirt_disk.create_disk(first_disk["type"], path=disk_path, + size=disk_size, disk_format="qcow2", + session=remote_session) + remote_session.close() + + 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() + migration_obj.verify_default() + finally: + migration_obj.cleanup_connection() + base_steps.cleanup_disks_remote(params, vm) diff --git a/libvirt/tests/src/numa/guest_numa.py b/libvirt/tests/src/numa/guest_numa.py index 3ece45dc093..b06a24a7ff9 100644 --- a/libvirt/tests/src/numa/guest_numa.py +++ b/libvirt/tests/src/numa/guest_numa.py @@ -12,6 +12,7 @@ from virttest import test_setup from virttest import utils_params from virttest import libvirt_version +from virttest.staging import utils_memory # Using as lower capital is not the best way to do, but this is just a @@ -49,19 +50,24 @@ def handle_param(param_tuple, params): return param_list -def dynamic_node_replacement(params, numa_info, test_obj): +def dynamic_node_replacement(params, numa_info, arch, test_obj): """ Replace numa node parameters dynamically per current system configuration :param numa_info: available numa node info from avocado-vt/utils_misc :param params: all params passed to test + :param arch: The host architecture :param test_obj: test object - for cancel case """ node_list = numa_info.get_online_nodes_withmem() key_names = ['memnode_nodeset_', 'page_nodenum_'] for param in params: if 'numa_cells_with_memory_required' in param: - if int(params['numa_cells_with_memory_required']) > len(node_list): + arch = platform.machine() + if 'ppc64' in arch: + if not node_list: + test_obj.cancel("No NUMA nodes available on this system to perform the test.") + elif int(params['numa_cells_with_memory_required']) > len(node_list): test_obj.cancel("There is no enough NUMA nodes available on this system to perform the test.") if 'memory_nodeset' in param: params['memory_nodeset'] = ','.join([str(elem) for elem in node_list]) @@ -97,39 +103,10 @@ def run(test, params, env): """ Test guest numa setting """ - - def replace_qemu_cmdline(cmdline_list): - """ - Replace the expected qemu command line for new machine type - - :param cmdline_list: The list for expected qemu command lines - :return: The list contains the updated qemu command lines if any - """ - os_xml = getattr(vmxml, "os") - machine_ver = getattr(os_xml, 'machine') - if (machine_ver.startswith("pc-q35-rhel") and - machine_ver > 'pc-q35-rhel8.2.0' and - libvirt_version.version_compare(6, 4, 0)): - # Replace 'node,nodeid=0,cpus=0-1,mem=1024' with - # 'node,nodeid=0,cpus=0-1,memdev=ram-node0' - # Replace 'node,nodeid=1,cpus=2-3,mem=1024' with - # 'node,nodeid=1,cpus=2-3,memdev=ram-node1' - for cmd in cmdline_list: - line = cmd['cmdline'] - try: - node = line.split(',')[1][-1] - cmd['cmdline'] = line.replace('mem=1024', - 'memdev=ram-node{}'.format(node)) - # We can skip replacing, when the cmdline parameter is empty. - except IndexError: - pass - - return cmdline_list - host_numa_node = utils_misc.NumaInfo() node_list = host_numa_node.online_nodes arch = platform.machine() - dynamic_node_replacement(params, host_numa_node, test) + dynamic_node_replacement(params, host_numa_node, arch, test) if 'ppc64' in arch: try: ppc_memory_nodeset = "" @@ -140,9 +117,11 @@ def replace_qemu_cmdline(cmdline_list): ppc_memory_nodeset += str(node_list[int(nodes.split('-')[1])]) else: node_lst = nodes.split(',') - for n in range(len(node_lst) - 1): - ppc_memory_nodeset += str(node_list[int(node_lst[n])]) + ',' - ppc_memory_nodeset += str(node_list[int(node_lst[-1])]) + for n in range(len(node_lst)): + if int(node_lst[n]) in node_list: + ppc_memory_nodeset += str(node_lst[n]) + if n < len(node_lst) - 1: + ppc_memory_nodeset += ',' params['memory_nodeset'] = ppc_memory_nodeset except IndexError: test.cancel("No of numas in config does not match with no of " @@ -153,7 +132,11 @@ def replace_qemu_cmdline(cmdline_list): for pkey in pkeys: for key in params.keys(): if pkey in key: - params[key] = str(node_list[int(params[key])]) + index = int(params[key]) + if index < len(node_list): + params[key] = str(node_list[index]) + else: + params[key] = str(node_list[-1]) # Modify qemu command line try: if params['qemu_cmdline_mem_backend_1']: @@ -230,9 +213,17 @@ def replace_qemu_cmdline(cmdline_list): backup_list = [] page_tuple = ('vmpage_size', 'vmpage_unit', 'vmpage_nodeset') page_list = handle_param(page_tuple, params) - nr_pagesize_total = params.get("nr_pagesize_total") + hugepage_mem_total = params.get("hugepage_mem_total") deallocate = False + # Calculate huge page number and change huge page size to + # default huge page size + if hugepage_mem_total and page_list: + default_mem_huge_page_size = utils_memory.get_huge_page_size() + hugepage_num = int(hugepage_mem_total) // default_mem_huge_page_size + for page in page_list: + page['size'] = str(default_mem_huge_page_size) + if page_list: if not libvirt_version.version_compare(1, 2, 5): test.cancel("Setting hugepages more specifically per " @@ -250,7 +241,7 @@ def _update_qemu_conf(): """ Mount hugepage path, update qemu conf then restart libvirtd """ - size_dict = {'2048': '2M', '1048576': '1G', '16384': '16M'} + size_dict = {'2048': '2M', '1048576': '1G', '16384': '16M', '524288': '512M'} for page in page_list: if page['size'] not in supported_hp_size: test.cancel("Hugepage size [%s] isn't supported, " @@ -297,12 +288,25 @@ def _update_qemu_conf(): qemu_conf_restore = True # set hugepage with total number or per-node number - if nr_pagesize_total: - # Only set total 2M size huge page number as total 1G size runtime - # update not supported now. + if hugepage_mem_total and page_list: + # Only set default huge page memory deallocate = True - hp_cl.target_hugepages = int(nr_pagesize_total) + hp_cl.target_hugepages = hugepage_num hp_cl.set_hugepages() + # for strict mode, allocate the guest numa cell again to + # make sure it has enough huge page + numa_hugepage_dict = {} + if numa_memnode and numa_memnode[0]['mode'] == 'strict': + if numa_cell: + for cell in numa_cell: + if cell['id'] == numa_memnode[0]['cellid']: + numa_hugepage_dict['node'] = numa_memnode[0]['nodeset'] + numa_hugepage_dict['hp_num'] = int( + cell['memory']) // default_mem_huge_page_size + numa_hugepage_dict['hp_size'] = default_mem_huge_page_size + if numa_hugepage_dict: + hp_cl.set_node_num_huge_pages( + numa_hugepage_dict['hp_num'], numa_hugepage_dict['node'], numa_hugepage_dict['hp_size']) if page_list: hp_size = [h_list[p_size]['size'] for p_size in range(len(h_list))] multi_hp_size = hp_cl.get_multi_supported_hugepage_size() @@ -355,7 +359,8 @@ def _update_qemu_conf(): # guest numa cpu setting vmcpuxml = libvirt_xml.vm_xml.VMCPUXML() - vmcpuxml.xml = "" + cpu_mode = params.get('cpu_mode') + vmcpuxml.xml = "" % cpu_mode if topology: vmcpuxml.topology = topology logging.debug(vmcpuxml.numa_cell) @@ -429,7 +434,6 @@ def _update_qemu_conf(): with open("/proc/%s/cmdline" % vm_pid) as f_cmdline: q_cmdline_list = f_cmdline.read().split("\x00") logging.debug("vm qemu cmdline list is %s" % q_cmdline_list) - cmdline_list = replace_qemu_cmdline(cmdline_list) for cmd in cmdline_list: logging.debug("checking '%s' in qemu cmdline", cmd['cmdline']) p_found = False diff --git a/libvirt/tests/src/numa/guest_numa_hmat/hmat_info.py b/libvirt/tests/src/numa/guest_numa_hmat/hmat_info.py new file mode 100644 index 00000000000..9286e1dd83b --- /dev/null +++ b/libvirt/tests/src/numa/guest_numa_hmat/hmat_info.py @@ -0,0 +1,221 @@ +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Copyright Red Hat +# +# SPDX-License-Identifier: GPL-2.0 +# Author: Dan Zheng +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +from virttest import libvirt_version +from virttest import utils_libvirtd +from virttest import utils_package +from virttest import virsh +from virttest import ssh_key + +from virttest.libvirt_xml import capability_xml +from virttest.libvirt_xml import vm_xml +from virttest.utils_test import libvirt + +from provider.numa import numa_base +from provider.virtual_network import network_base + + +def setup_default(test_obj): + """ + Default setup function for the test + + :param test_obj: NumaTest object + """ + test_obj.setup() + test_obj.test.log.debug("Step: setup is done") + + +def prepare_vm_xml(test_obj): + """ + Customize the vm xml + + :param test_obj: NumaTest object + :return: VMXML object updated + """ + vmxml = test_obj.prepare_vm_xml() + test_obj.test.log.debug("Step: vm xml before defining:\n%s", vmxml) + return vmxml + + +def verify_guest_dmesg(test_obj, vm_session): + """ + Verify messages in guest dmesg output + + :param test_obj: NumaTest object + :param vm_session: vm session + """ + dmesg_pattern = test_obj.params.get("dmesg_pattern") + search_list = dmesg_pattern.split(",") + cmd_dmesg = 'dmesg | grep hmat' + status, output = vm_session.cmd_status_output(cmd_dmesg) + if status: + test_obj.test.error("Can not find any message with command '%s'" % cmd_dmesg) + + for search_item in search_list: + if not output.count(search_item): + test_obj.test.fail("Expect '%s' in guest dmesg, but not found" % search_item) + else: + test_obj.test.log.debug("Verify '%s' in guest dmesg - PASS", search_item) + test_obj.test.log.debug("Verify guest dmesg - PASS") + + +def verify_qemu_command_line(test_obj): + """ + Verify qemu command line + + :param test_obj: NumaTest object + """ + all_search_keys = [key for key in list(test_obj.params.keys()) if "qemu_check" in key] + + all_search_values = [test_obj.params.get(key) for key in all_search_keys] + test_obj.test.log.debug("search string:%s", all_search_values) + libvirt.check_qemu_cmd_line(all_search_values, expect_exist=True) + test_obj.test.log.debug("Verify qemu command line - PASS") + + +def verify_hmat_info(test_obj, vm_session): + """ + Verify HMAT info + + :param test_obj: NumaTest object + :param vm_session: vm session + """ + if not utils_package.package_install("libvirt", vm_session): + test_obj.test.fail("Failed to install libvirt on guest") + if libvirt_version.version_compare(9, 0, 0): + for daemon_name in ["virtproxyd.socket", "virtqemud.socket"]: + daemon = utils_libvirtd.Libvirtd(daemon_name, session=vm_session) + daemon.start() + test_obj.test.log.debug("%s is started", daemon_name) + + iface_mac = vm_xml.VMXML.get_first_mac_by_name(test_obj.vm.name) + vm_ip = network_base.get_vm_ip(vm_session, iface_mac) + if not vm_ip: + test_obj.test.error("Can not get vm IP") + connect_uri = "qemu+ssh://%s/system" % vm_ip + vm_user = test_obj.params.get("username", "root") + vm_user_passwd = test_obj.params.get("password") + ssh_key.setup_ssh_key(vm_ip, vm_user, vm_user_passwd) + output = virsh.capabilities("", uri=connect_uri, + ignore_status=False, debug=True) + cap_xml = capability_xml.CapabilityXML() + cap_xml.xml = output + + verify_hmat_cache_by_virsh_capabilities(test_obj, cap_xml) + verify_hmat_interconnects_by_virsh_capabilities(test_obj, cap_xml) + + +def verify_hmat_cache_by_virsh_capabilities(test_obj, cap_xml): + """ + Verify HMAT cache info + + :param test_obj: NumaTest object + :param cap_xml: CapabilityXML instance + """ + def _compare(cell_id, cache_id, expect_cache, actual_cache): + if actual_cache != expect_cache: + test_obj.test.fail("Expect cache %d in cell %d to be '%s', " + "but found '%s'" % (cache_id, cell_id, + expect_cache, + actual_cache)) + + numa_cell0_cache0 = eval(test_obj.params.get("numa_cell0_cache0")) + numa_cell0_cache1 = eval(test_obj.params.get("numa_cell0_cache1")) + numa_cell1_cache0 = eval(test_obj.params.get("numa_cell1_cache0")) + cells = cap_xml.cells_topology.get_cell() + + actual_cell0_cache0 = cells[0].cache[0].fetch_attrs() + actual_cell0_cache1 = cells[0].cache[1].fetch_attrs() + actual_cell1_cache0 = cells[1].cache[0].fetch_attrs() + _compare(0, 0, numa_cell0_cache0, actual_cell0_cache0) + _compare(0, 1, numa_cell0_cache1, actual_cell0_cache1) + _compare(1, 0, numa_cell1_cache0, actual_cell1_cache0) + test_obj.test.log.debug("Verify HMAT cache information in virsh capability - PASS") + + +def verify_hmat_interconnects_by_virsh_capabilities(test_obj, cap_xml): + """ + Verify HMAT interconnects info + + :param test_obj: NumaTest object + :param cap_xml: CapabilityXML instance + """ + def _compare(conf_items, actual_items, item_name): + conf_sublist = [] + for item in conf_items: + # Ignore checking "access" because kernel does not expose it yet + if item["type"] == "access" or item.get("cache"): + continue + conf_sublist.append(item) + if len(conf_sublist) != len(actual_items): + test_obj.test.fail("Expect %s to be '%s', " + "but found '%s'" % (item_name, + conf_sublist, + actual_items)) + for conf_item in conf_sublist: + if conf_item not in actual_items: + test_obj.test.fail("Expect %s to include '%s', " + "but not found in '%s'" % (item_name, + conf_item, + actual_items)) + else: + test_obj.test.log.debug("Verify '%s' in HMAT interconnects of " + "virsh capability in guest - PASS", item_name) + interconnects = cap_xml.cells_topology.interconnects.fetch_attrs() + conf_bandwidth = eval(test_obj.params.get("bandwidth")) + conf_latency = eval(test_obj.params.get("latency")) + _compare(conf_bandwidth, interconnects["bandwidth"], "bandwidth") + _compare(conf_latency, interconnects["latency"], "latency") + test_obj.test.log.debug("Verify HMAT interconnects information of " + "virsh capability in guest - PASS") + + +def run_default(test_obj): + """ + Default run function for the test + + :param test_obj: NumaTest object + """ + test_obj.test.log.debug("Step: prepare vm xml") + vmxml = prepare_vm_xml(test_obj) + test_obj.test.log.debug("Step: define vm") + virsh.define(vmxml.xml, **test_obj.virsh_dargs) + test_obj.test.log.debug("Step: start vm") + ret = virsh.start(test_obj.vm.name, **test_obj.virsh_dargs) + test_obj.test.log.debug("After vm is started, vm xml:\n" + "%s", vm_xml.VMXML.new_from_dumpxml(test_obj.vm.name)) + vm_session = test_obj.vm.wait_for_login() + verify_qemu_command_line(test_obj) + verify_guest_dmesg(test_obj, vm_session) + verify_hmat_info(test_obj, vm_session) + + +def teardown_default(test_obj): + """ + Default teardown function for the test + + :param test_obj: NumaTest object + """ + test_obj.teardown() + test_obj.test.log.debug("Step: teardown is done") + + +def run(test, params, env): + """ + Test for numa memory binding with emulator thread pin + """ + vm_name = params.get("main_vm") + vm = env.get_vm(vm_name) + numatest_obj = numa_base.NumaTest(vm, params, test) + try: + setup_default(numatest_obj) + run_default(numatest_obj) + finally: + teardown_default(numatest_obj) diff --git a/libvirt/tests/src/numa/guest_numa_node_tuning/auto_memory_nodeset_placement.py b/libvirt/tests/src/numa/guest_numa_node_tuning/auto_memory_nodeset_placement.py index abe4bf3eff7..5699f101b55 100644 --- a/libvirt/tests/src/numa/guest_numa_node_tuning/auto_memory_nodeset_placement.py +++ b/libvirt/tests/src/numa/guest_numa_node_tuning/auto_memory_nodeset_placement.py @@ -114,7 +114,7 @@ def verify_cgroup_mem_binding(test_obj): """ mem_mode = test_obj.params.get('mem_mode') nodeset = test_obj.params.get('nodeset') - online_nodes = libvirt_numa.parse_numa_nodeset_to_str('x-y', test_obj.online_nodes) + online_nodes = libvirt_numa.convert_all_nodes_to_string(test_obj.online_nodes) vcpu_placement = eval(test_obj.params.get('vm_attrs')).get('placement') vm_pid = test_obj.vm.get_pid() cg = libvirt_cgroup.CgroupTest(vm_pid) @@ -391,8 +391,6 @@ def get_cpus_by_numad_advisory(test_obj): if cpus_from_numactl: cpus_from_numactl = cpus_from_numactl[0].strip().split(' ') cpus_from_numactl = [int(item) for item in cpus_from_numactl] - else: - test_obj.test.error("Can not find node %s's cpus" % nodeset_numad) cpus += cpus_from_numactl test_obj.test.log.debug("The cpus on the node advised by numad: %s", cpus) return sorted(cpus) diff --git a/libvirt/tests/src/numa/guest_numa_node_tuning/auto_memory_placement_numad_fail.py b/libvirt/tests/src/numa/guest_numa_node_tuning/auto_memory_placement_numad_fail.py new file mode 100644 index 00000000000..31f5edff40c --- /dev/null +++ b/libvirt/tests/src/numa/guest_numa_node_tuning/auto_memory_placement_numad_fail.py @@ -0,0 +1,102 @@ +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Copyright Red Hat +# +# SPDX-License-Identifier: GPL-2.0 +# +# Author: Dan Zheng +# + +import os +import shutil + +from avocado.utils import process + +from virttest import data_dir +from virttest import virsh + +from virttest.utils_test import libvirt + +from provider.numa import numa_base + + +def modify_numad_executable_file(numatest_obj): + """ + Modify numad executable file + + :param numatest_obj: NumaTest object + """ + dest_dir = os.path.join(data_dir.get_tmp_dir(), 'numad') + numad_path_origin = '/usr/bin/numad' + shutil.copyfile(numad_path_origin, dest_dir) + new_numad_content = """ +#! /bin/sh +exit 1""" + + with open(numad_path_origin, 'w') as fp: + fp.write(new_numad_content) + + process.run('restorecon %s' % numad_path_origin, shell=True) + numatest_obj.test.log.debug("Backup the numad file to %s", dest_dir) + return dest_dir + + +def setup_default(numatest_obj): + """ + Default setup function for the test + + :param numatest_obj: NumaTest object + """ + dest_dir = modify_numad_executable_file(numatest_obj) + numatest_obj.test.params['numad_backup'] = dest_dir + numatest_obj.setup() + numatest_obj.test.log.debug("Step: setup is done") + + +def run_default(numatest_obj): + """ + Default run function for the test + + :param numatest_obj: NumaTest object + """ + numatest_obj.test.log.debug("Step: prepare vm xml") + vmxml = numatest_obj.prepare_vm_xml() + numatest_obj.test.log.debug("Step: define vm") + ret = virsh.define(vmxml.xml, **numatest_obj.virsh_dargs) + numatest_obj.test.log.debug("Step: start vm and check result") + numatest_obj.virsh_dargs.update({'ignore_status': True}) + ret = virsh.start(numatest_obj.vm.name, **numatest_obj.virsh_dargs) + err_msg_expected = numatest_obj.produce_expected_error() + libvirt.check_result(ret, expected_fails=err_msg_expected) + + +def teardown_default(numatest_obj): + """ + Default teardown function for the test + + :param numatest_obj: NumaTest object + """ + numatest_obj.teardown() + numad_backup = numatest_obj.test.params['numad_backup'] + numad_path_origin = '/usr/bin/numad' + with open(numad_path_origin) as fp: + numatest_obj.test.log.debug("Before recovering, " + "%s is%s", numad_path_origin, fp.read()) + shutil.copyfile(numad_backup, numad_path_origin) + process.run('restorecon %s' % numad_path_origin, shell=True) + numatest_obj.test.log.debug("Step: teardown is done") + + +def run(test, params, env): + """ + Test for numa memory binding with emulator thread pin + """ + vm_name = params.get("main_vm") + vm = env.get_vm(vm_name) + numatest_obj = numa_base.NumaTest(vm, params, test) + try: + setup_default(numatest_obj) + run_default(numatest_obj) + finally: + teardown_default(numatest_obj) diff --git a/libvirt/tests/src/numa/guest_numa_node_tuning/change_numa_tuning.py b/libvirt/tests/src/numa/guest_numa_node_tuning/change_numa_tuning.py index 4c7d5b94141..8b3acf760fb 100644 --- a/libvirt/tests/src/numa/guest_numa_node_tuning/change_numa_tuning.py +++ b/libvirt/tests/src/numa/guest_numa_node_tuning/change_numa_tuning.py @@ -21,6 +21,7 @@ from virttest.utils_libvirt import libvirt_misc from virttest.utils_libvirt import libvirt_vmxml from virttest.utils_test import libvirt +from virttest.staging import utils_memory from provider.numa import numa_base @@ -45,7 +46,7 @@ def prepare_vm_xml(test_obj): :return: VMXML object updated """ vmxml = test_obj.prepare_vm_xml() - all_nodes = test_obj.all_usable_numa_nodes + all_nodes = test_obj.online_nodes_withmem mem_total = test_obj.host_numa_info.read_from_node_meminfo(all_nodes[0], 'MemTotal') offset = 1000000 if int(mem_total) < offset: @@ -77,9 +78,9 @@ def verify_host_numa_memory_allocation(test_obj, check_N0=False): :param test_obj: NumaTest object """ mem_size = get_memory_in_vmxml(test_obj) - kernelpagesize_kB = test_obj.params.get('kernelpagesize_kB') + kernelpagesize_kB = utils_memory.getpagesize() out_numa_maps = numa_base.get_host_numa_memory_alloc_info(mem_size) - all_nodes = test_obj.all_usable_numa_nodes + all_nodes = test_obj.online_nodes_withmem N0_value = re.findall('N%s=(\d+)' % all_nodes[0], out_numa_maps) N1_value = re.findall('N%s=(\d+)' % all_nodes[1], out_numa_maps) has_kernelpage = bool(re.search('kernelpagesize_kB=%s' % kernelpagesize_kB, out_numa_maps)) @@ -173,10 +174,10 @@ def run_default(test_obj): another_mem_mode = select_different_mem_mode(mem_mode) verify_numatune(test_obj, mem_mode=another_mem_mode, - nodeset=str(test_obj.all_usable_numa_nodes[1])) + nodeset=str(test_obj.online_nodes_withmem[1])) numatune_result = virsh.numatune(test_obj.vm.name, mode=mem_mode, - nodeset=str(test_obj.all_usable_numa_nodes[0]), + nodeset=str(test_obj.online_nodes_withmem[0]), **test_obj.virsh_dargs).stdout_text.strip() test_obj.test.log.debug("Step: start vm") ret = virsh.start(test_obj.vm.name, **test_obj.virsh_dargs) @@ -187,7 +188,7 @@ def run_default(test_obj): error_expected = produce_expected_error(test_obj) verify_numatune(test_obj, mem_mode=another_mem_mode, - nodeset=test_obj.all_usable_numa_nodes[0], + nodeset=test_obj.online_nodes_withmem[0], error_expected=error_expected) @@ -211,9 +212,9 @@ def run_mem_mode_restrictive(test_obj): mem_mode = test_obj.params.get('mem_mode') run_default(test_obj) test_obj.test.log.debug("Step: change numatune nodeset on running vm when mode is restrictive") - verify_numatune(test_obj, mem_mode=mem_mode, nodeset=test_obj.all_usable_numa_nodes[1]) + verify_numatune(test_obj, mem_mode=mem_mode, nodeset=test_obj.online_nodes_withmem[1]) verify_host_numa_memory_allocation(test_obj) - nodeset = "%s,%s" % (test_obj.all_usable_numa_nodes[0], test_obj.all_usable_numa_nodes[1]) + nodeset = "%s,%s" % (test_obj.online_nodes_withmem[0], test_obj.online_nodes_withmem[1]) nodeset = numa_base.convert_to_string_with_dash(nodeset) test_obj.test.log.debug("Step: change numatune nodeset in range on running vm when mode is restrictive") verify_numatune(test_obj, mem_mode=mem_mode, nodeset=nodeset) diff --git a/libvirt/tests/src/numa/guest_numa_node_tuning/host_guest_mixed_memory_binding.py b/libvirt/tests/src/numa/guest_numa_node_tuning/host_guest_mixed_memory_binding.py new file mode 100644 index 00000000000..c9412e918e6 --- /dev/null +++ b/libvirt/tests/src/numa/guest_numa_node_tuning/host_guest_mixed_memory_binding.py @@ -0,0 +1,382 @@ +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Copyright Red Hat +# +# SPDX-License-Identifier: GPL-2.0 +# +# Author: Dan Zheng +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +import os +import re + +from avocado.utils import process + +from virttest import libvirt_cgroup +from virttest import libvirt_version +from virttest import virsh +from virttest.libvirt_xml import vm_xml +from virttest.utils_test import libvirt +from virttest.utils_libvirt import libvirt_memory +from virttest.utils_libvirt import libvirt_numa + +from provider.numa import numa_base + + +def setup_default(numatest_obj): + """ + Default setup function for the test + + :param numatest_obj: NumaTest object + """ + numatest_obj.setup(expect_node_free_mem_min=1048576) + numatest_obj.test.log.debug("Step: setup is done") + + +def prepare_vm_xml(numatest_obj): + """ + Customize the vm xml + + :param numatest_obj: NumaTest object + + :return: VMXML object updated + """ + numa_memnode = numatest_obj.params.get('numa_memnode') + numa_memnode = numa_memnode % numatest_obj.online_nodes_withmem[1] + numatest_obj.params['numa_memnode'] = numa_memnode + vmxml = numatest_obj.prepare_vm_xml() + numatest_obj.test.log.debug("Step: vm xml before defining:\n%s", vmxml) + return vmxml + + +def generate_start_expected_error(numatest_obj): + """ + produce the expected error message + + :param numatest_obj: NumaTest object + + :return: str, error message to be checked + """ + err_msg = numatest_obj.produce_expected_error() + mem_mode = numatest_obj.params.get('mem_mode') + single_host_node = numatest_obj.params.get('single_host_node') + memnode_mode = numatest_obj.params.get('memnode_mode') + + if (not libvirt_version.version_compare(9, 4, 0) and + memnode_mode != 'restrictive' and + single_host_node == 'yes' and + mem_mode == 'strict'): + new_err_msg = "cannot bind memory to host NUMA nodes: Invalid argument" + err_msg = "%s|%s" % (err_msg, new_err_msg) if err_msg else new_err_msg + return err_msg + + +def generate_define_expected_error(numatest_obj): + """ + produce the expected error message + + :param numatest_obj: NumaTest object + + :return: str, error message to be checked + """ + mem_mode = numatest_obj.params.get('mem_mode') + single_host_node = numatest_obj.params.get('single_host_node') + memnode_mode = numatest_obj.params.get('memnode_mode') + err_msg = '' + msg = "'restrictive' mode is required in %s element when mode is 'restrictive' in %s element" + if mem_mode == 'restrictive' and memnode_mode != 'restrictive': + err_msg = msg % ('memnode', 'memory') + if (libvirt_version.version_compare(9, 4, 0) and + (mem_mode != 'restrictive' or single_host_node is None) and + memnode_mode == 'restrictive'): + err_msg = msg % ('memory', 'memnode') + + return err_msg + + +def check_vm_numa_1_memory_allocation(numatest_obj, mem_size): + """ + Check vm numa node 1's memory allocation information + + :param numatest_obj: NumaTest object + :param mem_size: int, vm node memory size + """ + out_numa_maps = numa_base.get_host_numa_memory_alloc_info(mem_size) + memnode_mode = numatest_obj.params.get('memnode_mode') + mem_mode = numatest_obj.params.get('mem_mode') + single_host_node = numatest_obj.params.get('single_host_node') + all_nodes = numatest_obj.online_nodes_withmem + node_values = {} + numatest_obj.test.log.debug("all_nodes:%s", all_nodes) + for node_num in all_nodes: + node_value = re.findall('N%s=(\d+)' % node_num, out_numa_maps) + if not node_value: + continue + numatest_obj.test.log.debug("N%s_value:%s", node_num, node_value[0]) + node_values[node_num] = node_value[0] + + def _check_N0_no_N1(): + if all_nodes[0] not in node_values: + numatest_obj.test.fail("Expect N%s > 0, but found not" % all_nodes[0]) + if all_nodes[1] in node_values: + numatest_obj.test.fail("Not expect N%s to exist, but found" % all_nodes[1]) + + def _check_N0_N1_sum(): + n0_value = 0 if all_nodes[0] not in node_values else int(node_values[all_nodes[0]]) + n1_value = 0 if all_nodes[1] not in node_values else int(node_values[all_nodes[1]]) + if n0_value + n1_value <= 0: + numatest_obj.test.fail("Expect N%s + N%s > 0, but found " + "not" % (all_nodes[0], all_nodes[1])) + + def _check_all_nodes_sum(): + node_value_sum = 0 + for node_value in node_values.values(): + node_value_sum += int(node_value) + if node_value_sum <= 0: + numatest_obj.test.fail("Expect the sum of all node values is greater than 0, but found not") + + def _check_N0(): + if all_nodes[0] not in node_values: + numatest_obj.test.fail("Expect N%s > 0, but found not" % all_nodes[0]) + + if mem_mode is not None: + if single_host_node == "yes": + if mem_mode == 'strict' and memnode_mode in ['strict', 'interleave', 'preferred']: + pat = "bind:%s" % all_nodes[0] + _check_N0_no_N1() + if mem_mode == 'strict' and memnode_mode == 'restrictive': + pat = "bind:%s" % all_nodes[0] + _check_N0_N1_sum() + if mem_mode == 'interleave': + pat = "interleave:%s" % all_nodes[0] + _check_N0() + if mem_mode == 'preferred': + pat = "prefer \(many\):%s" % all_nodes[0] \ + if libvirt_version.version_compare(9, 3, 0) \ + else "prefer:%s" % all_nodes[0] + _check_N0() + if mem_mode == 'restrictive': + pat = "default" + _check_N0_N1_sum() + elif single_host_node == 'no': + nodeset = numa_base.convert_to_string_with_dash(numatest_obj.params['nodeset']) + if mem_mode == 'strict': + pat = "bind:%s" % nodeset + if mem_mode == 'interleave': + pat = "interleave:%s" % nodeset + if mem_mode == 'preferred': + pat = "prefer \(many\):%s" % nodeset + if mem_mode == 'restrictive': + pat = "default" + _check_N0_N1_sum() + else: + pat = "default" + _check_all_nodes_sum() + + search_pattern = r"\s+%s\s+anon=" % pat + if not re.findall(search_pattern, out_numa_maps): + numatest_obj.test.fail("Fail to find the pattern '%s' in " + "numa_maps output '%s'" % (search_pattern, + out_numa_maps)) + numatest_obj.test.log.debug("Step: verify vm numa node 1 memory allocation - PASS") + + +def check_vm_numa_0_memory_allocation(numatest_obj, mem_size): + """ + Check vm numa node 0's memory allocation information + + :param numatest_obj: NumaTest object + :param mem_size: int, vm node memory size + """ + out_numa_maps = numa_base.get_host_numa_memory_alloc_info(mem_size) + all_nodes = numatest_obj.online_nodes_withmem + node0_value = re.findall('N%s=(\d+)' % all_nodes[0], out_numa_maps) + node1_value = re.findall('N%s=(\d+)' % all_nodes[1], out_numa_maps) + memnode_mode = numatest_obj.params.get('memnode_mode') + + if memnode_mode == 'strict': + pat = "bind:%s" % all_nodes[1] + elif memnode_mode == 'interleave': + pat = "interleave:%s" % all_nodes[1] + elif memnode_mode == 'preferred': + if not libvirt_version.version_compare(9, 3, 0): + pat = "prefer:%s" % all_nodes[1] + else: + pat = "prefer \(many\):%s" % all_nodes[1] + else: + pat = "default" + node0_value = 0 if not node0_value else int(node0_value[0]) + node1_value = 0 if not node1_value else int(node1_value[0]) + if node0_value + node1_value <= 0: + numatest_obj.test.fail("Expect N%s + N%s > 0, but " + "found not" % (all_nodes[0], all_nodes[1])) + search_pattern = r"\s+%s\s+anon=" % pat + if not re.findall(search_pattern, out_numa_maps): + numatest_obj.test.fail("Fail to find the pattern '%s' in " + "numa_maps output '%s'" % (search_pattern, + out_numa_maps)) + numatest_obj.test.log.debug("Step: verify vm numa 0 memory allocation - PASS") + + +def check_cgroup(numatest_obj): + """ + Check vm cgroup information + + :param numatest_obj: NumaTest object + """ + memnode_mode = numatest_obj.params.get('memnode_mode') + mem_mode = numatest_obj.params.get('mem_mode') + single_host_node = numatest_obj.params.get('single_host_node') + all_nodes = numatest_obj.online_nodes_withmem + + vm_pid = numatest_obj.vm.get_pid() + cg = libvirt_cgroup.CgroupTest(vm_pid) + is_cgroup2 = cg.is_cgroup_v2_enabled() + surfix_emulator = 'emulator/cpuset.mems' if is_cgroup2 else 'cpuset.mems' + surfix_vcpu0 = 'vcpu0/cpuset.mems' if is_cgroup2 else '../vcpu0/cpuset.mems' + surfix_vcpu1 = 'vcpu1/cpuset.mems' if is_cgroup2 else '../vcpu1/cpuset.mems' + numatest_obj.test.log.debug("The cgroup_path for " + "controller 'cpuset':%s", cg.get_cgroup_path(controller='cpuset')) + emulator_cpuset_mems_cgroup_path = os.path.join(cg.get_cgroup_path(controller='cpuset'), + surfix_emulator) + vcpu0_cpuset_mems_cgroup_path = os.path.join(cg.get_cgroup_path(controller='cpuset'), + surfix_vcpu0) + vcpu1_cpuset_mems_cgroup_path = os.path.join(cg.get_cgroup_path(controller='cpuset'), + surfix_vcpu1) + cmd_emulator = 'cat %s' % re.escape(emulator_cpuset_mems_cgroup_path) + cmd_vcpu0 = 'cat %s' % re.escape(vcpu0_cpuset_mems_cgroup_path) + cmd_vcpu1 = 'cat %s' % re.escape(vcpu1_cpuset_mems_cgroup_path) + emulator_cpuset_mems = process.run(cmd_emulator, shell=True).stdout_text.strip() + vcpu0_cpuset_mems = process.run(cmd_vcpu0, shell=True).stdout_text.strip() + vcpu1_cpuset_mems = process.run(cmd_vcpu1, shell=True).stdout_text.strip() + nodeset_memnode = eval(numatest_obj.params['numa_memnode'])[0].get('nodeset') + if (single_host_node == 'yes' and mem_mode in ['strict', 'restrictive'] + and memnode_mode == 'restrictive'): + if (emulator_cpuset_mems != str(all_nodes[0]) or + vcpu1_cpuset_mems != str(all_nodes[0])): + numatest_obj.test.fail("Expect emulator/cpuset.mems and " + "vcpu1/cpuset.mems to be %s, but " + "found %s and %s" % (all_nodes[0], + emulator_cpuset_mems, + vcpu1_cpuset_mems)) + if vcpu0_cpuset_mems != nodeset_memnode: + numatest_obj.test.fail("Expect vcpu0/cpuset.mems to " + "be %s, but found %s" % (nodeset_memnode, + vcpu0_cpuset_mems)) + if mem_mode in ['interleave', 'preferred'] and memnode_mode == 'restrictive': + for item in [emulator_cpuset_mems, vcpu1_cpuset_mems]: + if item != '': + numatest_obj.test.fail("Expect cpuset.mems to be '', " + "but found %s" % item) + if vcpu0_cpuset_mems != nodeset_memnode: + numatest_obj.test.fail("Expect vcpu0/cpuset.mems to be %s, " + "but found %s" % (nodeset_memnode, + vcpu0_cpuset_mems)) + if ((not mem_mode or mem_mode in ['interleave', 'preferred']) and + memnode_mode == 'strict'): + if is_cgroup2: + if any([emulator_cpuset_mems, vcpu0_cpuset_mems, vcpu1_cpuset_mems]): + numatest_obj.test.fail("Expect emulator/cpuset.mems and " + "vcpu0/cpuset.mems and vcpu1/cpuset.mems " + "to be '', but found " + "%s %s %s" % (emulator_cpuset_mems, + vcpu0_cpuset_mems, + vcpu1_cpuset_mems)) + else: + numatest_obj.test.log.debug("emulator_cpuset_mems=%s, " + "vcpu0_cpuset_mems=%s, " + "vcpu1_cpuset_mems=%s", emulator_cpuset_mems, + vcpu0_cpuset_mems, vcpu1_cpuset_mems) + nodeset = libvirt_numa.convert_all_nodes_to_string(all_nodes) + for item in [emulator_cpuset_mems, vcpu0_cpuset_mems, vcpu1_cpuset_mems]: + if item != nodeset: + numatest_obj.test.fail("Expect cpuset.mems to be %s, " + "but found %s" % (nodeset, item)) + if (single_host_node == 'yes' and mem_mode == 'strict' and + memnode_mode != 'restrictive'): + mem_nodeset = numatest_obj.params['nodeset'] + memnode_nodeset = eval(numatest_obj.params['numa_memnode'])[0].get('nodeset') + nodeset = ','.join(sorted(set(mem_nodeset).union(set(memnode_nodeset)))) + nodeset = numa_base.convert_to_string_with_dash(nodeset) + for item in [emulator_cpuset_mems, vcpu0_cpuset_mems, vcpu1_cpuset_mems]: + if item != nodeset: + numatest_obj.test.fail("Expect cpuset.mems to be %s, " + "but found %s" % (nodeset, item)) + if (single_host_node == 'no' and mem_mode == 'strict' and + memnode_mode != 'restrictive'): + nodeset = numa_base.convert_to_string_with_dash(numatest_obj.params['nodeset']) + for item in [emulator_cpuset_mems, vcpu0_cpuset_mems, vcpu1_cpuset_mems]: + if item != nodeset: + numatest_obj.test.fail("Expect cpuset.mems to be %s, " + "but found %s" % (nodeset, item)) + if (single_host_node == 'no' and mem_mode in ['strict', 'restrictive'] and + memnode_mode == 'restrictive'): + nodeset = numa_base.convert_to_string_with_dash(numatest_obj.params['nodeset']) + for item in [emulator_cpuset_mems, vcpu1_cpuset_mems]: + if item != nodeset: + numatest_obj.test.fail("Expect cpuset.mems to be %s, " + "but found %s" % (nodeset, item)) + if vcpu0_cpuset_mems != nodeset_memnode: + numatest_obj.test.fail("Expect vcpu0/cpuset.mems to be %s, but " + "found %s" % (nodeset_memnode, + vcpu0_cpuset_mems)) + numatest_obj.test.log.debug("Step: verify vm cgroup - PASS") + + +def run_default(numatest_obj): + """ + Default run function for the test + + :param numatest_obj: NumaTest object + """ + numatest_obj.test.log.debug("Step: prepare vm xml") + vmxml = prepare_vm_xml(numatest_obj) + numatest_obj.test.log.debug("Step: define vm and check results") + numatest_obj.virsh_dargs.update({'ignore_status': True}) + ret = virsh.define(vmxml.xml, **numatest_obj.virsh_dargs) + err_msg_expected = generate_define_expected_error(numatest_obj) + libvirt.check_result(ret, expected_fails=err_msg_expected) + if err_msg_expected: + return + numatest_obj.test.log.debug("Step: start vm and check results") + ret = virsh.start(numatest_obj.vm.name, **numatest_obj.virsh_dargs) + err_msg_expected = generate_start_expected_error(numatest_obj) + libvirt.check_result(ret, expected_fails=err_msg_expected) + if err_msg_expected: + return + numatest_obj.test.log.debug("After vm is started, vm xml:\n" + "%s", vm_xml.VMXML.new_from_dumpxml(numatest_obj.vm.name)) + vm_session = numatest_obj.vm.wait_for_login() + libvirt_memory.consume_vm_freememory(vm_session) + vm_session.close() + numatest_obj.test.log.debug("Step: consume vm memory - PASS") + check_vm_numa_0_memory_allocation(numatest_obj, numatest_obj.params.get('vm_node0_mem')) + check_vm_numa_1_memory_allocation(numatest_obj, numatest_obj.params.get('vm_node1_mem')) + check_cgroup(numatest_obj) + + +def teardown_default(numatest_obj): + """ + Default teardown function for the test + + :param numatest_obj: NumaTest object + """ + numatest_obj.teardown() + + numatest_obj.test.log.debug("Step: teardown is done") + + +def run(test, params, env): + """ + Test mixed host and guest numa memory binding + """ + libvirt_version.is_libvirt_feature_supported(params) + vm_name = params.get("main_vm") + vm = env.get_vm(vm_name) + numatest_obj = numa_base.NumaTest(vm, params, test) + try: + setup_default(numatest_obj) + run_default(numatest_obj) + finally: + teardown_default(numatest_obj) diff --git a/libvirt/tests/src/numa/guest_numa_node_tuning/memory_binding_setting.py b/libvirt/tests/src/numa/guest_numa_node_tuning/memory_binding_setting.py index 1973261281e..9eccdfe006a 100644 --- a/libvirt/tests/src/numa/guest_numa_node_tuning/memory_binding_setting.py +++ b/libvirt/tests/src/numa/guest_numa_node_tuning/memory_binding_setting.py @@ -7,18 +7,20 @@ # # Author: Dan Zheng # +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ import os import re -import platform +from avocado.utils import memory from avocado.utils import process from virttest import libvirt_cgroup from virttest import libvirt_version -from virttest import virsh from virttest import test_setup +from virttest import utils_libvirtd +from virttest import virsh from virttest.libvirt_xml import vm_xml from virttest.utils_test import libvirt from virttest.utils_libvirt import libvirt_numa @@ -34,12 +36,16 @@ def setup_default(test_obj): """ test_obj.setup() if test_obj.params.get('memory_backing'): + numa_base.adjust_parameters(test_obj.params, + hugepage_mem=int(test_obj.params.get("hugepage_mem"))) expected_hugepage_size = test_obj.params.get('expected_hugepage_size') hpc = test_setup.HugePageConfig(test_obj.params) all_nodes = test_obj.online_nodes_withmem target_hugepages = test_obj.params.get('target_hugepages') hpc.set_node_num_huge_pages(target_hugepages, all_nodes[0], expected_hugepage_size) hpc.set_node_num_huge_pages(target_hugepages, all_nodes[1], expected_hugepage_size) + hpc.mount_hugepage_fs() + utils_libvirtd.Libvirtd().restart() test_obj.test.log.debug("Get first node hugepage is " "%d", hpc.get_node_num_huge_pages(all_nodes[0], expected_hugepage_size)) @@ -101,9 +107,8 @@ def verify_host_numa_memory_allocation(test_obj): has_huge = True if re.search('huge', out_numa_maps) else False N0_value = re.findall('N%s=(\d+)' % all_nodes[0], out_numa_maps) N1_value = re.findall('N%s=(\d+)' % all_nodes[1], out_numa_maps) - default_pagesize = test_obj.params.get('default_pagesize') expected_hugepage_size = test_obj.params.get('expected_hugepage_size') - psize = expected_hugepage_size if memory_backing else default_pagesize + psize = expected_hugepage_size if memory_backing else memory.get_page_size() // 1024 has_kernelpage = True if re.search('kernelpagesize_kB=%s' % psize, out_numa_maps) else False def _check_values(expect_huge, expect_N0, expect_N1, expect_sum=None): @@ -152,20 +157,14 @@ def _check_values(expect_huge, expect_N0, expect_N1, expect_sum=None): mem_mode == 'prefered' and not single_host_node) or \ (mem_mode in ['interleave', 'preferred'] and single_host_node): - if platform.machine() == 'aarch64': - _check_values(True, 3, 1) - else: - _check_values(True, 512, 500) + hpc = test_setup.HugePageConfig(test_obj.params) + N0_expect = hpc.get_node_num_huge_pages(all_nodes[0], expected_hugepage_size) + _check_values(True, N0_expect, int(mem_size/psize)-N0_expect) elif not single_host_node and mem_mode == 'interleave': - if platform.machine() == 'aarch64': - _check_values(True, 2, 2) - else: - _check_values(True, 506, 506) + avg_value = int(mem_size/psize/2) + _check_values(True, avg_value, avg_value) elif not single_host_node and mem_mode in ['strict', 'restrictive']: - if platform.machine() == 'aarch64': - _check_values(True, 0, 0, 4) - else: - _check_values(True, 0, 0, 1012) + _check_values(True, 0, 0, int(mem_size/psize)) test_obj.test.log.debug("Step: verify host numa node memory allocation PASS") @@ -177,7 +176,7 @@ def verify_cgroup(test_obj): """ mem_mode = test_obj.params.get('mem_mode') nodeset = numa_base.convert_to_string_with_dash(test_obj.params.get('nodeset')) - online_nodes = libvirt_numa.parse_numa_nodeset_to_str('x-y', test_obj.online_nodes) + online_nodes = libvirt_numa.convert_all_nodes_to_string(test_obj.online_nodes) vm_pid = test_obj.vm.get_pid() cg = libvirt_cgroup.CgroupTest(vm_pid) surfix = 'emulator/cpuset.mems' if cg.is_cgroup_v2_enabled() else 'cpuset.mems' diff --git a/libvirt/tests/src/numa/guest_numa_node_tuning/memory_binding_with_emulator_thread.py b/libvirt/tests/src/numa/guest_numa_node_tuning/memory_binding_with_emulator_thread.py index 915c6a27ffd..b97efea87ff 100644 --- a/libvirt/tests/src/numa/guest_numa_node_tuning/memory_binding_with_emulator_thread.py +++ b/libvirt/tests/src/numa/guest_numa_node_tuning/memory_binding_with_emulator_thread.py @@ -26,12 +26,15 @@ def setup_default(test_obj): :param test_obj: NumaTest object """ - test_obj.setup(node_index=1) + test_obj.setup() if test_obj.params.get('memory_backing'): + numa_base.adjust_parameters(test_obj.params, + node_index='1', + hugepage_mem=int(test_obj.params.get("hugepage_mem"))) hpc = test_setup.HugePageConfig(test_obj.params) hpc.setup() utils_libvirtd.Libvirtd().restart() - test_obj.params['hp_config_2M'] = hpc + test_obj.params['hpc_list'] = [hpc] test_obj.test.log.debug("Step: setup is done") diff --git a/libvirt/tests/src/numa/guest_numa_node_tuning/numa_mem_binding_with_offline_cpu.py b/libvirt/tests/src/numa/guest_numa_node_tuning/numa_mem_binding_with_offline_cpu.py index 6d3c067422a..8306c939c72 100644 --- a/libvirt/tests/src/numa/guest_numa_node_tuning/numa_mem_binding_with_offline_cpu.py +++ b/libvirt/tests/src/numa/guest_numa_node_tuning/numa_mem_binding_with_offline_cpu.py @@ -44,6 +44,10 @@ def setup_test(): online_nodes = numa_info.get_online_nodes_withmem() test.log.debug("Get online node with memory:%s", online_nodes) + if len(online_nodes) < 2: + test.cancel("Expect %d numa nodes at " + "least, but found %d" % (2, + len(online_nodes))) node_cpus = numa_info.get_all_node_cpus()[ online_nodes[offline_node_index]].strip().split(' ') diff --git a/libvirt/tests/src/numa/guest_numa_node_tuning/specific_numa_memory_bind_hugepage.py b/libvirt/tests/src/numa/guest_numa_node_tuning/specific_numa_memory_bind_hugepage.py index 5bc9b2dafd8..080d81bf645 100644 --- a/libvirt/tests/src/numa/guest_numa_node_tuning/specific_numa_memory_bind_hugepage.py +++ b/libvirt/tests/src/numa/guest_numa_node_tuning/specific_numa_memory_bind_hugepage.py @@ -25,11 +25,15 @@ def setup_default(test_obj): :param test_obj: NumaTest object """ test_obj.setup() + numa_base.adjust_parameters(test_obj.params, + hugepage_mem=int(test_obj.params.get("hugepage_mem"))) hpc = test_setup.HugePageConfig(test_obj.params) hpc.setup() utils_libvirtd.Libvirtd().restart() - test_obj.params['hp_config_2M'] = hpc + test_obj.params['hpc_list'] = [hpc] test_obj.test.log.debug("Step: setup is done") + test_obj.test.log.debug("Host memory page status is:\n%s" + % virsh.freepages(options='--all').stdout_text) def prepare_vm_xml(test_obj): diff --git a/libvirt/tests/src/numa/guest_numa_topology/change_vcpu_pin.py b/libvirt/tests/src/numa/guest_numa_topology/change_vcpu_pin.py index a001bf9d750..46f674cce9e 100644 --- a/libvirt/tests/src/numa/guest_numa_topology/change_vcpu_pin.py +++ b/libvirt/tests/src/numa/guest_numa_topology/change_vcpu_pin.py @@ -160,7 +160,10 @@ def run_default(test_obj): test_obj.vm.wait_for_login().close() online_cpus = cpuutils.online_list() host_online_cpu_num = len(online_cpus) - verify_vcpuinfo(test_obj, online_cpus, host_online_cpu_num) + # For vcpuinfo would be impacted by numad changing cpu affinity of guest process, + # so we skip testing the numad impact. + if test_obj.params.get('numad_active') == 'no': + verify_vcpuinfo(test_obj, online_cpus, host_online_cpu_num) verify_vcpupin(test_obj, online_cpus, host_online_cpu_num) @@ -171,9 +174,10 @@ def teardown_default(test_obj): :param test_obj: NumaTest object """ test_obj.teardown() - backup_numad_status = test_obj.params['backup_numad_status'] - libvirt_service.ensure_service_status('numad', - expect_active=backup_numad_status) + backup_numad_status = test_obj.params.get("backup_numad_status") + if backup_numad_status: + libvirt_service.ensure_service_status('numad', + expect_active=backup_numad_status) test_obj.test.log.info("Step: teardown is done") diff --git a/libvirt/tests/src/numa/guest_numa_topology/numa_topology_with_cpu_topology.py b/libvirt/tests/src/numa/guest_numa_topology/numa_topology_with_cpu_topology.py index 5881dcc4578..2221d9180ac 100644 --- a/libvirt/tests/src/numa/guest_numa_topology/numa_topology_with_cpu_topology.py +++ b/libvirt/tests/src/numa/guest_numa_topology/numa_topology_with_cpu_topology.py @@ -37,9 +37,9 @@ def prepare_vm_xml(test_obj): cpu_topology = eval(test_obj.params.get('cpu_topology', '{}')) vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(test_obj.vm.name) if numa_cells: - if vmxml.xmltreefile.find('cpu'): + if vmxml.xmltreefile.find('cpu') is not None: cpuxml = vmxml.cpu - if cpuxml.xmltreefile.find('topology'): + if cpuxml.xmltreefile.find('topology') is not None: del cpuxml.topology else: cpuxml = vm_xml.VMCPUXML() @@ -51,30 +51,21 @@ def prepare_vm_xml(test_obj): return vmxml -def verify_vm_cpu_info(vm_session, test_obj, cpu_info_type, cmd): +def verify_vm_cpu_info(test_obj): """ Verify vm's cpu information - :param vm_session: vm session :param test_obj: NumaTest object - :param cpu_info_type: str, specified cpu info type, like 'cores', 'threads' - :param cmd: str, the command used to check the cpu info """ - status, output = vm_session.cmd_status_output(cmd, timeout=300) - if status: - test_obj.test.error("Can't get cpu info with command '%s'" % cmd) - cpu_info = eval(test_obj.params.get('cpu_topology'))[cpu_info_type] - if cpu_info_type == 'cores': - dies = eval(test_obj.params.get('cpu_topology'))['dies'] - cpu_info = str(int(cpu_info) * int(dies)) - if cpu_info != output.strip(): - test_obj.test.fail('Guest cpu %s is expected ' - 'to be %s, but found %s' % (cpu_info_type, - cpu_info, - output.strip())) - else: - test_obj.test.log.debug("Step: check vm cpu %s " - "to be '%s': PASS", cpu_info_type, cpu_info) + vm_topology = test_obj.vm.get_cpu_topology_in_vm() + expect_topology = eval(test_obj.params.get('cpu_topology')) + expect_topology['cores'] = str(int(expect_topology['cores']) * int(expect_topology['dies'])) + for key in expect_topology: + if expect_topology[key] != vm_topology[key]: + test_obj.test.fail('Guest cpu %s is expected ' + 'to be %s, but found %s' % (key, + expect_topology[key], + vm_topology[key])) def verify_vm_numa_node(vm_session, test_obj): @@ -163,12 +154,7 @@ def run_default(test_obj): test_obj.test.log.debug("After vm is started, vm xml:\n" "%s", vm_xml.VMXML.new_from_dumpxml(test_obj.vm.name)) vm_session = test_obj.vm.wait_for_login() - cmds = {'sockets': 'cat /proc/cpuinfo|grep "physical id"|sort -u|wc -l', - 'cores': 'cat /proc/cpuinfo|grep "core id"|sort|uniq|wc -l', - 'dies': 'cat /sys/devices/system/cpu/cpu*/topology/die_id|sort|uniq|wc -l', - 'threads': 'lscpu|grep Thread|cut -d":" -f2'} - for cpu_info_type, cpu_cmd in cmds.items(): - verify_vm_cpu_info(vm_session, test_obj, cpu_info_type, cpu_cmd) + verify_vm_cpu_info(test_obj) verify_vm_numa_node(vm_session, test_obj) verify_dmesg_vm_numa_mem(vm_session, test_obj) diff --git a/libvirt/tests/src/numa/guest_numa_topology/numa_topology_with_hugepage.py b/libvirt/tests/src/numa/guest_numa_topology/numa_topology_with_hugepage.py index 6de74855a33..64b72c575ff 100644 --- a/libvirt/tests/src/numa/guest_numa_topology/numa_topology_with_hugepage.py +++ b/libvirt/tests/src/numa/guest_numa_topology/numa_topology_with_hugepage.py @@ -10,6 +10,7 @@ import re +from avocado.utils import memory from avocado.utils import process from virttest import utils_libvirtd @@ -39,23 +40,30 @@ def setup_default(test_obj): :param test_obj: NumaTest object """ + memory_backing = eval(test_obj.params.get('memory_backing', '{}')) + if memory_backing: + numa_base.check_hugepage_availability(memory_backing["hugepages"]["pages"]) test_obj.setup() - params_2M = {'hugepage_size': '2048', - 'vm_hugepage_mountpoint': test_obj.params.get('hugepage_path_2M'), - 'target_hugepages': test_obj.params.get('target_hugepages_2M')} - params_1G = {'hugepage_size': '1048576', - 'vm_hugepage_mountpoint': test_obj.params.get('hugepage_path_1G'), - 'target_hugepages': test_obj.params.get('target_hugepages_1G'), - 'kernel_hp_file': '/sys/kernel/mm/hugepages/hugepages-1048576kB/nr_hugepages'} hp_size = test_obj.params.get('hp_size') - if hp_size in ['2M', '2M_1G', 'scarce_mem']: - test_obj.params.update(params_2M) - hpconfig_2M = setup_hugepage(test_obj.params) - test_obj.params['hp_config_2M'] = hpconfig_2M - if hp_size in ['1G', '2M_1G']: - test_obj.params.update(params_1G) - hpconfig_1G = setup_hugepage(test_obj.params) - test_obj.params['hp_config_1G'] = hpconfig_1G + hpc_list = [] + if hp_size in ['default_hugepage', 'scarce_mem']: + numa_base.adjust_parameters(test_obj.params, + hugepage_mem=int(test_obj.params.get('hugepage_mem'))) + hpconfig = setup_hugepage(test_obj.params) + hpc_list.append(hpconfig) + mapping_hp_kib = {'2M': 2048, '512M': 524288, '1G': 1048576} + for pg_size in ['2M', '512M', '1G']: + if hp_size.count(pg_size): + hugepage_size = mapping_hp_kib[pg_size] + hugepage_mem_by_size = eval(test_obj.params.get("hugepage_mem_by_size")) + new_params = test_obj.params.copy() + numa_base.adjust_parameters(new_params, + hugepage_size=hugepage_size, + hugepage_mem=hugepage_mem_by_size[hugepage_size]) + hpconfig = setup_hugepage(new_params) + hpc_list.append(hpconfig) + test_obj.params[pg_size] = new_params + test_obj.params['hpc_list'] = hpc_list utils_libvirtd.Libvirtd().restart() test_obj.test.log.debug("Step: setup is done") @@ -74,21 +82,6 @@ def prepare_vm_xml(test_obj): return vmxml -def produce_expected_error(test_obj): - """ - produce the expected error message - - :param test_obj: NumaTest object - - :return: str, error message to be checked - """ - hugepage_size = test_obj.params.get('hp_size') - err_msg = "" - if hugepage_size == 'scarce_mem': - err_msg = "unable to map backing store for guest RAM: Cannot allocate memory" - return err_msg - - def verify_hugepage_memory_in_numa_maps(test_obj): """ Verify hugepage memory in numa_maps is correct @@ -110,15 +103,26 @@ def _check_numa_maps(mem_size, hugepage_num, pagesize): "numa_maps output '%s'" % (pat, out_numa_maps)) hp_size = test_obj.params.get('hp_size') - if hp_size in ['2M', '2M_1G']: + params_2M = test_obj.params.get('2M') + params_512M = test_obj.params.get('512M') + params_1G = test_obj.params.get('1G') + if hp_size in ['default_hugepage']: _check_numa_maps(test_obj.params.get('vm_numa_node0_mem'), - test_obj.params.get('target_hugepages_2M'), '2048') - if hp_size == '1G': + test_obj.params.get('target_hugepages'), str(memory.get_huge_page_size())) + if hp_size in ['512M_2M']: _check_numa_maps(test_obj.params.get('vm_numa_node0_mem'), - test_obj.params.get('target_hugepages_1G'), '1048576') - if hp_size == '2M_1G': + params_512M.get('target_hugepages'), '524288') _check_numa_maps(test_obj.params.get('vm_numa_node1_mem'), - test_obj.params.get('target_hugepages_1G'), '1048576') + params_2M.get('target_hugepages'), '2048') + if hp_size in ['2M_1G']: + _check_numa_maps(test_obj.params.get('vm_numa_node0_mem'), + params_2M.get('target_hugepages'), '2048') + _check_numa_maps(test_obj.params.get('vm_numa_node1_mem'), + params_1G.get('target_hugepages'), '1048576') + if hp_size == '1G': + _check_numa_maps(test_obj.params.get('vm_numa_node0_mem'), + params_1G.get('target_hugepages'), '1048576') + test_obj.test.log.debug("Step: verify hugepage memory in numa_maps: PASS") @@ -130,14 +134,23 @@ def check_qemu_cmdline(test_obj): """ pat_in_qemu_cmdline = test_obj.params.get('pat_in_qemu_cmdline') hp_size = test_obj.params.get('hp_size') - hugepage_path_1G = test_obj.params.get('hugepage_path_1G') - hugepage_path_2M = test_obj.params.get('hugepage_path_2M') - node0_mem_path = '%s/libvirt/qemu/.*' % hugepage_path_2M \ - if hp_size in ['2M', '2M_1G'] else '%s/libvirt/qemu/.*' % hugepage_path_1G + params_2M = test_obj.params.get('2M') + params_512M = test_obj.params.get('512M') + params_1G = test_obj.params.get('1G') + node1_mem_path = '' + if hp_size == 'default_hugepage': + node0_mem_path = '%s/libvirt/qemu/.*' % test_obj.params['vm_hugepage_mountpoint'] + elif hp_size == '512M_2M': + node0_mem_path = '%s/libvirt/qemu/.*' % params_512M.get('vm_hugepage_mountpoint') + node1_mem_path = '"mem-path":"%s/libvirt/qemu/.*",' % params_2M.get('vm_hugepage_mountpoint') + elif hp_size == '2M_1G': + node0_mem_path = '%s/libvirt/qemu/.*' % params_2M.get('vm_hugepage_mountpoint') + node1_mem_path = '"mem-path":"%s/libvirt/qemu/.*",' % params_1G.get('vm_hugepage_mountpoint') + elif hp_size == '1G': + node0_mem_path = '%s/libvirt/qemu/.*' % params_1G.get('vm_hugepage_mountpoint') + node0_mem_size = int(test_obj.params.get('vm_numa_node0_mem')) * 1024 - node1_mem_path = '"mem-path":"%s/libvirt/qemu/.*",' % hugepage_path_1G \ - if hp_size == '2M_1G' else '' - node1_prealloc = '"prealloc":true,' if hp_size == '2M_1G' else '' + node1_prealloc = '"prealloc":true,' if hp_size == '2M_1G' or hp_size == '512M_2M' else '' node1_mem_size = int(test_obj.params.get('vm_numa_node1_mem')) * 1024 pat_in_qemu_cmdline = pat_in_qemu_cmdline % (node0_mem_path, node0_mem_size, @@ -163,7 +176,7 @@ def run_default(test_obj): test_obj.test.log.debug("Step: start vm and check results") test_obj.virsh_dargs.update({'ignore_status': True}) ret = virsh.start(test_obj.vm.name, **test_obj.virsh_dargs) - err_msg_expected = produce_expected_error(test_obj) + err_msg_expected = test_obj.params.get("err_msg") libvirt.check_result(ret, expected_fails=err_msg_expected) if err_msg_expected: return @@ -181,11 +194,6 @@ def teardown_default(test_obj): :param test_obj: NumaTest object """ test_obj.teardown() - hpconfig_2M = test_obj.params.get('hp_config_2M') - hpconfig_1G = test_obj.params.get('hp_config_1G') - for hpconfig in [hpconfig_2M, hpconfig_1G]: - if hpconfig: - hpconfig.cleanup() test_obj.test.log.debug("Step: hugepage is deallocated") test_obj.test.log.debug("Step: teardown is done") @@ -197,6 +205,7 @@ def run(test, params, env): vm_name = params.get("main_vm") vm = env.get_vm(vm_name) numatest_obj = numa_base.NumaTest(vm, params, test) + try: setup_default(numatest_obj) run_default(numatest_obj) diff --git a/libvirt/tests/src/numa/guest_numa_topology/various_numa_topology_settings.py b/libvirt/tests/src/numa/guest_numa_topology/various_numa_topology_settings.py index d22c42a0ad6..b6510c17225 100644 --- a/libvirt/tests/src/numa/guest_numa_topology/various_numa_topology_settings.py +++ b/libvirt/tests/src/numa/guest_numa_topology/various_numa_topology_settings.py @@ -27,6 +27,16 @@ def setup_default(test_obj): """ test_obj.setup() hpc = test_setup.HugePageConfig(test_obj.params) + + numa_cells = eval(test_obj.params.get('numa_cells', '[]')) + if numa_cells: + #set target_hugepages according to the setting of 'numa_cells'. + total_mem = 0 + for i in range(len(numa_cells)): + total_mem += int(numa_cells[i]['memory']) + test_obj.params["target_hugepages"] = int(total_mem/hpc.get_hugepage_size()) + hpc = test_setup.HugePageConfig(test_obj.params) + hpc.setup() test_obj.params['hp_config_obj'] = hpc test_obj.test.log.debug("Step: setup is done") @@ -162,7 +172,8 @@ def teardown_default(test_obj): """ test_obj.teardown() hpc = test_obj.params.get('hp_config_obj') - hpc.cleanup() + if hpc: + hpc.cleanup() test_obj.test.log.debug("Step: teardown is done") diff --git a/libvirt/tests/src/numa/host_numa/host_numa_info.py b/libvirt/tests/src/numa/host_numa/host_numa_info.py new file mode 100644 index 00000000000..c1ee2c0e9ad --- /dev/null +++ b/libvirt/tests/src/numa/host_numa/host_numa_info.py @@ -0,0 +1,397 @@ +import platform +import re + +from avocado.utils import memory as mem_utils + +from virttest import test_setup +from virttest import virsh +from virttest.libvirt_xml import capability_xml +from virttest.staging import utils_memory +from virttest.utils_misc import NumaNode + +from provider.numa import numa_base + + +def setup_default(test_obj): + """ + Default setup function for the test + + :param test_obj: NumaTest object + """ + expect_nodes_num = test_obj.params.get("expect_nodes_num", 2) + test_obj.params['expect_nodes_num'] = int(expect_nodes_num) + test_obj.setup(expect_nodes_num=int(expect_nodes_num)) + test_obj.test.log.debug("Step: setup is done") + + +def allocate_memory_on_host_nodes(test_obj): + """ + Allocate hugepage on all host nodes with memory + + :param test_obj: NumaTest object + :return: dict, allocated info, + like {'2048': '100', '1048576': '1'} + """ + def _allocate_test(page_num, node_id, page_size): + # Drop caches to clean some usable memory + with open("/proc/sys/vm/drop_caches", "w") as caches: + caches.write('3') + # Compact memory to get more continual memory + with open("/proc/sys/vm/compact_memory", "w") as memory: + memory.write('1') + hpc.set_node_num_huge_pages(page_num, node_id, page_size, ignore_error=True) + return hpc.get_node_num_huge_pages(node_id, page_size) + + ret = {} + sum_page_num = {} + all_nodes = test_obj.online_nodes_withmem + allocate_dict = eval(test_obj.params.get('allocate_dict')) + hpc = test_setup.HugePageConfig(test_obj.params) + pagesize_list = list(allocate_dict.keys()) + pagesize_list.sort(reverse=True) + for one_node in all_nodes: + allocated_info = {} + for pagesize in pagesize_list: + test_obj.test.log.debug("To allocate %s %s pages on node %s", allocate_dict[pagesize], pagesize, one_node) + allocated_num = _allocate_test(allocate_dict[pagesize], one_node, pagesize) + allocated_info.update({pagesize: allocated_num}) + sum_page_num[pagesize] = sum_page_num[pagesize] + allocated_num if sum_page_num.get(pagesize) else allocated_num + ret.update({one_node: allocated_info}) + test_obj.test.log.debug("Get allocated information for node %s: '%s'", one_node, allocated_info) + test_obj.test.log.debug("Get allocated information '%s'", ret) + if not all(sum_page_num.values()): + test_obj.test.cancel("At least one page size memory could not be allocated") + test_obj.params['allocate_result'] = ret + return ret + + +def verify_node_mem_by_capabilities(test_obj): + """ + Verify node memory by virsh capabilities + + :param test_obj: NumaTest object + :param capa_xml: CapabilityXML object + """ + def _check_cpu_pages(): + """ + Check pages information under + """ + pages_list = capa_xml.cpu_pages + not_match = [one_page['size'] for one_page in pages_list + if int(one_page['size']) not in supported_page_size_list] + if not_match: + test_obj.test.fail("The page size %s shown in virsh capabilities " + "do not exist in system " + "support list '%s'" % (not_match, + supported_page_size_list)) + + def _check_topo_cell(): + """ + Check memory, pages size and pages num under + """ + topo_xml = capa_xml.cells_topology + cells = topo_xml.get_cell(withmem=True) + for one_cell in cells: + total_mem = utils_memory.memtotal(node_id=one_cell.cell_id) + if one_cell.memory != total_mem: + test_obj.test.fail("Expect node memory '%s', " + "but found '%s'" % (total_mem, + one_cell.memory)) + pages_list = one_cell.pages + total_hugepage_mem = 0 + actual_default_page_num = None + for one_page in pages_list: + page_size = int(one_page.fetch_attrs()['size']) + page_num = int(one_page.fetch_attrs()['pages']) + test_obj.test.log.debug("allocate_result=%s", allocate_result) + test_obj.test.log.debug("one_page.fetch_attrs()=%s", one_page.fetch_attrs()) + if page_size != default_page_size: + pg_num = allocate_result[int(one_cell.cell_id)].get(page_size) + if pg_num is not None and pg_num != page_num: + test_obj.test.fail("Expect %s pages " + "with page size '%s', but " + "found %s" % (pg_num, + page_size, + page_num)) + total_hugepage_mem += int(page_size) * page_num + else: + actual_default_page_num = page_num + expect_default_page_num = (total_mem - total_hugepage_mem)//default_page_size + if expect_default_page_num != int(actual_default_page_num): + test_obj.test.fail("Expect %s pages with default " + "pagesize '%s', but " + "found '%s'" % (expect_default_page_num, + default_page_size, + actual_default_page_num)) + + supported_page_size_list = test_obj.params['supported_page_size_list'] + default_page_size = test_obj.params['default_page_size'] + allocate_result = test_obj.params['allocate_result'] + capa_xml = capability_xml.CapabilityXML() + _check_cpu_pages() + _check_topo_cell() + test_obj.test.log.debug("Verify memory value of each node " + "by virsh capabilities - PASS") + + +def common_test_freepages(test_obj, node_id, page_size, page_num, size_unit=''): + """ + Common function to check freepages + + :param test_obj: NumaTest object + :param node_id: str, host numa node id + :param page_size: str, hugepage size in KiB + :param page_num: str, page number + :param size_unit: str, page size unit, like KiB, M, G + """ + ret = virsh.freepages(cellno=node_id, + pagesize=page_size, + sizeunit=size_unit, + **test_obj.virsh_dargs).stdout_text.strip() + if size_unit == 'M': + page_size = page_size * 1024 + elif size_unit == 'G': + page_size = page_size * 1024 * 1024 + search_pattern = "%dKiB:\s+%s" % (page_size, page_num) + match = re.findall(search_pattern, ret) + if not match: + test_obj.test.error("Can not find '%s' in %s" % (search_pattern, ret)) + else: + test_obj.test.log.debug("Got match '%s' " + "for %s", match[0], search_pattern) + + +def verify_node_mem_by_freepages_all(test_obj): + """ + Verify node memory by virsh freepages --all + + :param test_obj: NumaTest object + """ + allocate_result = test_obj.params['allocate_result'] + output = virsh.freepages(options='--all', **test_obj.virsh_dargs).stdout_text.strip() + default_page_size = test_obj.params['default_page_size'] + all_freepages = {} + cell_freepages = {} + output += "\n\n" + node = None + for line in output.splitlines(): + if line: + key, value = line.split(":") + key = re.findall(r"(\d+)", key)[0] + if "Node" in line: + node = int(key) + else: + # Ignore to compare the default page size information + # because it changes all the time + if int(key) == default_page_size: + continue + else: + cell_freepages[int(key)] = int(value.strip()) + else: + all_freepages.update({node: cell_freepages}) + cell_freepages = {} + + test_obj.test.log.debug("Parsed all freepages " + "in 'virsh freepages --all': %s", all_freepages) + for node in all_freepages.keys(): + page_info = all_freepages[node] + for pgsize, pgnum in page_info.items(): + test_obj.test.log.debug("node %d, pgsize %d, pgnum %d", node, pgsize, pgnum) + if allocate_result.get(node): + if allocate_result[node].get(pgsize) is not None and pgnum != allocate_result[node][pgsize]: + test_obj.test.fail("Expect freepages " + "result has '%d' pages " + "for size '%d' on node %d, but " + "found '%d'" % (allocate_result[node][pgsize], + pgsize, node, pgnum)) + elif allocate_result[node].get(pgsize) is None and pgnum != 0: + test_obj.test.fail("Expect freepages " + "result has 0 page " + "for size '%d' on node %d, but " + "found '%d'" % (pgsize, node, pgnum)) + test_obj.test.log.debug("Verify node memory by freepages with --all - PASS") + + +def verify_node_mem_by_freepages(test_obj): + """ + Verify node memory by virsh freepages without options + + :param test_obj: NumaTest object + """ + allocate_result = test_obj.params['allocate_result'] + all_nodes = test_obj.online_nodes_withmem + for one_node in all_nodes: + for pgsize in allocate_result[one_node].keys(): + common_test_freepages(test_obj, + one_node, + pgsize, + allocate_result[one_node][pgsize]) + test_obj.test.log.debug("Verify huge page memory info on " + "each host numa node - PASS") + + +def verify_node_mem_by_freepages_various_unit(test_obj): + """ + Verify node memory by virsh freepages with different size units + + :param test_obj: NumaTest object + """ + allocate_result = test_obj.params['allocate_result'] + all_nodes = test_obj.online_nodes_withmem + if test_obj.params['expect_nodes_num'] == 1: + target_node = all_nodes[0] + else: + target_node = all_nodes[1] + for pgsize in allocate_result[target_node].keys(): + common_test_freepages(test_obj, + target_node, + pgsize, allocate_result[target_node][pgsize]) + common_test_freepages(test_obj, + target_node, + pgsize, + allocate_result[target_node][pgsize], + size_unit='KiB') + if int(pgsize) >= 1024: + common_test_freepages(test_obj, + target_node, + int(pgsize)//1024, + allocate_result[target_node][pgsize], + size_unit='M') + if int(pgsize) >= (1024*1024): + common_test_freepages(test_obj, + target_node, + int(pgsize)//(1024*1024), + allocate_result[target_node][pgsize], + size_unit='G') + test_obj.test.log.debug("Verify huge page memory info on " + "the first host numa node with different " + "page size unit - PASS") + + +def verify_node_distance_by_capabilities(test_obj): + """ + Verify node distance by virsh capabilities + + :param test_obj: NumaTest object + """ + topo_xml = capability_xml.CapabilityXML().cells_topology + cells = topo_xml.get_cell(withmem=True) + for one_cell in cells: + siblings = [sibling['value'] for sibling in one_cell.sibling] + distances = test_obj.host_numa_info.get_node_distance(one_cell.cell_id) + if siblings != distances: + test_obj.test.fail("For node '%s', " + "expect the distances to " + "be '%s', but " + "found '%s'" % (one_cell.cell_id, + distances, + siblings)) + test_obj.test.log.debug("Verify node distance by " + "capabilities - PASS") + + +def verify_node_cpus_by_capabilities(test_obj): + """ + Verify node cpus by virsh capabilities + + :param test_obj: NumaTest object + """ + topo_xml = capability_xml.CapabilityXML().cells_topology + cells = topo_xml.get_cell(withmem=True) + node_cpus = test_obj.host_numa_info.online_nodes_cpus + for one_cell in cells: + expect_cpu_num = len(node_cpus[int(one_cell.cell_id)].strip().split()) + if int(one_cell.cpus_num) != expect_cpu_num: + test_obj.test.fail("For node '%s', expect " + "cpus number to be '%s', " + "but found '%s'" % (one_cell.cell_id, + expect_cpu_num, + one_cell.cpus_num)) + if len(one_cell.cpu) != expect_cpu_num: + test_obj.test.fail("for node '%s', expect " + "cpu flag number to be '%s', " + "but found '%s'" % (one_cell.cell_id, + expect_cpu_num, + len(one_cell.cpu))) + verify_node_cpus_under_cell(test_obj, one_cell.cpu, one_cell.cell_id) + + test_obj.test.log.debug("Verify node cpus by capabilities - PASS") + + +def verify_node_cpus_under_cell(test_obj, cpu_list, node_id): + """ + Verify node cpus under in virsh capabilities + + :param test_obj: NumaTest object + :param cpu_list: list, cpu list under + :param node_id: str, host numa node id + """ + one_numa_node = NumaNode(int(node_id) + 1) + for one_cpu_dict in cpu_list: + cpu_info_in_sys = one_numa_node.get_cpu_topology(one_cpu_dict['id']) + if not set(one_cpu_dict.items()).issubset(cpu_info_in_sys.items()): + test_obj.test.fail("Expect cpu '%s' in node '%s' " + "to be included in '%s', but found " + "'%s'" % (one_cpu_dict['id'], + node_id, + cpu_info_in_sys, + one_cpu_dict)) + test_obj.test.log.debug("Verify node cpus under cell - PASS") + + +def run_default(test_obj): + """ + Default run function for the test + + :param test_obj: NumaTest object + """ + supported_hugepage_sizes = mem_utils.get_supported_huge_pages_size() + default_page_size = mem_utils.get_page_size()//1024 + supported_page_size_list = supported_hugepage_sizes + [default_page_size] + test_obj.params['default_page_size'] = default_page_size + test_obj.params['supported_page_size_list'] = supported_page_size_list + + allocate_memory_on_host_nodes(test_obj) + verify_node_mem_by_capabilities(test_obj) + verify_node_mem_by_freepages_all(test_obj) + verify_node_mem_by_freepages(test_obj) + verify_node_mem_by_freepages_various_unit(test_obj) + verify_node_distance_by_capabilities(test_obj) + if 'aarch64' not in platform.machine().lower(): + verify_node_cpus_by_capabilities(test_obj) + + +def teardown_default(test_obj): + """ + Default teardown function for the test + + :param test_obj: NumaTest object + """ + test_obj.teardown() + + allocate_dict = eval(test_obj.params.get('allocate_dict')) + hpc = test_setup.HugePageConfig(test_obj.params) + for one_psize in allocate_dict.keys(): + hpc.set_kernel_hugepages(one_psize, 0) + + test_obj.test.log.debug("Step: teardown is done") + + +def run(test, params, env): + """ + Test numa topology together with cpu topology + """ + default_pagesize = int(params.get("default_pagesize")) * 1024 + default_kernel_pagesize = mem_utils.get_page_size() + if default_pagesize != default_kernel_pagesize: + test.cancel("The case does not support on " + "current host kernel " + "size %d" % default_kernel_pagesize) + vm_name = params.get("main_vm") + vm = env.get_vm(vm_name) + numatest_obj = numa_base.NumaTest(vm, params, test) + try: + setup_default(numatest_obj) + run_default(numatest_obj) + finally: + teardown_default(numatest_obj) diff --git a/libvirt/tests/src/numa/numa_capabilities.py b/libvirt/tests/src/numa/numa_capabilities.py index 5a8cd83cabe..942e3d2e0d4 100644 --- a/libvirt/tests/src/numa/numa_capabilities.py +++ b/libvirt/tests/src/numa/numa_capabilities.py @@ -14,6 +14,7 @@ def run(test, params, env): """ Test capabilities with host numa node topology """ + missing_cpu_topology_key = params.get("missing_cpu_topology_key") libvirtd = utils_libvirtd.Libvirtd() libvirtd.start() try: @@ -49,11 +50,16 @@ def run(test, params, env): cpu_topo_list = [] for cpu_id in cpu_list: cpu_dict = node_.get_cpu_topology(cpu_id) + # if specific cpu topology file from sysfs doesn't exist, default 0 + # would be used in virsh capabilities + if missing_cpu_topology_key and cpu_dict[missing_cpu_topology_key] is None: + cpu_dict[missing_cpu_topology_key] = '0' cpu_topo_list.append(cpu_dict) logging.debug("cpu topology list from capabilities xml is %s", cpu_list_from_xml) - if cpu_list_from_xml != cpu_topo_list: - test.fail("cpu list %s from capabilities xml not " - "expected.") + for i, cpu_dict in enumerate(cpu_list_from_xml): + if not set(cpu_dict.items()).issubset(set(cpu_topo_list[i].items())): + test.fail("cpu list %s from capabilities xml is not subset from " + "system %s" % (cpu_list_from_xml, cpu_topo_list)) finally: libvirtd.restart() diff --git a/libvirt/tests/src/numa/numa_config_with_auto_placement.py b/libvirt/tests/src/numa/numa_config_with_auto_placement.py index 468566154e4..b7d8f795880 100644 --- a/libvirt/tests/src/numa/numa_config_with_auto_placement.py +++ b/libvirt/tests/src/numa/numa_config_with_auto_placement.py @@ -159,51 +159,31 @@ def check_iothreadinfo(vm_name, cpu_range, config=''): :param cpu_range: range of CPUs available as a string :param config: config parameter as a string, empty by default """ - numa_info = utils_misc.NumaInfo() result = virsh.iothreadinfo(vm_name, options=config, debug=True, ignore_status=False) - range_found = False - for node in numa_info.get_online_nodes_withcpu(): - if re.search('{}\s*{}'.format(node, cpu_range), - result.stdout_text): - logging.debug( - 'Expected cpu range: {} found in stdout for ' - 'node: {}.'.format(cpu_range, node)) - range_found = True - else: - logging.debug('Node {} has no cpu range'.format(node)) - if not range_found: - raise TestFail('Expected cpu range: {} not found in stdout of ' - 'iothreadinfo command.'.format(cpu_range)) + live_vmxml = libvirt_xml.VMXML.new_from_dumpxml(vm_name) + iothread_num = live_vmxml.iothreads + for iothread_id in range(1, iothread_num + 1): + if not re.search('{}\s*{}'.format(iothread_id, cpu_range), + result.stdout_text): + raise TestFail( + 'Iothread {} has no expected cpu affinity {} according to stdout of ' + 'iothreadinfo cmd {}.'.format(iothread_id, cpu_range, result.stdout_text)) -def check_cgget_output(test, expected_value): +def check_cgget_output(test, vm, expected_value): """ Get the cgget output and check it for required value :param test: test object + :param vm: virtual machine :param cgget_message: expected message string in output """ - # Find the slice and print it with the cgget - cpuset_slices = process.run('systemd-cgls cpuset') - machine_found = False - slice_line = None - cpuset_lines = re.split('\s', cpuset_slices.stdout_text) - for line in cpuset_lines: - if re.search('machine-qemu', line): - slice_line = line.strip() - # No more lines need to be checked - break - if not slice_line: - test.error("'machine-qemu' is not found in 'systemd-cgls cpuset' output") - slice_line = slice_line.replace('\\', '\\\\')[2:] - + vm_pid = vm.get_pid() + cg = libvirt_cgroup.CgroupTest(vm_pid) + cg_path = cg.get_cgroup_path(controller='cpuset').split('emulator')[0] for item in ['emulator', 'vcpu0']: - if libvirt_cgroup.CgroupTest('').is_cgroup_v2_enabled(): - cmd = 'cat /sys/fs/cgroup/machine.slice/{}/libvirt/{}/cpuset.mems'.format(slice_line, item) - else: - cmd = 'cat /sys/fs/cgroup/cpuset/machine.slice/{}/libvirt/{}/cpuset.mems'.format(slice_line, item) - + cmd = 'cat {}{}/cpuset.mems'.format(re.escape(cg_path), item) result = process.run(cmd, shell=True, ignore_status=False, verbose=True) if expected_value != result.stdout_text.strip(): test.fail('{} is not found in the cpuset.mems file'.format(expected_value)) @@ -257,7 +237,7 @@ def run(test, params, env): test.fail("The used nodeset is not the same after the libvirtd " "restart.{} is not as expected: {}". format(nodeset_after, nodeset)) - check_cgget_output(test, nodeset) + check_cgget_output(test, vm, nodeset) except Exception as e: test.fail('Unexpected failure during the test: {}'.format(e)) diff --git a/libvirt/tests/src/numa/numa_memAccess.py b/libvirt/tests/src/numa/numa_memAccess.py index a046e7e8bee..47e434dbe3c 100644 --- a/libvirt/tests/src/numa/numa_memAccess.py +++ b/libvirt/tests/src/numa/numa_memAccess.py @@ -26,7 +26,7 @@ def define_and_check_xml(vmxml, params): if "cell_id" in key: numa_cells.append(eval(params[key])) pages = [eval(params["page_id_0"])] - logging.debug(numa_cells, pages) + logging.debug("numa cell is: %s, pages are: %s", numa_cells, pages) del vmxml.numa_memory vmcpuxml = libvirt_xml.vm_xml.VMCPUXML() diff --git a/libvirt/tests/src/numa/numa_memory.py b/libvirt/tests/src/numa/numa_memory.py index b47e448a40d..d7cda36b629 100644 --- a/libvirt/tests/src/numa/numa_memory.py +++ b/libvirt/tests/src/numa/numa_memory.py @@ -200,9 +200,7 @@ def run(test, params, env): if numa_memory.get('nodeset'): numa_nodeset_format = numa_memory.get('nodeset') - numa_memory['nodeset'] = libvirt_numa.parse_numa_nodeset_to_str(numa_nodeset_format, - node_list, - ignore_error=True) + numa_memory['nodeset'] = libvirt_numa.convert_all_nodes_to_string(node_list) used_node = cpu.cpus_parser(numa_memory['nodeset']) logging.debug("set node list is %s", used_node) if not status_error: diff --git a/libvirt/tests/src/numa/numa_memory_migrate.py b/libvirt/tests/src/numa/numa_memory_migrate.py index cb51637762c..044190fff44 100644 --- a/libvirt/tests/src/numa/numa_memory_migrate.py +++ b/libvirt/tests/src/numa/numa_memory_migrate.py @@ -64,8 +64,7 @@ def mem_compare(used_node, left_node): try: if numa_memory.get('nodeset'): numa_nodeset_format = numa_memory.get('nodeset') - numa_memory['nodeset'] = libvirt_numa.parse_numa_nodeset_to_str(numa_nodeset_format, - node_list) + numa_memory['nodeset'] = libvirt_numa.convert_all_nodes_to_string(node_list) used_node = cpu.cpus_parser(numa_memory['nodeset']) logging.debug("set node list is %s", used_node) diff --git a/libvirt/tests/src/numa/numa_memory_spread.py b/libvirt/tests/src/numa/numa_memory_spread.py index 249c356982c..f525586bbe5 100644 --- a/libvirt/tests/src/numa/numa_memory_spread.py +++ b/libvirt/tests/src/numa/numa_memory_spread.py @@ -84,7 +84,7 @@ def prepare_host_for_test(params, test): # Decrease nodeset size by 25% undersize = int(nodeset_size * 0.25) # Memory to eat is a whole nodeset + 5% of neighbour size - memory_to_eat = int(nodeset_size + 0.05 * nodeset_nb_size) + memory_to_eat = int(nodeset_size + 0.005 * nodeset_nb_size) nodeset_string = '{},{}'.format(online_nodes[0], neighbour) process.run("swapoff -a", shell=True) diff --git a/libvirt/tests/src/numa/numa_node_tuning/auto_mem_placement_with_incompatible_host_nodeset.py b/libvirt/tests/src/numa/numa_node_tuning/auto_mem_placement_with_incompatible_host_nodeset.py index ac899195c61..10e7b899f8d 100644 --- a/libvirt/tests/src/numa/numa_node_tuning/auto_mem_placement_with_incompatible_host_nodeset.py +++ b/libvirt/tests/src/numa/numa_node_tuning/auto_mem_placement_with_incompatible_host_nodeset.py @@ -52,7 +52,7 @@ def run_test(): session.send('ZZ') _, text = session.read_until_any_line_matches( [r"%s" % error_msg], timeout=10, internal_timeout=1) - test.log.debug("Checked '%s' exists in '%s'", (error_msg, text)) + test.log.debug("Checked '%s' exists in '%s'", error_msg, text) test.log.debug("Input 'i' to turn off validation") session.sendline('i') @@ -60,8 +60,7 @@ def run_test(): _, text = session.read_until_any_line_matches( [r"%s" % (success_msg % vm_name)], timeout=10, internal_timeout=1) session.close() - test.log.debug("Checked '%s' exists in '%s'", (success_msg % vm_name, - text)) + test.log.debug("Checked '%s' exists in '%s'", success_msg % vm_name, text) vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) libvirt_vmxml.check_guest_xml_by_xpaths( diff --git a/libvirt/tests/src/numa/numa_numanode_cpu_info.py b/libvirt/tests/src/numa/numa_numanode_cpu_info.py index 76ccdcc746a..124b9557e9b 100644 --- a/libvirt/tests/src/numa/numa_numanode_cpu_info.py +++ b/libvirt/tests/src/numa/numa_numanode_cpu_info.py @@ -7,6 +7,7 @@ from virttest import utils_misc from virttest import utils_test from virttest import virsh +from virttest.staging import utils_memory # Using as lower capital is not the best way to do, but this is just a @@ -23,45 +24,51 @@ def update_xml(vm_name, online_nodes, params): """ vmxml = libvirt_xml.VMXML.new_from_dumpxml(vm_name) memory_mode = params.get("memory_mode") + memory_size = int(params.get("memory_size")) + current_memory_size = int(params.get("current_memory_size")) numa_memory = {'mode': memory_mode, 'nodeset': online_nodes[1]} vmxml.numa_memory = numa_memory mb_xml = libvirt_xml.vm_xml.VMMemBackingXML() mb_xml.hugepages = libvirt_xml.vm_xml.VMHugepagesXML() vmxml.mb = mb_xml + vmxml.memory = memory_size + vmxml.current_mem = current_memory_size logging.debug("vm xml is %s", vmxml) vmxml.sync() -def setup_host(required_node_num, online_nodes, pages_list, ori_page_set): +def setup_host(required_node_num, online_nodes, memory_list, ori_page_set): """ Setup host for test - update number of hugepages and check :param required_node_num: int, numa node number at least on the host required by the test :param online_nodes: List of all online nodes with memory available - :param pages_list: List of required number of pages for particular nodes + :param memory_list: List of required hugepage memory for particular nodes :param ori_page_set: A dict used to save original node page """ index = 0 if len(online_nodes) >= required_node_num: - for pages in pages_list: + hugepage_size = utils_memory.get_huge_page_size() + for memory_size in memory_list: ori_page_set[online_nodes[index]] = process.run( - 'cat /sys/devices/system/node/node{}/hugepages/hugepages-2048kB/nr_hugepages'. - format(online_nodes[index]), shell=True).stdout_text.strip() + 'cat /sys/devices/system/node/node{}/hugepages/hugepages-{}kB/nr_hugepages'. + format(online_nodes[index], hugepage_size), shell=True).stdout_text.strip() logging.debug("ori_page_set is {}".format(ori_page_set)) + pages = int(int(memory_size) / hugepage_size) ret = process.run( - 'echo {} > /sys/devices/system/node/node{}/hugepages/hugepages-2048kB/nr_hugepages'. - format(pages, online_nodes[index]), shell=True) + 'echo {} > /sys/devices/system/node/node{}/hugepages/hugepages-{}kB/nr_hugepages'. + format(pages, online_nodes[index], hugepage_size), shell=True) if ret.exit_status: - raise TestError('Cannot set {} hugepages on node {}'. - format(pages, online_nodes[index])) + raise TestError('Cannot set {} pages for {}kB huge page on node {}'. + format(pages, hugepage_size, online_nodes[index])) ret = process.run( - 'cat /sys/devices/system/node/node{}/hugepages/hugepages-2048kB/nr_hugepages'. - format(online_nodes[index]), shell=True) - if pages not in ret.stdout_text: - raise TestError('Setting {} hugepages on node {} was unsuccessful'. - format(pages, online_nodes[index])) + 'cat /sys/devices/system/node/node{}/hugepages/hugepages-{}kB/nr_hugepages'. + format(online_nodes[index], hugepage_size), shell=True) + if str(pages) not in ret.stdout_text: + raise TestError('Setting {} pages for {}kB huge page on node {} was unsuccessful'. + format(pages, hugepage_size, online_nodes[index])) index += 1 else: raise TestCancel("The test cannot continue since there is no enough " @@ -75,13 +82,13 @@ def run(test, params, env): vm_name = params.get("main_vm") vm = env.get_vm(vm_name) error_message = params.get("err_msg") - pages_list = eval(params.get('nodes_pages')) + node_memory_list = eval(params.get('nodes_memory')) backup_xml = libvirt_xml.VMXML.new_from_dumpxml(vm_name) numa_info = utils_misc.NumaInfo() online_nodes = numa_info.get_online_nodes_withmem() ori_page_set = {} required_numa_node_num = int(params.get("numa_cells_with_memory_required", '2')) - setup_host(required_numa_node_num, online_nodes, pages_list, ori_page_set) + setup_host(required_numa_node_num, online_nodes, node_memory_list, ori_page_set) try: if vm.is_alive(): vm.destroy() @@ -94,8 +101,9 @@ def run(test, params, env): except Exception as e: test.error("Unexpected error: {}".format(e)) finally: + hugepage_size = utils_memory.get_huge_page_size() for node_index, ori_page in ori_page_set.items(): process.run( - 'echo {} > /sys/devices/system/node/node{}/hugepages/hugepages-2048kB/nr_hugepages'. - format(ori_page, node_index), shell=True) + 'echo {} > /sys/devices/system/node/node{}/hugepages/hugepages-{}kB/nr_hugepages'. + format(ori_page, node_index, hugepage_size), shell=True) backup_xml.sync() diff --git a/libvirt/tests/src/passthrough/ap/libvirt_ap_passthrough_autostart.py b/libvirt/tests/src/passthrough/ap/libvirt_ap_passthrough_autostart.py index 2ec18207ff1..628f49b1e51 100644 --- a/libvirt/tests/src/passthrough/ap/libvirt_ap_passthrough_autostart.py +++ b/libvirt/tests/src/passthrough/ap/libvirt_ap_passthrough_autostart.py @@ -11,15 +11,19 @@ # # Copyright: Red Hat Inc. 2022 # Author: Sebastian Mitterle +import logging + from avocado.core.exceptions import TestFail from virttest.libvirt_xml.vm_xml import VMXML -from virttest.utils_misc import cmd_status_output +from virttest.utils_misc import cmd_status_output, wait_for from virttest.utils_zcrypt import load_vfio_ap from provider.vfio import ap from provider.vfio.mdev_handlers import MdevHandler +LOG = logging.getLogger("avocado." + __name__) + def confirm_device_is_running(uuid, session=None): """ @@ -30,11 +34,14 @@ def confirm_device_is_running(uuid, session=None): be executed on the host. :raises TestFail: if the device isn't running. """ - cmd = "mdevctl list -u %s" % uuid - err, out = cmd_status_output(cmd, shell=True, session=session) - if uuid not in out: - raise TestFail("Mediated device UUID(%s) not listed in output:" - " %s. Exit code: %s" % (uuid, out, err)) + def _is_listed(): + """Parameterless helper function to use with wait_for""" + cmd = "mdevctl list -u %s" % uuid + err, out = cmd_status_output(cmd, shell=True, session=session) + LOG.debug("mediated device status - {}, output - {}.".format(err, out)) + return uuid in out + if not wait_for(_is_listed, timeout=5): + raise TestFail("Mediated device UUID(%s) not listed" % uuid) def run(test, params, env): diff --git a/libvirt/tests/src/passthrough/ccw/libvirt_ccw_passthrough.py b/libvirt/tests/src/passthrough/ccw/libvirt_ccw_passthrough.py index 758632e5c39..4cc5b9f79fc 100644 --- a/libvirt/tests/src/passthrough/ccw/libvirt_ccw_passthrough.py +++ b/libvirt/tests/src/passthrough/ccw/libvirt_ccw_passthrough.py @@ -1,17 +1,50 @@ from uuid import uuid4 +from virttest.utils_misc import wait_for, cmd_status_output from virttest.utils_zchannels import ChannelPaths from virttest.libvirt_xml.vm_xml import VMXML from provider.vfio import ccw +def mdev_listed(uuid): + """ + Returns a function that will check if the mediated device + with given uuid is listed + + :param uuid: uuid of the mediated device + """ + + def _mdev_listed(): + """ + True if uuid is listed, False else + """ + cmd = "lsmdev" + _, o = cmd_status_output(cmd) + LOG.debug(o) + return uuid in o + + return _mdev_listed + + +def guest_is_responsive(session): + """ + Executes a simple command on the guest and handles errors. + + :param session: logged in guest console session + :return True: if all works well, False if not + """ + try: + cmd_status_output("ls", session=session, ignore_status=False) + return True + except Exception as e: + logging.debug(f"failed to execute command: {e}") + return False + + def run(test, params, env): """ Test for CCW, esp. DASD disk passthrough on s390x. - - The CCW disk/its subchannel for passthrough is expected to - be listed on the host but not enabled for use. """ vm_name = params.get("main_vm") @@ -47,15 +80,15 @@ def run(test, params, env): if device_removal_case: ChannelPaths.set_standby(chpids) - if ccw.device_is_listed(session, chpids): - test.fail("Device must not be visible inside guest") + if not guest_is_responsive(session): + test.fail("Guest and host must be responsive if device removed.") vm.destroy() ChannelPaths.set_online(chpids) ccw.set_override(schid) ccw.start_device(uuid, schid) - + wait_for(lambda: mdev_listed(uuid), timeout=10) vm.start() session = vm.wait_for_login() diff --git a/libvirt/tests/src/passthrough/ccw/libvirt_ccw_passthrough_read_write.py b/libvirt/tests/src/passthrough/ccw/libvirt_ccw_passthrough_read_write.py index b9aefd3210f..b4d04c45820 100644 --- a/libvirt/tests/src/passthrough/ccw/libvirt_ccw_passthrough_read_write.py +++ b/libvirt/tests/src/passthrough/ccw/libvirt_ccw_passthrough_read_write.py @@ -8,9 +8,6 @@ def run(test, params, env): """ Test for CCW, esp. DASD disk passthrough on s390x. - - The CCW disk/its subchannel for passthrough is expected to - be listed on the host but not enabled for use. """ vm_name = params.get("main_vm") @@ -24,10 +21,12 @@ def run(test, params, env): uuid = None chpids = None + plugmethod = params.get("plugmethod") + try: ccw.assure_preconditions() - if vm.is_alive(): + if vm.is_alive() and plugmethod == "coldplug": vm.destroy() schid, chpids = ccw.get_device_info(devid) @@ -37,12 +36,18 @@ def run(test, params, env): ccw.start_device(uuid, schid) ccw.attach_hostdev(vm_name, uuid) - vm.start() + if vm.is_dead() and plugmethod == "coldplug": + vm.start() session = vm.wait_for_login() if not ccw.read_write_operations_work(session, chpids): test.fail("Read/write operation failing inside guest.") + if vm.is_alive() and plugmethod == "coldplug": + vm.destroy() + + ccw.detach_hostdev(vm_name, uuid) + finally: if uuid: ccw.stop_device(uuid) diff --git a/libvirt/tests/src/passthrough/pci/ism_pci_passthrough.py b/libvirt/tests/src/passthrough/pci/ism_pci_passthrough.py index 0fe12c5549c..907e73d20c1 100644 --- a/libvirt/tests/src/passthrough/pci/ism_pci_passthrough.py +++ b/libvirt/tests/src/passthrough/pci/ism_pci_passthrough.py @@ -5,27 +5,29 @@ from avocado.core.exceptions import TestError, TestFail from avocado.utils import process +from virttest import virsh from virttest.libvirt_xml.vm_xml import VMXML from virttest.libvirt_xml.nodedev_xml import NodedevXML +from provider.vfio import get_hostdev_xml -logging = log.getLogger('avocado.' + __name__) + +logging = log.getLogger("avocado." + __name__) smc_port = 37373 -def attach_device(pci_dev, vmxml): +def get_ism_address(pci_dev): """ - Attaches the pci device if it's an ISM device. + Get the ISM device address. - :param pci_dev: The node device name of the ISM device. - :param vmxml: VMXML instance of the VM + :param pci_dev: libvirt's node device name + :return: the address element + :raises TestError: if the device is not an ISM device """ pci_xml = NodedevXML.new_from_dumpxml(pci_dev) if "ism" != pci_xml.driver_name: raise TestError("Device %s is not an ISM device: %s" % (pci_dev, pci_xml)) - pci_address = pci_xml.cap.get_address_dict() - vmxml.add_hostdev(pci_address) - vmxml.sync() + return pci_xml.cap.get_address_dict() def check_device_is_available(vm): @@ -37,7 +39,7 @@ def check_device_is_available(vm): session = vm.wait_for_login() output = session.cmd_output("lspci") session.close() - devices = output.split('\n') + devices = output.split("\n") if not len(devices) >= 1 or "ISM" not in devices[0]: raise TestFail("Expected 1 ISM PCI device but got: %s" % output) @@ -63,6 +65,31 @@ def check_guest_and_host_can_communicate(vm, guest_iface): raise TestFail("SMC-D is not functional: %s" % output) +def hotplug_device(pci_dev, vm_name): + """ + Hotplug the device + + :param vm_name: the VM name + :param pci_dev: the node device name + """ + pci_address = get_ism_address(pci_dev) + hostdev_xml = get_hostdev_xml(pci_address) + virsh.attach_device(vm_name, hostdev_xml.xml, flagstr="--live", debug=True) + time.sleep(1) + + +def coldplug_device(pci_dev, vmxml): + """ + Updates the VMXML with the given PCI device if it's an ISM device. + + :param pci_dev: The node device name of the ISM device. + :param vmxml: VMXML instance of the VM + """ + pci_address = get_ism_address(pci_dev) + vmxml.add_hostdev(pci_address) + vmxml.sync() + + def start_test_server(session): """ Starts the server part in a different thread. @@ -71,7 +98,9 @@ def start_test_server(session): """ session.cmd("systemctl stop firewalld") - server = Thread(target=lambda: session.cmd("timeout 10s smc_chk -S -p %s" % smc_port)) + server = Thread( + target=lambda: session.cmd("timeout 10s smc_chk -S -p %s" % smc_port) + ) server.start() time.sleep(1) return server @@ -119,10 +148,16 @@ def run(test, params, env): backup_xml = vmxml.copy() try: - attach_device(pci_dev, vmxml) - vm.start() - - if check == "available": + if "hotplug" not in check: + if vm.is_alive(): + vm.destroy() + coldplug_device(pci_dev, vmxml) + vm.start() + + if check == "available_hotplug": + hotplug_device(pci_dev, vm_name) + check_device_is_available(vm) + elif check == "available": check_device_is_available(vm) elif check == "available_after_reboot": check_device_is_available_after_reboot(vm) diff --git a/libvirt/tests/src/passthrough/pci/libvirt_pci_passthrough.py b/libvirt/tests/src/passthrough/pci/libvirt_pci_passthrough.py index 3fc9d9e9e55..82e776ba2cf 100644 --- a/libvirt/tests/src/passthrough/pci/libvirt_pci_passthrough.py +++ b/libvirt/tests/src/passthrough/pci/libvirt_pci_passthrough.py @@ -1,5 +1,6 @@ import logging as log import ipaddress +import platform import time from virttest import virsh, virt_vm @@ -39,6 +40,8 @@ def run(test, params, env): i) Reboot. ii) Suspend/Resume. iii) Start/Shutdown. + d). Multiple Reboots: + 1. Checking PCI Device remains persistent across multiple reboots """ def guest_lifecycle(): @@ -93,6 +96,8 @@ def guest_lifecycle(): sriov = ('yes' == params.get("libvirt_pci_SRIOV", 'no')) device_type = params.get("libvirt_pci_device_type", "NIC") vm_vfs = int(params.get("number_vfs", 2)) + number_of_reboots = int(params.get("number_of_reboots", "1")) + arch = platform.machine() pci_dev = None pci_address = None bus_info = [] @@ -174,59 +179,76 @@ def guest_lifecycle(): pci_address = pci_xml.cap.get_address_dict() vmxml.add_hostdev(pci_address) - try: - for itr in range(iteration): - logging.info("Currently executing iteration number: '%s'", itr) - vmxml.sync() - vm.start() - session = vm.wait_for_login() - # The Network configuration is generic irrespective of PF or SRIOV VF - if device_type == "NIC": - if sorted(vm.get_pci_devices()) != sorted(nic_list_before): - logging.debug("Adapter passthroughed to guest successfully") - else: - test.fail("Passthrough adapter not found in guest.") - net_ip = ipaddress.ip_address(net_ip) - nic_list_after = vm.get_pci_devices() - nic_list = list(set(nic_list_after).difference(set(nic_list_before))) - for val in range(len(nic_list)): - bus_info.append(str(nic_list[val]).split(' ', 1)[0]) - nic_list[val] = str(nic_list[val]).split(' ', 1)[0][:-2] - bus_info.sort() - if not sriov: - # check all functions get same iommu group + def check_device_status(net_ip, server_ip, netmask): + logging.info("Currently executing iteration number: '%s'", itr) + vmxml.sync() + vm.start() + session = vm.wait_for_login() + # The Network configuration is generic irrespective of PF or SRIOV VF + if device_type == "NIC": + if sorted(vm.get_pci_devices()) != sorted(nic_list_before): + logging.debug("Adapter passthroughed to guest successfully") + else: + test.fail("Passthrough adapter not found in guest.") + net_ip = ipaddress.ip_address(net_ip) + nic_list_after = vm.get_pci_devices() + nic_list = list(set(nic_list_after).difference(set(nic_list_before))) + for val in range(len(nic_list)): + bus_info.append(str(nic_list[val]).split(' ', 1)[0]) + nic_list[val] = str(nic_list[val]).split(' ', 1)[0][:-2] + bus_info.sort() + if not sriov: + # check all functions get same iommu group + # arch ppc64 gets different iommu group when attached to VM + if arch != "ppc64le": if len(set(nic_list)) != 1: test.fail("Multifunction Device passthroughed but " "functions are in different iommu group") - # ping to server from each function - for val in bus_info: - nic_name = str(utils_misc.get_interface_from_pci_id(val, session)) - session.cmd("ip addr flush dev %s" % nic_name) - session.cmd("ip addr add %s/%s dev %s" - % (net_ip, netmask, nic_name)) - session.cmd("ip link set %s up" % nic_name) - # Pinging using nic_name is having issue, - # hence replaced with IPAddress - s_ping, o_ping = utils_test.ping(server_ip, count=5, - interface=net_ip, timeout=30, - session=session) - logging.info(o_ping) - if s_ping != 0: - err_msg = "Ping test fails, error info: '%s'" - test.fail(err_msg % o_ping) - # Each interface should have unique IP + # ping to server from each function + for val in bus_info: + nic_name = str(utils_misc.get_interface_from_pci_id(val, session)) + session.cmd("ip addr flush dev %s" % nic_name) + session.cmd("ip addr add %s/%s dev %s" + % (net_ip, netmask, nic_name)) + session.cmd("ip link set %s up" % nic_name) + # Pinging using nic_name is having issue, + # hence replaced with IPAddress + s_ping, o_ping = utils_test.ping(server_ip, count=5, + interface=net_ip, timeout=30, + session=session) + logging.info(o_ping) + if s_ping != 0: + err_msg = "Ping test fails, error info: '%s'" + test.fail(err_msg % o_ping) + # Each interface should have unique IP + # For ppc64 arch let's test using one ip only + if arch != "ppc64le": net_ip = net_ip + 1 - elif device_type == "STORAGE": - # Get the result of "fdisk -l" in guest, and - # compare the result with fdisk_list_before. - output = session.cmd_output("fdisk -l|grep \"Disk identifier:\"") - fdisk_list_after = output.splitlines() - if fdisk_list_after == fdisk_list_before: - test.fail("Didn't find the disk attached to guest.") + elif device_type == "STORAGE": + # Get the result of "fdisk -l" in guest, and + # compare the result with fdisk_list_before. + output = session.cmd_output("fdisk -l|grep \"Disk identifier:\"") + fdisk_list_after = output.splitlines() + if fdisk_list_after == fdisk_list_before: + test.fail("Didn't find the disk attached to guest.") - # Execute VM Life-cycle Operation with device pass-through + def multiple_reboot(number_of_reboots): + for reboot_count in range(number_of_reboots): + logging.info("Performing VM Reboot with device pass-through for reboot count : %s", reboot_count) guest_lifecycle() + logging.info("Check device avialablity after VM Reboot for reboot count : %s", reboot_count) + check_device_status(net_ip, server_ip, netmask) + + try: + for itr in range(iteration): + check_device_status(net_ip, server_ip, netmask) + + # Execute VM Life-cycle Operation with device pass-through + guest_lifecycle() + + # Execute Multiple reboots on VM and check the device persistency + multiple_reboot(number_of_reboots) finally: backup_xml.sync() diff --git a/libvirt/tests/src/passthrough/robustness/passthrough_robustness.py b/libvirt/tests/src/passthrough/robustness/passthrough_robustness.py new file mode 100644 index 00000000000..0b12ed36a6e --- /dev/null +++ b/libvirt/tests/src/passthrough/robustness/passthrough_robustness.py @@ -0,0 +1,311 @@ +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# See LICENSE for more details. +# +# Copyright: Red Hat Inc. 2024 +# Author: Sebastian Mitterle +import logging + +from avocado.core.exceptions import TestError, TestFail +from virttest import virsh +from virttest.libvirt_xml.nodedev_xml import NodedevXML +from virttest.libvirt_xml.vm_xml import VMXML + +from provider import vfio +from provider.vfio.mdev_handlers import MdevHandler + +LOG = logging.getLogger("avocado." + __name__) + + +class VMHandler(object): + """Handles usage of VMs in this test""" + + def __init__(self, vms): + """ + Initializes the instance fields and stores VMXML + for later backup. + + :param vms: list of VM instances as obtained from env + """ + self.vms = vms + self.vmxml_backups = [] + for vm in self.vms: + self.vmxml_backups.append(VMXML.new_from_inactive_dumpxml(vm.name)) + + def run(self, action, vm_idx, device, handlers): + """ + Delegates actions to VMs. + + :param action: the name of the method to call on the VM instance + :param vm_idx: the index of the VM to call the method on + :param device: the device identifier if action involves a device + :param handlers: a reference to the NodeDevHandlerAggregator instance that + holds all device handlers + """ + if action in ["reboot", "start", "destroy", "shutdown", "pause", "resume"]: + getattr(self.vms[vm_idx], action)() + elif action in ["attach", "detach"]: + hostdev_xml = handlers.get_hostdev_xml(device) + getattr(virsh, action + "_device")( + self.vms[vm_idx].name, + hostdev_xml, + flagstr="--current", + ignore_status=False, + debug=True, + ) + + elif action == "check_present": + session = self.vms[vm_idx].wait_for_login() + try: + handlers.run("check_present", device, session) + except TestFail as e: + raise e + finally: + session.close() + else: + raise TestError(f"Unknown action: {action}") + + def clean_up(self): + """Restores the VMXML""" + for xml in self.vmxml_backups: + xml.sync() + + +class NodeDevHandlerAggregator(object): + """ + Holds NodeDevHandler singletons per device identifier + and delegates actions + """ + + def __init__(self): + """Initializes the instance""" + self.handlers = [] + + def add_once(self, device): + """ + Creates and stores a single NodeDevHandler instance per device identifier. + + :param device: the device identifier as used in the commands, e.g. "ap-0.0.000e" + more info in NodeDevHandler.__init__ + """ + device_type, device_id = device.split("-") + if [h for h in self.handlers if h.type == device_type and h.id == device_id]: + pass + else: + self.handlers.append(NodeDevHandler(device_type, device_id)) + + def run(self, action, device, session=None): + """ + Delegates the action to the given device handler + + :param action: method implemented by the device handler, e.g. 'start' + :param device: the device identifier as used in the commands, e.g. "ap-0.0.000e" + more info in NodeDevHandler.__init__ + :param session: logged-in guest session, e.g. for checking if device is present inside + """ + device_type, device_id = device.split("-") + handler = [ + h for h in self.handlers if h.type == device_type and h.id == device_id + ][0] + if session: + getattr(handler, action)(session=session) + else: + getattr(handler, action)() + + def get_hostdev_xml(self, device): + """ + Retrieves the existing host device XML file reference for a given device + + :param device: the device identifier as used in the commands, e.g. "ap-0.0.000e" + more info in NodeDevHandler.__init__ + """ + device_type, device_id = device.split("-") + handler = [ + h for h in self.handlers if h.type == device_type and h.id == device_id + ][0] + return handler.hostdev_xml.xml + + +class NodeDevHandler(object): + """An object to handle actions on node devices""" + + device_address_counter = 10 + + def __init__(self, device_type, device_id): + """ + Holds the initial identifiers and prepares + fields for future use. + It also prepares the device identifiers for + the host device xml and check inside the guest. + + Examples: + vfio_ap: device_type=ap, device_id=00.000e + vfio_ccw: device_type=ccw, device_id=0.0.5200 + pci_ism: device_type=ism, device_id=0000.00.00.0 + pci_roce: device_type=roce, device_id=0000.00.00.2 + """ + self.type = device_type + if self.type not in ["ap", "ccw", "ism", "roce"]: + raise TestError(f"Unknown device type {self.type}") + self.id = device_id + self.nodedev_name = None + self.hostdev_xml = None + self.mdev_handler = None + self.guest_id = None + self.devno = None + self.uid = None + self.fid = None + self.previously_started = False + + if self.type in ["ism", "roce"]: + self.uid = f"{NodeDevHandler.device_address_counter:#0{6}x}" + self.fid = f"{NodeDevHandler.device_address_counter:#0{10}x}" + self.guest_id = f"{NodeDevHandler.device_address_counter:#0{6}x}:00:00.0".replace("0x", "") + NodeDevHandler.device_address_counter += 1 + elif self.type in ["ccw"]: + self.devno = f"{NodeDevHandler.device_address_counter:#0{6}x}" + NodeDevHandler.device_address_counter += 1 + + def start(self): + """Starts the device""" + if self.type == "ap": + if not self.previously_started: + self.mdev_handler = MdevHandler.from_type("vfio_ap-passthrough") + self.nodedev_name = self.mdev_handler.create_nodedev("nodedev", [self.id]) + self.hostdev_xml = vfio.get_hostdev_xml(self.mdev_handler.uuid, "vfio-ap") + self.previously_started = True + elif self.type == "ccw": + if not self.previously_started: + self.mdev_handler = MdevHandler.from_type("vfio_ccw-io") + self.mdev_handler.expected_device_address = f"0.0.{self.devno}".replace( + "0x", "" + ) + self.nodedev_name = self.mdev_handler.create_nodedev( + api="nodedev", devid=self.id + ) + hostdev_xml = vfio.get_hostdev_xml(self.mdev_handler.uuid, "vfio-ccw") + addr = hostdev_xml.Address.new_from_dict( + { + "type_name": "ccw", + "cssid": "0xfe", + "ssid": "0x0", + "devno": self.devno, + } + ) + hostdev_xml.address = addr + hostdev_xml.xmltreefile.write() + self.hostdev_xml = hostdev_xml + self.previously_started = True + else: + if not self.previously_started: + self.nodedev_name = "pci_" + self.id.replace(":", "_").replace(".", "_") + pci_xml = NodedevXML.new_from_dumpxml(self.nodedev_name) + hostdev_xml = vfio.get_hostdev_xml(pci_xml.cap.get_address_dict()) + addr = hostdev_xml.Address.new_from_dict( + { + "type_name": "pci", + "domain": "0x0000", + "bus": "0x00", + "slot": "0x00", + "function": "0x0", + } + ) + zpci = addr.Zpci.new_from_dict({"uid": self.uid, "fid": self.fid}) + addr.set_zpci_attrs(zpci) + hostdev_xml.address = addr + hostdev_xml.xmltreefile.write() + self.hostdev_xml = hostdev_xml + self.previously_started = True + + def stop(self, ignore_status=False): + """ + Stops the device + + :param ignore_status: if to ignore if device can't be stopped + this avoids issues during test teardown + """ + if self.type in ["ism", "roce"]: + return + virsh.nodedev_destroy( + self.nodedev_name, debug=True, ignore_status=ignore_status + ) + + def check_present(self, session): + """ + Checks if the device is present inside the guest. + + :param session: the guest console session + """ + if self.type in ["ap", "ccw"]: + self.mdev_handler.check_device_present_inside_guest(session) + elif self.type in ["ism", "roce"]: + name_part = "ISM" if self.type == "ism" else "Ethernet" + vfio.check_pci_device_present(self.guest_id, name_part, session) + + def clean_up(self): + """Cleans the handler up""" + if self.mdev_handler: + self.mdev_handler.clean_up() + + +def run(test, params, env): + """ + These tests execute workflows over passthrough devices + and VMs. + + The test steps are configured in the test configuration via + the parameter `cmds`. It holds all steps to be executed. + + All steps are terminated with ",". + There are two kind of steps: + action;device_identifier - this is an action to be executed on the node + device by the NodeDevHandler instance, e.g. start + or stop the device + action;vm_idx[;device_identifier] - this is an action prefixed with "vm_"; + the action is executed on the VM or delegated, + s. VMHandler; the vm_idx determines which VM is used + and the optional parameter `device_identifier` is passed + for actions that involve both, VM and the node device, + e.g. `vm_attach;0;ap-0.0.000e` + """ + vm_handler = VMHandler(env.get_all_vms()) + + try: + cmds = params.get("cmds").split(",") + handlers = NodeDevHandlerAggregator() + parts = None + action = None + vm_idx = None + device = None + hostdev_xml = None + for cmd in cmds: + if not cmd.strip(): + continue + LOG.debug(f"Run {cmd}.") + parts = cmd.split(";") + action = parts[0] + if not action.startswith("vm"): + device = parts[1] + handlers.add_once(device) + handlers.run(action, device) + else: + action = parts[0].replace("vm_", "") + vm_idx = parts[1] + if len(parts) > 2: + device = parts[2] + vm_handler.run(action, int(vm_idx), device, handlers) + + finally: + if vm_handler: + vm_handler.clean_up() + if handlers: + for handler in handlers.handlers: + handler.stop(ignore_status=True) + handler.clean_up() diff --git a/libvirt/tests/src/save_and_restore/abort_managedsave.py b/libvirt/tests/src/save_and_restore/abort_managedsave.py new file mode 100644 index 00000000000..3f386a398dc --- /dev/null +++ b/libvirt/tests/src/save_and_restore/abort_managedsave.py @@ -0,0 +1,74 @@ +import logging +import os +import re + +from virttest import virsh +from virttest import utils_test +from virttest.libvirt_xml import vm_xml + +from provider.save import save_base + +LOG = logging.getLogger('avocado.test.' + __name__) +VIRSH_ARGS = {'debug': True, 'ignore_status': False} + + +def run(test, params, env): + """ + Test the scenario to abort the vm ManagedSave process + Steps: + 1. Start the vm, run stress in the vm to slow down the ManagedSave process; + 2. Run "virsh managedsave" to save the vm; + 3. During the managedsave process, run domjobabort; + 4. Check the VM's states after the abort operation and check the events; + """ + + vm_name = params.get('main_vm') + vm = env.get_vm(vm_name) + default_path = params.get('default_path') + file_path = default_path + vm_name + '.save' + stress_package = params.get("stress_package", "stress") + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + bkxml = vmxml.copy() + event_cmd = params.get("event_cmd") + expected_event = eval(params.get('expected_event')) + try: + vm.start() + pid_ping, upsince = save_base.pre_save_setup(vm) + LOG.debug('TEST_STEP1: run stress on the vm:') + vm_stress = utils_test.VMStress(vm, stress_package, params) + vm_stress.load_stress_tool() + LOG.debug('TEST_STEP2: ManagedSave the VM:') + # Start event session to catch the events + event_session = virsh.EventTracker.start_get_event(vm_name, event_cmd=event_cmd) + cmd = "managedsave %s" % vm_name + virsh_session = virsh.VirshSession(virsh_exec=virsh.VIRSH_EXEC, + auto_close=False) + virsh_session.sendline(cmd) + LOG.debug('TEST_STEP3: Abort the ManagedSave process') + # check if the save process is succeed, cancel the test if save succeed + st = virsh.domjobinfo(vm_name, ignore_status=True).stdout_text.strip() + LOG.debug("domjobinfo: %s", st) + if not re.search("Unbounded", st): + test.cancel("Test cancel since managedsave process completed before abort.") + virsh.domjobabort(vm_name).stdout_text.strip() + LOG.debug("Check the VM's state details after save abort") + save_base.post_save_check(vm, pid_ping, upsince) + # check the events for abort + LOG.debug("TEST_STEP4: Check the event:") + event_output = virsh.EventTracker.finish_get_event(event_session) + for event in expected_event: + if not re.search(event, event_output): + test.fail('Not find: %s from event output:%s' % (event, event_output)) + # check VM states details + outputs_ = virsh.domstate(vm_name, "--reason").stdout_text.strip() + LOG.debug("TEST_STEP5: check the domstate: %s and ensure no saved file", outputs_) + if not re.search("save canceled", outputs_): + test.fail("There is no 'save canceled' words in the domstate outputs!") + if os.path.exists(file_path): + test.fail("There should not be the save file since managedsave aborted") + virsh_session.close() + virsh.shutdown(vm_name, **VIRSH_ARGS) + finally: + bkxml.sync() + if os.path.exists(file_path): + os.remove(file_path) diff --git a/libvirt/tests/src/save_and_restore/abort_save.py b/libvirt/tests/src/save_and_restore/abort_save.py new file mode 100644 index 00000000000..81d0639bbf1 --- /dev/null +++ b/libvirt/tests/src/save_and_restore/abort_save.py @@ -0,0 +1,66 @@ +import logging +import re +import os + +from virttest import data_dir +from virttest import utils_test +from virttest import utils_misc +from virttest import virsh +from virttest.libvirt_xml import vm_xml + +from provider.save import save_base + +LOG = logging.getLogger('avocado.test.' + __name__) + + +def run(test, params, env): + """ + Test the scenario to abort the vm save process + Steps: + 1. Start the vm, run stress in the vm to slow down the save process; + 2. Run "virsh save" to save the vm; + 3. During the save process, run domjobabort; + 4. Check the VM's states after the abort operation; + """ + vm_name = params.get('main_vm') + vm = env.get_vm(vm_name) + stress_package = params.get("stress_package", "stress") + + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + bkxml = vmxml.copy() + + try: + vm.start() + pid_ping, upsince = save_base.pre_save_setup(vm) + LOG.debug('TEST_STEP1: run stress on the vm:') + vm_stress = utils_test.VMStress(vm, stress_package, params) + vm_stress.load_stress_tool() + save_path = os.path.join(data_dir.get_tmp_dir(), 'rhel.save') + LOG.debug('TEST_STEP2: Save the VM:') + cmd = "save %s %s" % (vm_name, save_path) + virsh_session = virsh.VirshSession(virsh_exec=virsh.VIRSH_EXEC, + auto_close=True) + virsh_session.sendline(cmd) + LOG.debug('TEST_STEP3: Abort the save process') + # check if the save process is succeed, if save succeed, cancel the test + st = virsh.domjobinfo(vm_name, ignore_status=True).stdout_text.strip() + LOG.debug("domjobinfo: %s", st) + if not re.search("Unbounded", st): + test.cancel("Test cancel since save process completed before abort.") + virsh.domjobabort(vm_name) + utils_misc.wait_for(lambda: vm.state() == 'running', 10) + LOG.debug("vm state is %s after abort the save process", vm.state()) + if vm.state() != 'running': + test.fail(f'VM should be running after abort restore, not {vm.state()}') + save_base.post_save_check(vm, pid_ping, upsince) + LOG.debug("TEST_STEP4: Check the VM's state details after save abort") + outputs = virsh.domstate(vm_name, "--reason").stdout_text.strip() + LOG.debug("vm state detail is %s", outputs) + if not re.search("save canceled", outputs): + test.fail("There is no 'save canceled' words in the domstate outputs!") + virsh.shutdown(vm_name, debug=True, ignore_status=False) + finally: + virsh_session.close() + bkxml.sync() + if os.path.exists(save_path): + os.remove(save_path) diff --git a/libvirt/tests/src/save_and_restore/managedsave_dumpxml.py b/libvirt/tests/src/save_and_restore/managedsave_dumpxml.py new file mode 100644 index 00000000000..0fa868bdb54 --- /dev/null +++ b/libvirt/tests/src/save_and_restore/managedsave_dumpxml.py @@ -0,0 +1,101 @@ +import os +import logging +import xml.etree.ElementTree as ET + +from avocado.utils import process + +from virttest import virsh +from virttest.libvirt_xml import vm_xml +from virttest.utils_test import libvirt +from virttest.utils_libvirt import libvirt_vmxml + +LOG = logging.getLogger('avocado.' + __name__) + + +def run(test, params, env): + """ + Test command: virsh managedsave-dumpxml + Extract the domain XML that was in effect at the time the saved state file was created + with the managedsave command. Using --security-info will also include security sensitive information. + """ + vm_name = params.get("main_vm") + vm = env.get_vm(vm_name) + managed_save_file = "/var/lib/libvirt/qemu/save/%s.save" % vm_name + graphic_attrs = eval(params.get('graphic_attrs', '{}')) + + def setup(): + """" + Prepare the pre-conditions: + 1) Prepare the vm with security info; + 2) Managedsave the vm; + """ + vmxml_ = vm_xml.VMXML.new_from_dumpxml(vm_name) + libvirt_vmxml.modify_vm_device(vmxml_, 'graphics', graphic_attrs) + vmxml_.sync() + if not vm.is_alive(): + vm.start() + LOG.info("vm %s state is %s", vm_name, virsh.domstate(vm_name).stdout) + virsh.dumpxml(vm_name, "--xpath //graphics") + virsh.managedsave(vm_name, ignore_status=False, debug=True) + + def check_outputxml(xml_text, graphic_setting): + """ + Check the XML snippet: + 1) If no --xpath option, the root element should be ; + 2) If --xpath is given, validate the root structure accordingly; + 3) If --security-info is set, ensure password info is included/excluded correctly. + """ + try: + # If xml_text is actual content, parse from string + root = ET.fromstring(xml_text) + + # Step 1: Validate root + if option == "--xpath //os": + if root.tag != "os": + test.fail("Expected root tag but got <%s>" % root.tag) + + elif option == "--xpath //os --wrap": + if root.tag != "nodes": + test.fail("Expected root tag for wrapped content.") + children = list(root) + if not children or children[0].tag != "os": + test.fail("Expected first child under to be .") + + else: # Default: should be + if root.tag != "domain": + test.fail("Expected root tag but got <%s>" % root.tag) + + # Step 2: Validate security info + if option == "--security-info": + expected = f"passwd='{graphic_setting.get('passwd', '')}'" + LOG.info("Checking for presence of: %s", expected) + if expected not in xml_text: + test.fail("Missing security info (passwd) in the XML.") + else: + if "passwd" in xml_text: + test.fail("Unexpected security info (passwd) found in the XML.") + + except ET.ParseError as e: + test.fail(f"XML parsing failed: {e}") + + option = params.get("option", "") + err_msg = params.get("err_msg", None) + opt_r = "yes" == params.get("readonly", "no") + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + bk_xml = vmxml.copy() + + try: + LOG.info("TEST_STEP1: Managedsave the VM:") + setup() + LOG.info("TEST_STEP2: Dump the VM's xml by managedave-dumpxml with %s:", option) + res = virsh.managedsave_dumpxml(vm_name, option, readonly=opt_r) + libvirt.check_result(res, expected_fails=err_msg) + if not err_msg: + LOG.info("TEST_STEP3: Check the format of the xml dumped:") + check_outputxml(res.stdout.strip(), graphic_attrs) + virsh.destroy(vm_name) + finally: + virsh.managedsave_remove(vm_name, debug=True) + if os.path.exists(managed_save_file): + process.run("rm -f %s" % managed_save_file, shell=True, ignore_status=True) + bk_xml.sync() diff --git a/libvirt/tests/src/save_and_restore/managedsave_remove.py b/libvirt/tests/src/save_and_restore/managedsave_remove.py new file mode 100644 index 00000000000..30fdfd36507 --- /dev/null +++ b/libvirt/tests/src/save_and_restore/managedsave_remove.py @@ -0,0 +1,108 @@ +import os +import logging +from virttest import virsh +from avocado.utils import process +from virttest.libvirt_xml import vm_xml +from virttest.utils_test import libvirt + +LOG = logging.getLogger('avocado.' + __name__) + + +def run(test, params, env): + """ + Test command: virsh managedsave-remove + + Remove the managedsave state file for a domain, if it exists. + This ensures the domain will do a full boot the next time it + is started. + """ + + vm_name = params.get("main_vm") + vm = env.get_vm(vm_name) + managed_save_file = "/var/lib/libvirt/qemu/save/%s.save" % vm_name + + def setup(): + """" + Prepare the pre-conditions + 1. Managedsave vm if needed + 2. Prepare an invalid saved file if needed + 3. Remove the saved file if needed + """ + if not vm.is_alive(): + vm.start() + if vm_managedsaved: + virsh.managedsave(vm_name, debug=True) + if file_state == "corrupt": + process.run("echo > %s" % managed_save_file, shell=True, ignore_status=True) + elif file_state == "nonexist" and vm_managedsaved: + process.run("rm -f %s" % managed_save_file, shell=True, ignore_status=True) + + file_state = params.get("file_state") + vm_managedsaved = "yes" == params.get("vm_managedsaved") + expected_fails = None + expected_match = None + if vm_managedsaved and file_state == 'nonexist': + expected_fails = 'No such file or directory' + if vm_managedsaved and file_state != 'nonexist': + expected_match = 'Removed managedsave image' + if not vm_managedsaved: + expected_match = 'removal skipped' + + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + bk_xml = vmxml.copy() + + try: + LOG.info("Step1: Setup before the managedsave-remove and " + "check vm state:") + setup() + # check VM's status after setup, managedsave vm should + # be inactive with "saved" states. + dom_state = virsh.dom_list("--all --managed-save", + debug=True).stdout.strip().splitlines() + vm_state = str([item for item in dom_state if vm_name in item]) + LOG.info("vm %s state is %s", vm_name, vm_state) + if vm_managedsaved: + if "saved" not in vm_state: + test.fail("The domain state should includes 'saved'!") + else: + LOG.info("Found expected state 'saved' in %s state", vm_name) + else: + if "running" not in vm_state: + test.fail("vm should be running!") + else: + LOG.info("Found expected state 'running' in %s state", vm_name) + LOG.info("Step2: Do managedsave-remove:") + ret = virsh.managedsave_remove(vm_name, debug=True) + LOG.debug("%s", ret) + libvirt.check_result(ret, expected_fails=expected_fails, + expected_match=expected_match) + LOG.info("Step3: Check the vm state:") + dom_state1 = virsh.dom_list("--all --managed-save", + debug=True).stdout.strip().splitlines() + vm_state1 = str([item for item in dom_state1 if vm_name in item]) + LOG.info("vm %s state is %s", vm_name, vm_state1) + # Normally, when vm in 'saved' state, it should be 'shut off' after removal + if vm_managedsaved: + if file_state == 'nonexist' and "saved" not in vm_state1: + test.fail("The domain state should not change!") + if file_state != 'nonexist' and "shut off" not in vm_state1: + test.fail("The domain state should change to 'shut off'!") + else: + if "running" not in vm_state: + test.fail("vm should be running!") + else: + LOG.info("Found expected state 'running' in %s state", vm_name) + LOG.info("step4: Check the saved file") + if os.path.exists(managed_save_file): + LOG.info("The saved file exists: %s", managed_save_file) + if vm_managedsaved or file_state != 'corrupt': + test.fail("There should not be saved file after removal") + else: + LOG.info("Saved file does not exists!") + if vm_managedsaved and file_state == 'nonexist': + virsh.undefine(vm_name, '--managed-save --keep-nvram', debug=True) + finally: + virsh.managedsave_remove(vm_name, debug=True) + if os.path.exists(managed_save_file): + process.run("rm -f %s" % managed_save_file, shell=True, ignore_status=True) + bk_xml.sync() diff --git a/libvirt/tests/src/save_and_restore/restore_from_local_file.py b/libvirt/tests/src/save_and_restore/restore_from_local_file.py index e45d5f42c2b..52398dca326 100644 --- a/libvirt/tests/src/save_and_restore/restore_from_local_file.py +++ b/libvirt/tests/src/save_and_restore/restore_from_local_file.py @@ -57,7 +57,7 @@ def setup_bypass_cache(check_cmd, test): :param test: test instance :return: subprocess instance to run check command """ - sm = software_manager.SoftwareManager() + sm = software_manager.manager.SoftwareManager() if not sm.check_installed('lsof'): test.error("Need to install lsof on host") sp = process.SubProcess(check_cmd, shell=True) diff --git a/libvirt/tests/src/save_and_restore/restore_from_unqualified_file.py b/libvirt/tests/src/save_and_restore/restore_from_unqualified_file.py index 10f8433e99d..a8f4cb90d54 100644 --- a/libvirt/tests/src/save_and_restore/restore_from_unqualified_file.py +++ b/libvirt/tests/src/save_and_restore/restore_from_unqualified_file.py @@ -45,6 +45,7 @@ def run(test, params, env): vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) bkxml = vmxml.copy() try: + process.run('chcon -t qemu_var_run_t "/var/tmp"', ignore_status=True, shell=True) if scenario == 'invalid': process.run(f'echo > {save_path}', shell=True) diff --git a/libvirt/tests/src/save_and_restore/save_to_block.py b/libvirt/tests/src/save_and_restore/save_to_block.py index a0a79b4eeec..532b4592dbf 100644 --- a/libvirt/tests/src/save_and_restore/save_to_block.py +++ b/libvirt/tests/src/save_and_restore/save_to_block.py @@ -1,3 +1,4 @@ +import datetime import logging import re @@ -34,6 +35,10 @@ def run(test, params, env): try: selinux_status = passt.ensure_selinux_enforcing() + # Record time for comparison avc log when finished + start_time = datetime.datetime.now() + unix_ts_start = start_time.timestamp() + LOG.debug('Start time is: %s', start_time) if namespaces: qemu_conf.namespaces = eval(namespaces) libvirtd.restart() @@ -57,12 +62,22 @@ def run(test, params, env): LOG.debug(f'VM state after restore: {vm.state()}') if vm.state() != 'running': test.fail(f'VM should be running after restore, not {vm.state()}') - - avc_denied = process.run("grep -E 'avc:.*denied' /var/log/audit/audit.log", - ignore_status=True).stdout_text.strip() - if avc_denied: - test.fail(f'Got avc denied:\n{avc_denied}') - + # Record time for comparison avc log + end_time = datetime.datetime.now() + unix_ts_end = end_time.timestamp() + LOG.debug('End time is: %s', end_time) + avc_denied_log = process.run("grep -E 'avc:.*denied' /var/log/audit/audit.log", + ignore_status=True).stdout_text.strip() + # Filter matching lines + filtered_lines = [] + for line in avc_denied_log.splitlines(): + match = re.search(r"audit\((\d+\.\d+):\d+\)", line) + if match: + log_ts = float(match.group(1)) + if unix_ts_start <= log_ts <= unix_ts_end: + filtered_lines.append(line.strip()) + if filtered_lines: + test.fail(f'Got avc denied:\n{filtered_lines}') save_base.post_save_check(vm, pid_ping, upsince) virsh.shutdown(vm_name, **VIRSH_ARGS) finally: diff --git a/libvirt/tests/src/save_and_restore/save_to_nfs.py b/libvirt/tests/src/save_and_restore/save_to_nfs.py index cfcdbb6f617..b457310512a 100644 --- a/libvirt/tests/src/save_and_restore/save_to_nfs.py +++ b/libvirt/tests/src/save_and_restore/save_to_nfs.py @@ -68,7 +68,8 @@ def run(test, params, env): os.chmod(save_path, mod) LOG.debug('Make nfs mount dir and mount nfs storage') - os.mkdir(nfs_mount_dir) + if not os.path.exists(nfs_mount_dir): + os.mkdir(nfs_mount_dir) utils_disk.mount('127.0.0.1:' + nfs['export_dir'], nfs_mount_dir, 'nfs', options='rw') diff --git a/libvirt/tests/src/save_and_restore/save_with_options.py b/libvirt/tests/src/save_and_restore/save_with_options.py index fa776edf392..e77555539ca 100644 --- a/libvirt/tests/src/save_and_restore/save_with_options.py +++ b/libvirt/tests/src/save_and_restore/save_with_options.py @@ -3,7 +3,6 @@ import re from avocado.utils import process - from virttest import utils_misc from virttest import utils_package from virttest import virsh @@ -18,6 +17,12 @@ def run(test, params, env): + def check_output(pattern, output, cmd): + msg = f'to find [{pattern}] in {cmd} output' + LOG.debug(f'Expect {msg}') + if not re.search(pattern, output): + test.fail(f'Failed {msg}') + vm_name = params.get('main_vm') vm = env.get_vm(vm_name) @@ -33,7 +38,14 @@ def run(test, params, env): rand_id = utils_misc.generate_random_string(3) save_path = f'/var/tmp/{vm_name}_{rand_id}.save' check_cmd = params.get('check_cmd', '') - check_cmd = check_cmd.format(save_path, save_path) if check_cmd else check_cmd + check_cmd = check_cmd.format( + save_path, save_path) if check_cmd else check_cmd + check_reason = 'yes' == params.get('check_reason', 'no') + check_reason = check_reason and not status_error + check_reason_cmd = params.get('check_reason_cmd') + pattern_running = params.get('pattern_running') + pattern_completed = params.get('pattern_completed') + domst_reason = params.get('domst_reason') vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) bkxml = vmxml.copy() @@ -60,10 +72,24 @@ def run(test, params, env): sp = process.SubProcess(check_cmd, shell=True) sp.start() + if check_reason: + monitor_sp = process.SubProcess(check_reason_cmd, shell=True) + monitor_sp.start() + save_result = virsh.save(vm_name, save_path, options=options, debug=True, virsh_opt=virsh_options) libvirt.check_exit_status(save_result, status_error) + if check_reason: + domjobinfo_output = monitor_sp.get_stdout().decode() + monitor_sp.terminate() + LOG.debug(f'domjobinfo output:\n{domjobinfo_output}') + check_output(pattern_running, domjobinfo_output, 'domjobinfo') + + domjobinfo_completed = virsh.domjobinfo( + vm_name, '--completed', **VIRSH_ARGS).stdout_text + check_output(pattern_completed, domjobinfo_completed, 'domjobinfo') + if status_error: libvirt.check_result(save_result, error_msg) if vm.state() != pre_state: @@ -80,6 +106,12 @@ def run(test, params, env): test.fail(f'Expect content "{expect_msg}" not in output: ' f'{save_output}') + if check_reason: + domst_save = virsh.domstate( + vm_name, '--reason', **VIRSH_ARGS).stdout_text + pattern_save = 'shut off \(saved\)' + check_output(pattern_save, domst_save, 'domstate') + if scenario == 'bypass_cache_opt': output = sp.get_stdout().decode() LOG.debug(f'bypass-cache check output:\n{output}') @@ -103,6 +135,11 @@ def run(test, params, env): timeout=timeout): test.fail(f'VM should be {after_state} after restore, but current ' f'state is {vm.state()}') + if check_reason: + domst_restore = virsh.domstate( + vm_name, '--reason', **VIRSH_ARGS).stdout_text + pattern_restore = f'{pre_state}\s*\({domst_reason}\)' + check_output(pattern_restore, domst_restore, 'domstate') if vm.state() == 'paused': virsh.resume(vm_name, **VIRSH_ARGS) diff --git a/libvirt/tests/src/scalability/define_create_vm_with_more_vcpus.py b/libvirt/tests/src/scalability/define_create_vm_with_more_vcpus.py new file mode 100644 index 00000000000..b237fe482da --- /dev/null +++ b/libvirt/tests/src/scalability/define_create_vm_with_more_vcpus.py @@ -0,0 +1,78 @@ +from virttest import libvirt_version +from virttest import virsh +from virttest.libvirt_xml import vm_xml +from virttest.utils_libvirt import libvirt_vmxml + + +def run(test, params, env): + """ + libvirt should automatically add iommu and ioapic setting + when define/create guest with more than 255 vcpus + """ + libvirt_version.is_libvirt_feature_supported(params) + iommu_dict = eval(params.get("iommu_dict", "{}")) + exp_iommu_dict = eval(params.get("exp_iommu_dict", "{}")) + define_vm = params.get("define_vm", "no") == "yes" + with_ioapic = params.get("with_ioapic", "no") == "yes" + feature_name = params.get("feature_name", "ioapic") + feature_attr = eval(params.get("feature_attr", "[]")) + + vm_name = params.get("main_vm", "avocado-vt-vm1") + vm = env.get_vm(vm_name) + vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) + backup_vmxml = vmxml.copy() + try: + libvirt_vmxml.remove_vm_devices_by_type(vm, "iommu") + vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) + vm_attrs = eval(params.get("vm_attrs", "{}")) + vmxml.setup_attrs(**vm_attrs) + + test.log.info(f"TEST_STEP: Update {feature_name} feature.") + features = vmxml.features + test.log.debug(f"orignal features: {features}") + if features.has_feature(feature_name): + if not with_ioapic: + test.log.debug(f"removing {feature_name}...") + features.remove_feature(feature_name) + else: + if with_ioapic: + test.log.debug(f"Adding {feature_name}...") + features.add_feature(feature_name, *feature_attr) + vmxml.features = features + + if iommu_dict: + test.log.info("TEST_STEP: Define VM with intel iommu device.") + iommu_dev = libvirt_vmxml.create_vm_device_by_type( + "iommu", iommu_dict) + vmxml.add_device(iommu_dev) + vmxml.xmltreefile.write() + test.log.debug(f"vm xml will be updated as below: \n{vmxml}") + if define_vm: + vmxml.sync() + else: + virsh.destroy(vm_name, debug=True) + virsh.undefine(vm_name, options='--nvram', debug=True, ignore_status=False) + virsh.create(vmxml.xml, debug=True, ignore_status=False) + + vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) + features = vmxml.features + test.log.debug(f"features after updating: {features}") + if not features.has_feature(feature_name): + test.fail("Failed to get feature - %s." % feature_name) + + if exp_iommu_dict: + actual_iommu = vm_xml.VMXML.new_from_dumpxml(vm.name)\ + .devices.by_device_tag("iommu")[0].fetch_attrs() + + test.log.debug(f"actual iommu device: {actual_iommu}\n" + f"expected iommu device: {exp_iommu_dict}") + if exp_iommu_dict != actual_iommu: + test.log.warning("iommu device xml comparison failed. " + "Adding alias and try again...") + exp_iommu_dict.update({"alias": {"name": "iommu0"}}) + if exp_iommu_dict != actual_iommu: + test.fail("Incorrect iommu device!") + finally: + if not define_vm: + vm.define(vmxml.xml) + backup_vmxml.sync() diff --git a/libvirt/tests/src/scsi/scsi_command_test_hostdev.py b/libvirt/tests/src/scsi/scsi_command_test_hostdev.py new file mode 100644 index 00000000000..3d5ebe6f298 --- /dev/null +++ b/libvirt/tests/src/scsi/scsi_command_test_hostdev.py @@ -0,0 +1,146 @@ +import ast +import re + +from avocado.utils import process + +from virttest import iscsi +from virttest import utils_package +from virttest.libvirt_xml import vm_xml +from virttest.libvirt_xml.devices import hostdev +from virttest.utils_test import libvirt + + +def run(test, params, env): + """ + SCSI command passthrough test for hostdev scsi device + """ + + def get_scsi_count(guest_cmd=False): + """ + Get the counts pf scsi devices. + + :params guest_cmd: if the command is ran in guest. + :params return: return the count of scsi device. + """ + if guest_cmd: + _, output = vm_session.cmd_status_output("lsscsi") + else: + output = process.run("lsscsi").stdout_text + scsi_device_count = len(re.findall("LIO", output)) + return scsi_device_count + + def create_second_target_by_iscsi(emulated_image, second_target): + """ + This test needs to have two LUNs with same image but not same target name. + The current libvirt.setup_or_cleanup_iscsi() can't cover it. + + :params emulated_image: an image used for iscsi target LUN + :params second_target: the second target name + """ + scsi_device_count = get_scsi_count() + sec_target_params = {'emulated_image': emulated_image, + 'target': second_target, + 'image_size': '1G', + 'enable_authentication': False, + 'iscsi_allow_multipath': 'yes'} + iscsi_dev = iscsi.Iscsi.create_iSCSI(sec_target_params) + iscsi_dev.login() + iscsi_status = get_scsi_count() + if int(iscsi_status) != (int(scsi_device_count) + 1): + test.fail("Prepare the second target fail!") + + def prepare_guest_with_hostdev_devices(vmxml, emulated_image): + """ + Prepare 2 scsi disks and hostdev devices xml. + + :params vmxml: the guest xml + :params emulated_image: an image used for iscsi target LUN + """ + for i in range(2): + if i == 0: + libvirt.setup_or_cleanup_iscsi(is_setup=True, is_login=True, + emulated_image=emulated_image) + else: + create_second_target_by_iscsi(emulated_image, second_target) + cmd = "lsscsi | grep LIO | awk '{print $1}' | awk -F '[:[]' '{print $2}' | tail -n 1" + scsi_host_num = process.run(cmd, shell=True, ignore_status=False).stdout_text.split()[0] + hostdev_dict = eval(params.get("hostdev_dict", "{}") % scsi_host_num) + hostdev_xml = hostdev.Hostdev() + hostdev_xml.setup_attrs(**hostdev_dict) + libvirt.add_vm_device(vmxml, hostdev_xml) + vmxml.sync() + test.log.debug("The current guest xml is: %s", vmxml) + + def setup_multipath_service(vm_session): + """ + Setup multipath service in guest. + + :params vm_session: the vm session + :params return: return the mpath disk name in guest + """ + mpath_conf_path = params.get("mpath_conf_path", "/etc/multipath.conf ") + pkg_list = ast.literal_eval(params.get("pkg_list")) + if not utils_package.package_install(pkg_list, vm_session): + test.fail("Failed to install %s package on guest!" % pkg_list) + vm_session.cmd("touch %s" % mpath_conf_path) + conf_in_guest = ( + "cat < %s\n" + "defaults {\n" + " user_friendly_names yes\n" + " find_multipaths yes\n" + " no_path_retry fail\n" + " enable_foreign '^$'\n" + " reservation_key file\n" + "}\n" + "EOF" + ) % mpath_conf_path + vm_session.cmd(conf_in_guest) + vm_session.cmd("systemctl restart multipathd") + status, output = vm_session.cmd_status_output("multipath -ll") + if status or ("active" not in output): + test.fail("Setup multipath service failed!") + mpath_dev = re.search(r"mpath[a-z]", output).group(0) + test.log.debug("The multipath disk in guest is %s.", mpath_dev) + return mpath_dev + + vm_name = params.get("main_vm", "avocado-vt-vm1") + vm = env.get_vm(vm_name) + emulated_image = params.get("emulated_image") + second_target = params.get("second_target") + vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) + backup_xml = vmxml.copy() + + try: + test.log.info("TEST_STEP1: start the guest with two hostdev devices.") + prepare_guest_with_hostdev_devices(vmxml, emulated_image) + vm.start() + test.log.info("TEST_STEP2: check the scsi disks in guest.") + vm_session = vm.wait_for_serial_login() + scsi_device_count = get_scsi_count(guest_cmd=True) + if int(scsi_device_count) != 2: + test.fail("Can't get the expected scsi disks in guest!") + test.log.info("TEST_STEP3: setup multipath service in guest.") + mpath_dev = setup_multipath_service(vm_session) + + test.log.info("TEST_STEP4: send the scsi commands to scsi disk.") + for cmd in [ + "mpathpersist --out --register-ignore --param-sark 123aaa /dev/mapper/%s" % mpath_dev, + "mpathpersist --out --reserve --param-rk 123aaa --prout-type 5 /dev/mapper/%s" % mpath_dev, + "mpathpersist --in -k /dev/mapper/%s" % mpath_dev, + "mpathpersist --in -r /dev/mapper/%s" % mpath_dev, + "mpathpersist --out --release --param-rk 123aaa --prout-type 5 /dev/mapper/%s" % mpath_dev, + "mpathpersist --out --register --param-rk 123aaa --prout-type 5 /dev/mapper/%s" % mpath_dev + ]: + status, output = vm_session.cmd_status_output(cmd) + if status: + test.fail("Send scsi commands to scsi disk failed with message %s!" % output) + test.log.debug("Send scsi commands successfully!") + vm_session.close() + finally: + if vm.is_alive(): + vm.destroy() + backup_xml.sync() + libvirt.setup_or_cleanup_iscsi(is_setup=False) + if second_target in process.run("targetcli ls").stdout_text: + iscsi.iscsi_logout(second_target) + process.run("targetcli /iscsi/ delete %s" % second_target, shell=True) diff --git a/libvirt/tests/src/scsi/scsi_controller_driver_plug_unplug.py b/libvirt/tests/src/scsi/scsi_controller_driver_plug_unplug.py new file mode 100644 index 00000000000..64e95a8ee47 --- /dev/null +++ b/libvirt/tests/src/scsi/scsi_controller_driver_plug_unplug.py @@ -0,0 +1,201 @@ +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Copyright Red Hat +# +# SPDX-License-Identifier: GPL-2.0 + +# Author: Dan Zheng +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +import time + +from virttest import virsh + +from virttest.libvirt_xml.devices.controller import Controller +from virttest.libvirt_xml import vm_xml +from virttest.utils_libvirt import libvirt_pcicontr +from virttest.utils_test import libvirt + + +def prepare_vm_xml(params, test): + """ + Prepare vm xml for the test + + :param params: dict, test parameters + :param test: test object + """ + iothread_num = params.get('iothread_num') + iothread_id = params.get('iothread_id') + vm_name = params.get("main_vm") + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + devices = vmxml.get_devices() + controllers = vmxml.get_devices(device_type='controller') + for one_device in controllers: + if one_device.type == 'scsi': + test.log.debug("Remove the existing scsi controller") + devices.remove(one_device) + vmxml.set_devices(devices) + if iothread_num: + vmxml.setup_attrs(iothreads=int(iothread_num), iothreadids={'iothread': [{'id': iothread_id}]}) + vmxml.sync() + libvirt_pcicontr.reset_pci_num(vm_name) + test.log.debug("The VM xml after preparation:" + "\n%s", vm_xml.VMXML.new_from_inactive_dumpxml(vm_name)) + + +def check_dumpxml(vm_name, options, controllers_dicts, expect_exist, test): + """ + Check vm xml by virsh dumpxml + + :param vm_name: str, vm name + :param options: str, virsh dumpxml options + :param controllers_dicts: dict, controller's configurations + :param expect_exist: boolean, True if expect existence, otherwise False + :param test: test object + """ + vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name, options=options) + controllers = vmxml.get_devices(device_type="controller") + for one_ctl_dict in controllers_dicts: + found = False + for one_ctl in controllers: + if (one_ctl.type == one_ctl_dict['type'] and + one_ctl.model == one_ctl_dict['model'] and + one_ctl.index == one_ctl_dict['index']): + found = True + break + if found != expect_exist: + test.fail("Expect controller (%s) %s exist " + "in vm xml" % (one_ctl_dict, + '' if expect_exist else 'not')) + test.log.debug("Verify controller (%s) in VM " + "xml - PASS", one_ctl_dict) + + +def _create_controllers(params): + """ + Create controllers for the tests + + :param params: dict, test parameters + :return: tuple, (list of controller objects, + list of controller parameters) + """ + contr_indexes = eval(params.get('contr_index')) + iothread_id = params.get('iothread_id') + same_address = eval(params.get('same_address', '{}')) + controller_dicts = [] + controllers = [] + for an_index in contr_indexes: + controller_dict = params.get('controller_dict') + controller_dict = eval(controller_dict % an_index) + if iothread_id: + controller_dict['driver'] = {'iothread': '%s' % iothread_id} + if same_address: + controller_dict['address'] = {'attrs': same_address} + ctrl = Controller(type_name=controller_dict['type']) + ctrl.setup_attrs(**controller_dict) + controller_dicts.append(controller_dict) + controllers.append(ctrl) + return (controllers, controller_dicts) + + +def test_default(vm_name, params, test): + """ + The common test function for plug and unplug + + :param vm_name: str, vm name + :param params: dict, test parameters + :param test: test object + """ + virsh_dargs = {'ignore_status': False, 'debug': True} + controllers, controller_dicts = _create_controllers(params) + for ctrl in controllers: + test.log.info("Step: Coldplug a controller %s", ctrl) + virsh.attach_device(vm_name, ctrl.xml, flagstr='--config', **virsh_dargs) + check_dumpxml(vm_name, '--inactive', controller_dicts, True, test) + for ctrl in controllers: + test.log.info("Step: Hotplug a controller %s", ctrl) + virsh.attach_device(vm_name, ctrl.xml, **virsh_dargs) + check_dumpxml(vm_name, '', controller_dicts, True, test) + for ctrl in controllers: + test.log.info("Step: Coldunplug a controller %s", ctrl) + virsh.detach_device(vm_name, ctrl.xml, flagstr='--config', **virsh_dargs) + time.sleep(10) + check_dumpxml(vm_name, '--inactive', controller_dicts, False, test) + for ctrl in controllers: + test.log.info("Step: Hotunplug a controller %s", ctrl) + virsh.detach_device(vm_name, ctrl.xml, **virsh_dargs) + time.sleep(10) + check_dumpxml(vm_name, '', controller_dicts, False, test) + + +def test_two_contrs_with_driver_hotplug_same_index(vm_name, params, test): + """ + Test hot plug with two controllers with driver in same index + + :param vm_name: str, vm name + :param params: dict, test parameters + :param test: test object + """ + virsh_dargs = {'ignore_status': False, 'debug': True} + same_index = params.get('same_index') + params['contr_index'] = '[%s, %s]' % (same_index, same_index) + controllers, _ = _create_controllers(params) + test.log.info("Step: Hotplug a controller %s", controllers[0]) + virsh.attach_device(vm_name, controllers[0].xml, **virsh_dargs) + virsh_dargs.update({'ignore_status': True}) + test.log.info("Step: Hotplug a controller %s", controllers[1]) + ret = virsh.attach_device(vm_name, controllers[1].xml, **virsh_dargs) + err_msg = params.get('err_msg') + libvirt.check_result(ret, expected_fails=err_msg) + + +def test_two_contrs_with_driver_hotplug_same_address(vm_name, params, test): + """ + Test hot plug with two controllers with driver in same address + + :param vm_name: str, vm name + :param params: dict, test parameters + :param test: test object + """ + virsh_dargs = {'ignore_status': False, 'debug': True} + controllers, _ = _create_controllers(params) + test.log.info("Step: Hotplug a controller %s", controllers[0]) + virsh.attach_device(vm_name, controllers[0].xml, **virsh_dargs) + virsh_dargs.update({'ignore_status': True}) + test.log.info("Step: Hotplug a controller %s", controllers[1]) + ret = virsh.attach_device(vm_name, controllers[1].xml, **virsh_dargs) + err_msg = params.get('err_msg') + libvirt.check_result(ret, expected_fails=err_msg) + + +def run(test, params, env): + """ + Test scsi controller plug unplug operations with different configurations. + + 1.Prepare VM xml. + 2.Do plug unplug scsi controller + 3.Check the test result. + """ + vm_name = params.get("main_vm") + vm = env.get_vm(vm_name) + vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) + vmxml_backup = vmxml.copy() + + contr_num = params.get("contr_num") + driver_config = params.get("driver_config") + test_scenario = params.get("scenarios") + case_name = "test_%s_%s_%s" % (contr_num, driver_config, test_scenario) + run_test_case = eval(case_name) if case_name in globals() else test_default + + try: + test.log.info("Step: Prepare the VM xml") + prepare_vm_xml(params, test) + test.log.info("Step: Start the VM") + vm.start() + vm.wait_for_login().close() + run_test_case(vm_name, params, test) + finally: + if vm.is_alive(): + virsh.destroy(vm_name) + vmxml_backup.sync() diff --git a/libvirt/tests/src/scsi/scsi_device.py b/libvirt/tests/src/scsi/scsi_device.py index 7ec802f4bd2..f4911571431 100644 --- a/libvirt/tests/src/scsi/scsi_device.py +++ b/libvirt/tests/src/scsi/scsi_device.py @@ -486,6 +486,7 @@ def test_coldplug_scsi_hostdev_qemu_pr_helper(test, params, env): :param env: environment instance """ vm_name = params.get("main_vm") + _ = env.get_vm(vm_name) block_device = setup_scsi_debug_block_device() disk_src_dict = {"attrs": {"dev": block_device}} @@ -611,6 +612,8 @@ def run(test, params, env): params.pop('boot_order') try: + # Load sg module + process.run("modprobe sg", shell=True, ignore_status=True, verbose=True) run_test_case(test, params, env) if coldplug: vm.start() diff --git a/libvirt/tests/src/scsi/scsi_disk_attributes.py b/libvirt/tests/src/scsi/scsi_disk_attributes.py new file mode 100644 index 00000000000..24dd7bdb6cd --- /dev/null +++ b/libvirt/tests/src/scsi/scsi_disk_attributes.py @@ -0,0 +1,56 @@ +from avocado.utils import process + +from virttest import virsh +from virttest import utils_disk +from virttest.libvirt_xml import vm_xml +from virttest.utils_libvirt import libvirt_vmxml, libvirt_disk +from virttest.utils_test import libvirt + + +def run(test, params, env): + """ + This case is to verify starting the guest with scsi disk with different attributes. + """ + def check_result(): + """ + Check the result in host and guest. + """ + test.log.debug("The current guest xml is %s", virsh.dumpxml(vm_name).stdout_text) + test.log.info("TEST_STEP2: check the guest xml.") + xml_after_adding_device = vm_xml.VMXML.new_from_dumpxml(vm_name) + libvirt_vmxml.check_guest_xml_by_xpaths(xml_after_adding_device, expected_xpaths) + test.log.info("TEST_STEP3: check the result in host and guest.") + vm_session = vm.wait_for_login() + cap_result = process.run("getpcaps `pidof qemu-kvm`", shell=True).stdout_text.strip() + new_disk = libvirt_disk.get_non_root_disk_name(vm_session)[0] + utils_disk.dd_data_to_vm_disk(vm_session, new_disk) + _, sg_result = vm_session.cmd_status_output("sg_persist -v /dev/%s" % new_disk) + vm_session.close() + if rawio_value == "yes": + if "cap_sys_rawio" not in cap_result or "registered reservation keys" not in sg_result: + test.fail("The rawio capability doesn't work as expected.") + if rawio_value == "no": + if "cap_sys_rawio" in cap_result or "aborted command" not in sg_result.lower(): + test.fail("Shouldn't get the rawio capability.") + + vm_name = params.get("main_vm") + vm = env.get_vm(vm_name) + disk_type = params.get("disk_type") + rawio_value = params.get("rawio_value") + expected_xpaths = eval(params.get("expected_xpaths")) + + vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) + backup_xml = vmxml.copy() + + try: + test.log.info("TEST_STEP1: start the guest with scsi disk.") + device_name = libvirt.setup_or_cleanup_iscsi(is_setup=True) + disk_dict = eval(params.get("disk_dict", "{}") % device_name) + disk_obj = libvirt_vmxml.create_vm_device_by_type("disk", disk_dict) + libvirt.add_vm_device(vmxml, disk_obj) + if not vm.is_alive(): + vm.start() + check_result() + finally: + backup_xml.sync() + libvirt.setup_or_cleanup_iscsi(is_setup=False) diff --git a/libvirt/tests/src/libvirt_rng.py b/libvirt/tests/src/security/rng/libvirt_rng.py similarity index 51% rename from libvirt/tests/src/libvirt_rng.py rename to libvirt/tests/src/security/rng/libvirt_rng.py index 58395f87d1c..3956c4ce50a 100644 --- a/libvirt/tests/src/libvirt_rng.py +++ b/libvirt/tests/src/security/rng/libvirt_rng.py @@ -16,6 +16,7 @@ from virttest import utils_misc from virttest import libvirt_version from virttest.utils_test import libvirt +from virttest.utils_version import VersionInterval from virttest.libvirt_xml import vm_xml from virttest.libvirt_xml import xcepts from virttest.libvirt_xml.devices import rng @@ -23,7 +24,8 @@ # Using as lower capital is not the best way to do, but this is just a # workaround to avoid changing the entire file. -logging = log.getLogger('avocado.' + __name__) +logging = log.getLogger("avocado." + __name__) +background_jobs = [] def run(test, params, env): @@ -38,6 +40,7 @@ def run(test, params, env): """ vm_name = params.get("main_vm") vm = env.get_vm(vm_name) + mem_files = eval(params.get("mem_files", "[]")) def check_rng_xml(xml_set, exists=True): """ @@ -86,38 +89,58 @@ def get_compare_values(xml_set, xml_get, rng_attr): get_value = xml_get[rng_attr] except xcepts.LibvirtXMLNotFoundError: get_value = None - logging.debug("get xml_set value(%s) is %s, get xml_get value is %s", - rng_attr, set_value, get_value) + logging.debug( + "get xml_set value(%s) is %s, get xml_get value is %s", + rng_attr, + set_value, + get_value, + ) return (set_value, get_value) match = True for rng_attr in xml_set.__slots__: set_value, get_value = get_compare_values(xml_set, xml_get, rng_attr) - logging.debug("rng_attr=%s, set_value=%s, get_value=%s", rng_attr, set_value, get_value) + logging.debug( + "rng_attr=%s, set_value=%s, get_value=%s", + rng_attr, + set_value, + get_value, + ) if set_value and set_value != get_value: - if rng_attr == 'backend': + if rng_attr == "backend": for bak_attr in xml_set.backend.__slots__: - set_backend, get_backend = get_compare_values(xml_set.backend, xml_get.backend, bak_attr) + set_backend, get_backend = get_compare_values( + xml_set.backend, xml_get.backend, bak_attr + ) if set_backend and set_backend != get_backend: - if bak_attr == 'source': + if bak_attr == "source": set_source = xml_set.backend.source get_source = xml_get.backend.source find = False for i in range(len(set_source)): for j in get_source: - if set(set_source[i].items()).issubset(j.items()): + if set(set_source[i].items()).issubset( + j.items() + ): find = True break if not find: - logging.debug("set source(%s) not in get source(%s)", - set_source[i], get_source) + logging.debug( + "set source(%s) not in get source(%s)", + set_source[i], + get_source, + ) match = False break else: continue else: - logging.debug("set backend(%s)- %s not equal to get backend-%s", - rng_attr, set_backend, get_backend) + logging.debug( + "set backend(%s)- %s not equal to get backend-%s", + rng_attr, + set_backend, + get_backend, + ) match = False break else: @@ -125,8 +148,12 @@ def get_compare_values(xml_set, xml_get, rng_attr): if not match: break else: - logging.debug("set value(%s)-%s not equal to get value-%s", - rng_attr, set_value, get_value) + logging.debug( + "set value(%s)-%s not equal to get value-%s", + rng_attr, + set_value, + get_value, + ) match = False break else: @@ -135,30 +162,26 @@ def get_compare_values(xml_set, xml_get, rng_attr): break if match: - logging.info("Find same rng xml as hotpluged") + logging.info("Found the same rng xml as hotplugged") else: - test.fail("Rng xml in VM not same with attached xml") + test.fail("Rng xml in VM not same as attached xml") return True - def modify_rng_xml(dparams, sync=True, get_xml=False): + def get_rng_xml(dparams): """ - Modify interface xml options + Get rng device xml :params dparams: parameters for organize xml - :params sync: whether sync to domain xml, if get_xml is True, - then sync will not take effect - :params get_xml: whether get device xml - :return: if get_xml=True, return xml file + :return: return rng xml file """ rng_model = dparams.get("rng_model", "virtio") rng_rate = dparams.get("rng_rate") backend_model = dparams.get("backend_model", "random") backend_type = dparams.get("backend_type") backend_dev = dparams.get("backend_dev", "") - backend_source_list = dparams.get("backend_source", - "").split() backend_protocol = dparams.get("backend_protocol") + backend_source_list = dparams.get("backend_source", "").split() rng_alias = dparams.get("rng_alias") device_address = dparams.get("address") vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) @@ -173,8 +196,7 @@ def modify_rng_xml(dparams, sync=True, get_xml=False): if backend_dev: backend.backend_dev = backend_dev if backend_source_list: - source_list = [ast.literal_eval(source) for source in - backend_source_list] + source_list = [ast.literal_eval(source) for source in backend_source_list] backend.source = source_list if backend_protocol: backend.backend_protocol = backend_protocol @@ -184,23 +206,41 @@ def modify_rng_xml(dparams, sync=True, get_xml=False): if with_packed: rng_xml.driver = dict(packed=driver_packed) if device_address: - rng_xml.address = rng_xml.new_rng_address(**{"attrs": ast.literal_eval(device_address)}) + rng_xml.address = rng_xml.new_rng_address( + **{"attrs": ast.literal_eval(device_address)} + ) logging.debug("Rng xml: %s", rng_xml) - if get_xml: - return rng_xml - if sync: + return rng_xml + + def modify_rng_xml(rng_xml, sync_or_edit="sync"): + """ + Modify rng xml + + :params rng_xml: the rng device xml + :params sync_or_edit: "sync" will redefine the VM with the rng + "edit" will edit the VM + """ + if sync_or_edit == "sync": vmxml.add_device(rng_xml) vmxml.xmltreefile.write() vmxml.sync() - else: + elif sync_or_edit == "edit": status = libvirt.exec_virsh_edit( - vm_name, [(r"://s/$/%s" % - re.findall(r"", - str(rng_xml), re.M - )[0].replace("/", "\/"))]) + vm_name, + [ + ( + r"://s/$/%s" + % re.findall(r"", str(rng_xml), re.M)[0].replace( + "/", "\/" + ) + ) + ], + ) if not status: test.fail("Failed to edit vm xml") + else: + test.error(f"Can't modify XML with method '{sync_or_edit}'.") def check_qemu_cmd(dparams): """ @@ -210,9 +250,7 @@ def check_qemu_cmd(dparams): rng_rate = dparams.get("rng_rate") backend_type = dparams.get("backend_type") backend_model = dparams.get("backend_model") - backend_source_list = dparams.get("backend_source", - "").split() - cmd = ("ps -ef | grep %s | grep -v grep" % vm_name) + cmd = "ps -ef | grep %s | grep -v grep" % vm_name logging.debug("Qemu cmd line info:\n") process.run(cmd, ignore_status=True, shell=True) chardev = src_host = src_port = None @@ -222,34 +260,32 @@ def check_qemu_cmd(dparams): chardev = "udp" for bc_source in backend_source_list: source = ast.literal_eval(bc_source) - if "mode" in source and source['mode'] == "connect": - src_host = source['host'] - src_port = source['service'] + if "mode" in source and source["mode"] == "connect": + src_host = source["host"] + src_port = source["service"] result = process.run(cmd, ignore_status=True, shell=True) if result.exit_status: - test.fail("Got error obtaining qemu cmdline:" - " %s" % result.stderr_text) + test.fail("Got error obtaining qemu cmdline: %s" % result.stderr_text) expected_matches = [] if backend_model == "builtin": expected_matches.append("rng-builtin") if chardev and src_host and src_port: - expected_matches.append("chardev %s,.*host=%s,port=%s" - % (chardev, src_host, src_port)) + expected_matches.append( + "chardev %s,.*host=%s,port=%s" % (chardev, src_host, src_port) + ) if rng_model == "virtio": expected_matches.append("%s" % dparams.get("rng_device")) if rng_rate: rate = ast.literal_eval(rng_rate) - expected_matches.append("max-bytes.*%s" % rate['bytes']) - expected_matches.append("period.*%s" % rate['period']) + expected_matches.append("max-bytes.*%s" % rate["bytes"]) + expected_matches.append("period.*%s" % rate["period"]) if with_packed: expected_matches.append("packed.*%s" % driver_packed) - if not all([re.findall(x, result.stdout_text) - for x in expected_matches]): + if not all([re.findall(x, result.stdout_text) for x in expected_matches]): logging.debug("Expected matches: %s" % expected_matches) logging.debug("QEMU cmdline: %s" % result.stdout_text) - test.fail("Can't see rng option" - " in command line. Please check the log.") + test.fail("Can't see rng option in command line. Please check the log.") def check_host(): """ @@ -260,69 +296,38 @@ def check_host(): cmd = "lsof |grep %s" % backend_dev ret = process.run(cmd, ignore_status=True, shell=True) if ret.exit_status or not ret.stdout_text.count("qemu"): - test.fail("Failed to check random device" - " on host, command output: %s" % - ret.stdout_text) + test.fail( + "Failed to check random device" + " on host, command output: %s" % ret.stdout_text + ) - def check_snapshot(bgjob=None): + def check_snapshot(): """ Do snapshot operation and check the results """ - snapshot_name1 = "snap.s1" - snapshot_name2 = "snap.s2" + # we only check_snapshot + snapshot_name = "s2" if not snapshot_vm_running: vm.destroy(gracefully=False) - ret = virsh.snapshot_create_as(vm_name, snapshot_name1, debug=True) + snap_options = params.get("snap_options") + if "--memspec" in snap_options: + snap_options += mem_files[1] + ret = virsh.snapshot_create_as( + vm_name, options=snap_options % snapshot_name, debug=True + ) libvirt.check_exit_status(ret) + snap_info = virsh.snapshot_info(vm_name, snapshot_name, debug=True) + check_snap_info(snap_info) snap_lists = virsh.snapshot_list(vm_name, debug=True) if snapshot_name not in snap_lists: - test.fail("Snapshot %s doesn't exist" - % snapshot_name) + test.fail("Snapshot %s doesn't exist" % snapshot_name) - if snapshot_vm_running: - options = "--force" - else: - options = "" - ret = virsh.snapshot_revert( - vm_name, ("%s %s" % (snapshot_name, options)), debug=True) + ret = virsh.snapshot_revert(vm_name, "s1", debug=True) libvirt.check_exit_status(ret) ret = virsh.dumpxml(vm_name, debug=True) if ret.stdout.strip().count(" %s" % - (virtio_dev, rng_files[1])), - timeout=timeout) + virtio_dev = re.findall("virtio_rng.\d+", rng_avail)[0] + _ = session.cmd_output( + ("echo -n %s > %s" % (virtio_dev, rng_files[1])), timeout=timeout + ) rng_currt = virtio_dev if not rng_currt.count("virtio") or rng_currt not in rng_avail: - test.fail("Failed to check rng file on guest." - " The virtio device is not the current rng device.") + test.fail( + "Failed to check rng file on guest." + " The virtio device is not the current rng device." + ) # Read the random device rng_rate = params.get("rng_rate") # For rng rate test this command and return in a short time # but for other test it will hang - cmd = ("dd if=/dev/hwrng of=rng.test count=100" - " && rm -f rng.test") + cmd = "dd if=/dev/hwrng of=rng.test %s && rm -f rng.test" % dd_throughput try: ret, output = session.cmd_status_output(cmd, timeout=timeout) if ret and expect_fail: @@ -393,6 +418,8 @@ def check_guest(session, expect_fail=False, if expect_fail: test.fail("Still can find rng device in guest") + elif rng_rate: + test.fail("No way to calc rng rate due to dd timeout") else: logging.info("dd cmd do not fail with error") # Check if file have data @@ -406,17 +433,14 @@ def check_guest(session, expect_fail=False, if rng_rate: rate_bytes, rate_period = list(ast.literal_eval(rng_rate).values()) - rate_conf = float(rate_bytes) / (float(rate_period)/1000) - ret = re.search(r"(\d+) bytes.*copied, (\d+.\d+) s", - output, re.M) + rate_conf = float(rate_bytes) / (float(rate_period) / 1000) + ret = re.search(r"(\d+) bytes.*copied, (\d+.\d+) s", output, re.M) if not ret: test.fail("Can't find rate from output") rate_real = float(ret.group(1)) / float(ret.group(2)) - logging.debug("Found rate: %s, config rate: %s", - rate_real, rate_conf) + logging.debug("Found rate: %s, config rate: %s", rate_real, rate_conf) if rate_real > rate_conf * 1.2: - test.fail("The rate of reading exceed" - " the limitation of configuration") + test.fail("The rate of reading exceed the limitation of configuration") if device_num > 1: rng_dev = rng_avail.split() compare_device_numbers(ignored_devices, rng_dev, device_num) @@ -436,9 +460,11 @@ def compare_device_numbers(ignored_devices, rng_dev, device_num): """ filtered_rng_dev = [x for x in rng_dev if x not in ignored_devices] if len(filtered_rng_dev) != device_num: - test.fail("Number of rng devices defined and available does not match.\n" - "Rng devices: %s\n" - "Number of devices: %i" % (rng_dev, device_num)) + test.fail( + "Number of rng devices defined and available does not match.\n" + "Rng devices: %s\n" + "Number of devices: %i" % (rng_dev, device_num) + ) def get_rng_device(guest_arch, rng_model): """ @@ -452,6 +478,16 @@ def get_rng_device(guest_arch, rng_model): else: test.fail("Unknown rng model %s" % rng_model) + def check_snap_info(snap_info): + """ + Check expected content in snapshot info + + :param snap_info: result get from vm snapshot info + """ + snap_state = "running" if snapshot_vm_running else "shutoff" + if snap_info["State"] != snap_state or snap_info["Location"] != "external": + test.fail("Snapshot info about State or Location checking failed!") + def rotate_audit_log(): """ Rotates the audit log so that the current log only contains @@ -459,7 +495,201 @@ def rotate_audit_log(): """ process.run("systemctl kill --signal SIGUSR1 auditd") - start_error = "yes" == params.get("start_error", "no") + def handle_egd_connect_mode(): + """ + Creates source for egd in connect mode, i.e. a server where the VM + connects to when started. + + It ignores external hosts and instead runs everything locally. + + After starting the fake egd in the background, wait a second to make + sure it's up when VM starts. + + Feed entropy from /dev/urandom to avoid blocking. + """ + connect_sources = [ + eval(source) + for source in backend_source_list + if eval(source)["mode"] == "connect" + ] + if not connect_sources: + return + for source in connect_sources: + + connect_port = source["service"] + + if params.get("backend_type") == "tcp" and ( + test_snapshot or (random_source and not test_guest_dump) + ): + cmd = f"cat /dev/urandom | nc -4 -l 127.0.0.1 {connect_port}" + job = utils_misc.AsyncJob(cmd) + background_jobs.append(job) + + if params.get("backend_type") == "udp" and ( + test_snapshot or (random_source and test_guest_dump) + ): + if not utils_package.package_install("socat"): + test.error("Failed to install socat on host") + cmd = f"cat /dev/urandom | socat udp-listen:{connect_port},reuseaddr,fork -" + job = utils_misc.AsyncJob(cmd) + background_jobs.append(job) + + time.sleep(1) + + logging.info(f"{background_jobs}") + for job in background_jobs: + logging.info(f"fake egd: {job.get_stderr()} {job.get_stdout()}") + + def handle_egd_bind_mode(): + """ + Provides entropy to the given port that's listening on the VM. + For test cases that use tcp bind mode only because we can't test + udp bind connect with external server. + + Feed entropy from /dev/urandom to avoid blocking. + """ + if not params.get("backend_type") == "tcp": + return + + if not backend_source_list: + return + + bind_sources = [ + eval(source) + for source in backend_source_list + if eval(source)["mode"] == "bind" + ] + + for source in bind_sources: + time.sleep(3) # extra time for VM to start listening + connect_port = source["service"] + cmd = f"cat /dev/random | nc -4 localhost {connect_port}" + job = utils_misc.AsyncJob(cmd) + background_jobs.append(job) + logging.info(f"fake egd: {job.get_stderr()} {job.get_stdout()}") + + def try_use_rngd(): + """ + Try to install rng-tools on host, it can speed up random rate + if installation failed, ignore the error and continue the test + """ + if utils_package.package_install(["rng-tools"]): + rngd_conf = "/etc/sysconfig/rngd" + rngd_srv = "/usr/lib/systemd/system/rngd.service" + if os.path.exists(rngd_conf): + # For rhel6 host, add extra options + with open(rngd_conf, "w") as f_rng: + f_rng.write('EXTRAOPTIONS="--rng-device /dev/urandom"') + elif os.path.exists(rngd_srv): + # For rhel7 host, modify start options + rngd_srv_conf = "/etc/systemd/system/rngd.service" + if not os.path.exists(rngd_srv_conf): + shutil.copy(rngd_srv, rngd_srv_conf) + process.run( + "sed -i -e 's#^ExecStart=.*#ExecStart=/sbin/rngd" + " -f -r /dev/urandom -o /dev/random#' %s" % rngd_srv_conf, + shell=True, + ) + process.run("systemctl daemon-reload") + process.run("service rngd start") + + def build_vm_xml(): + """ + Build the VM XML. + + :return: rng_xml + """ + rng_xml = None + if device_num > 1: + for i in xrange(device_num): + rng_model = params.get("rng_model_%s" % i, "virtio") + dparams[i] = {"rng_model": rng_model} + dparams[i].update( + {"backend_model": params.get("backend_model_%s" % i, "random")} + ) + dparams[i].update({"rng_device": get_rng_device(guest_arch, rng_model)}) + bk_type = params.get("backend_type_%s" % i) + if bk_type: + dparams[i].update({"backend_type": bk_type}) + bk_dev = params.get("backend_dev_%s" % i) + if bk_dev: + dparams[i].update({"backend_dev": bk_dev}) + bk_src = params.get("backend_source_%s" % i) + if bk_src: + dparams[i].update({"backend_source": bk_src}) + bk_pro = params.get("backend_protocol_%s" % i) + if bk_pro: + dparams[i].update({"backend_protocol": bk_pro}) + rng_xml = get_rng_xml(dparams[i]) + modify_rng_xml(rng_xml, "edit") + else: + params.update( + { + "rng_device": get_rng_device( + guest_arch, params.get("rng_model", "virtio") + ) + } + ) + + if urandom or detach_alias: + device_alias = "ua-" + str(uuid.uuid4()) + params.update({"rng_alias": device_alias}) + + rng_xml = get_rng_xml(params) + if not attach_rng: + sync_or_edit = "edit" if test_snapshot else "sync" + modify_rng_xml(rng_xml, sync_or_edit) + return rng_xml + + def handle_first_snapshot(): + """ + test_snapshot will take two snapshots: + s1: without rng + s2: with rng + """ + if test_snapshot: + snapshot_name = "s1" + if snapshot_vm_running: + vm.start() + vm.wait_for_login().close() + snap_options = params.get("snap_options") + if "--memspec" in snap_options: + snap_options += mem_files[0] + ret = virsh.snapshot_create_as( + vm_name, options=snap_options % snapshot_name, debug=True + ) + libvirt.check_exit_status(ret) + snap_info = virsh.snapshot_info(vm_name, snapshot_name, debug=True) + check_snap_info(snap_info) + + def handle_hotplug(): + """ + Hotplugs device if requested + """ + if attach_rng: + ret = virsh.attach_device( + vm_name, + rng_xml.xml, + flagstr=attach_options, + wait_remove_event=True, + debug=True, + ignore_status=True, + ) + libvirt.check_exit_status(ret, status_error) + if status_error: + return "pass_test_on_error" + if not check_rng_xml(rng_xml, True): + test.fail("Can not find rng device in xml") + return "" + + def remove_all_rng_devices(): + """ + Make sure no extra rng devices interfere. + """ + vmxml.remove_all_device_by_type("rng") + vmxml.sync() + logging.debug("Prepared vm xml without rng dev is %s", vmxml) + expected_create_error = params.get("expected_create_error", "") status_error = "yes" == params.get("status_error", "no") @@ -470,12 +700,10 @@ def rotate_audit_log(): expected_audit_message = params.get("expected_audit_message", "VIRT_RESOURCE") set_virtio_current = "yes" == params.get("set_virtio_current", "no") test_guest_dump = "yes" == params.get("test_guest_dump", "no") + test_guest_rng_file = "yes" == params.get("test_guest_rng_file", "no") test_qemu_cmd = "yes" == params.get("test_qemu_cmd", "no") test_snapshot = "yes" == params.get("test_snapshot", "no") - snapshot_vm_running = "yes" == params.get("snapshot_vm_running", - "no") - snapshot_with_rng = "yes" == params.get("snapshot_with_rng", "no") - snapshot_name = params.get("snapshot_name") + snapshot_vm_running = "yes" == params.get("snapshot_vm_running", "no") device_num = int(params.get("device_num", 1)) ignored_devices = params.get("ignored_devices", "").split(",") detach_alias = "yes" == params.get("rng_detach_alias", "no") @@ -488,147 +716,54 @@ def rotate_audit_log(): with_packed = "yes" == params.get("with_packed", "no") driver_packed = params.get("driver_packed", "on") urandom = "yes" == params.get("urandom", "no") + dd_throughput = params.get("dd_throughput") + backend_source_list = params.get("backend_source", "").split() - if params.get("backend_model") == "builtin" and not libvirt_version.version_compare(6, 2, 0): + if params.get("backend_model") == "builtin" and not libvirt_version.version_compare( + 6, 2, 0 + ): test.cancel("Builtin backend is not supported on this libvirt version") if device_num > 1 and not libvirt_version.version_compare(1, 2, 7): - test.cancel("Multiple virtio-rng devices not " - "supported on this libvirt version") + test.cancel("Multiple virtio-rng devices not supported on this libvirt version") if with_packed and not libvirt_version.version_compare(6, 3, 0): - test.cancel("The virtio packed attribute is not supported in" - " current libvirt version.") + test.cancel( + "The virtio packed attribute is not supported in" + " current libvirt version." + ) guest_arch = params.get("vm_arch_name", "x86_64") - # Back up xml file. - vmxml_backup = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) - logging.debug("vm xml is %s", vmxml_backup) - - # Try to install rng-tools on host, it can speed up random rate - # if installation failed, ignore the error and continue the test - if utils_package.package_install(["rng-tools"]): - rngd_conf = "/etc/sysconfig/rngd" - rngd_srv = "/usr/lib/systemd/system/rngd.service" - if os.path.exists(rngd_conf): - # For rhel6 host, add extra options - with open(rngd_conf, 'w') as f_rng: - f_rng.write('EXTRAOPTIONS="--rng-device /dev/urandom"') - elif os.path.exists(rngd_srv): - # For rhel7 host, modify start options - rngd_srv_conf = "/etc/systemd/system/rngd.service" - if not os.path.exists(rngd_srv_conf): - shutil.copy(rngd_srv, rngd_srv_conf) - process.run("sed -i -e 's#^ExecStart=.*#ExecStart=/sbin/rngd" - " -f -r /dev/urandom -o /dev/random#' %s" - % rngd_srv_conf, shell=True) - process.run('systemctl daemon-reload') - process.run("service rngd start") + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + vmxml_backup = vmxml.copy() - # Build the xml and run test. - try: - bgjob = None - bgjob2 = None + try_use_rngd() + try: if test_audit: rotate_audit_log() - # Prepare xml, make sure no extra rng dev. - vmxml = vmxml_backup.copy() - vmxml.remove_all_device_by_type('rng') - vmxml.sync() - logging.debug("Prepared vm xml without rng dev is %s", vmxml) - - # Take snapshot if needed - if snapshot_name: - if snapshot_vm_running: - vm.start() - vm.wait_for_login().close() - ret = virsh.snapshot_create_as(vm_name, snapshot_name, debug=True) - libvirt.check_exit_status(ret) - - # Destroy VM first - if vm.is_alive(): - vm.destroy(gracefully=False) + remove_all_rng_devices() + handle_first_snapshot() try: - # Build vm xml. dparams = {} - if device_num > 1: - for i in xrange(device_num): - rng_model = params.get("rng_model_%s" % i, "virtio") - dparams[i] = {"rng_model": rng_model} - dparams[i].update({"backend_model": params.get( - "backend_model_%s" % i, "random")}) - dparams[i].update({"rng_device": get_rng_device( - guest_arch, rng_model)}) - bk_type = params.get("backend_type_%s" % i) - if bk_type: - dparams[i].update({"backend_type": bk_type}) - bk_dev = params.get("backend_dev_%s" % i) - if bk_dev: - dparams[i].update({"backend_dev": bk_dev}) - bk_src = params.get("backend_source_%s" % i) - if bk_src: - dparams[i].update({"backend_source": bk_src}) - bk_pro = params.get("backend_protocol_%s" % i) - if bk_pro: - dparams[i].update({"backend_protocol": bk_pro}) - modify_rng_xml(dparams[i], False) - else: - params.update({"rng_device": get_rng_device( - guest_arch, params.get("rng_model", "virtio"))}) - - if detach_alias: - device_alias = "ua-" + str(uuid.uuid4()) - params.update({"rng_alias": device_alias}) - - rng_xml = modify_rng_xml(params, not test_snapshot, attach_rng) - - if urandom: - device_alias = "ua-" + str(uuid.uuid4()) - params.update({"rng_alias": device_alias}) - rng_xml = modify_rng_xml(params, False, True) - vmxml.add_device(rng_xml) - vmxml.sync() + if vm.is_alive(): + vm.destroy(gracefully=False) - # Add tcp random server - if random_source and params.get("backend_type") == "tcp" and not test_guest_dump: - cmd = "cat /dev/random | nc -4 -l localhost 1024" - bgjob = utils_misc.AsyncJob(cmd) + rng_xml = build_vm_xml() - if all([random_source, params.get("backend_type") == "udp", test_guest_dump]): - if not utils_package.package_install("socat"): - test.error("Failed to install socat on host") - cmd1 = "cat /dev/urandom|nc -l 127.0.0.1 1235" - bgjob = utils_misc.AsyncJob(cmd1) - cmd2 = "socat udp-listen:1234,reuseaddr,fork tcp:127.0.0.1:1235" - bgjob2 = utils_misc.AsyncJob(cmd2) + handle_egd_connect_mode() vm.start() - # Wait guest to enter boot stage - time.sleep(3) + virsh.dumpxml(vm_name, "--xpath //rng", debug=True) + time.sleep(3) # Wait guest to enter boot stage - if attach_rng: - ret = virsh.attach_device(vm_name, rng_xml.xml, - flagstr=attach_options, - wait_remove_event=True, - debug=True, ignore_status=True) - libvirt.check_exit_status(ret, status_error) - if status_error: - return - if not check_rng_xml(rng_xml, True): - test.fail("Can not find rng device in xml") - else: - # Start the VM. - if start_error: - test.fail("VM started unexpectedly") + if "pass_test_on_error" == handle_hotplug(): + return - # Feed the tcp random device some data - if test_guest_dump and params.get("backend_type") == "tcp": - cmd = "cat /dev/random | nc -4 localhost 1024" - bgjob = utils_misc.AsyncJob(cmd) + handle_egd_bind_mode() if test_qemu_cmd and not attach_rng: if device_num > 1: @@ -639,22 +774,22 @@ def rotate_audit_log(): if test_host: check_host() if test_audit: - libvirt.check_logfile(expected_audit_message, - audit_log_file) + libvirt.check_logfile(expected_audit_message, audit_log_file) session = vm.wait_for_login() if test_guest: check_guest(session, set_virtio_current=set_virtio_current) if test_guest_dump: check_guest_dump(session, True) if test_snapshot: - check_snapshot(bgjob) + check_snapshot() if urandom: check_rng_xml(rng_xml, True) if detach_alias: - result = virsh.detach_device_alias(vm_name, device_alias, - detach_alias_options, debug=True) + result = virsh.detach_device_alias( + vm_name, params.get("rng_alias"), detach_alias_options, debug=True + ) if "--config" in detach_alias_options: vm.destroy() @@ -672,45 +807,49 @@ def have_rng_xml(): # Detach after attach if attach_rng: - ret = virsh.detach_device(vm_name, rng_xml.xml, - flagstr=attach_options, - debug=True, ignore_status=True) + ret = virsh.detach_device( + vm_name, + rng_xml.xml, + flagstr=attach_options, + debug=True, + ignore_status=True, + ) libvirt.check_exit_status(ret, status_error) - if utils_misc.wait_for(lambda: check_rng_xml(rng_xml, False), wait_timeout): + if utils_misc.wait_for( + lambda: check_rng_xml(rng_xml, False), wait_timeout + ): logging.info("Find same rng xml as hotpluged") else: test.fail("Rng device still exists after detach!") - if test_guest_dump: + if test_guest_rng_file: + check_guest_rng_file(session) + elif test_guest_dump: check_guest_dump(session, False) session.close() except virt_vm.VMStartError as details: logging.info(str(details)) - if not start_error: - test.fail('VM failed to start, ' - 'please refer to https://bugzilla.' - 'redhat.com/show_bug.cgi?id=1220252:' - '\n%s' % details) except xcepts.LibvirtXMLError as details: logging.info(str(details)) - if expected_create_error not in str(details): - test.fail("Didn't find expected error:" - " %s" % expected_create_error) + details = str(details).replace("\n", "") + if not re.match(expected_create_error, details): + test.fail("Didn't match expected error: %s" % expected_create_error) finally: # Delete snapshots. snapshot_lists = virsh.snapshot_list(vm_name, debug=True) if len(snapshot_lists) > 0: libvirt.clean_up_snapshots(vm_name, snapshot_lists) - for snapshot in snapshot_lists: - virsh.snapshot_delete(vm_name, snapshot, "--metadata", debug=True) - + for snapshot in reversed(snapshot_lists): + virsh.snapshot_delete(vm_name, snapshot, "", debug=True) + if mem_files: + for memspec in mem_files: + if os.path.exists(memspec): + os.remove(memspec) # Recover VM. if vm.is_alive(): vm.destroy(gracefully=False) logging.info("Restoring vm...") vmxml_backup.sync() - if bgjob2: - bgjob2.kill_func() - if bgjob: - bgjob.kill_func() + for job in background_jobs: + job.kill_func() diff --git a/libvirt/tests/src/virtual_device/virtio_rng.py b/libvirt/tests/src/security/rng/virtio_rng.py similarity index 100% rename from libvirt/tests/src/virtual_device/virtio_rng.py rename to libvirt/tests/src/security/rng/virtio_rng.py diff --git a/libvirt/tests/src/security/virt_what_cvm.py b/libvirt/tests/src/security/virt_what_cvm.py new file mode 100644 index 00000000000..24299023dd5 --- /dev/null +++ b/libvirt/tests/src/security/virt_what_cvm.py @@ -0,0 +1,27 @@ +import logging as log + +from virttest import utils_misc, utils_package + + +logging = log.getLogger("avocado." + __name__) + + +def run(test, params, env): + """ + Confirms that the output of virt-what-cvm is as expected. + + :params test: The avocado test object + :params params: Parameters for the test + :params env: The avocado test environment object + """ + vm_name = params.get("main_vm") + vm = env.get_vm(vm_name) + expected_cvm = params.get("expected_cvm") + session = vm.wait_for_login() + utils_package.package_install("virt-what", session=session) + _, o = utils_misc.cmd_status_output("virt-what-cvm", session=session) + if o.strip() != expected_cvm.strip(): + test.fail( + f"Unexpected value '{o.strip()}' instead of {expected_cvm.strip()}." + " Note that the command is supported since virt-what-1.25-10." + ) diff --git a/libvirt/tests/src/serial/serial_functional.py b/libvirt/tests/src/serial/serial_functional.py index d143a64d9b2..2fbcb748434 100644 --- a/libvirt/tests/src/serial/serial_functional.py +++ b/libvirt/tests/src/serial/serial_functional.py @@ -23,6 +23,7 @@ from virttest import libvirt_version from avocado.utils import astring +from avocado.utils import process # Using as lower capital is not the best way to do, but this is just a @@ -737,6 +738,7 @@ def get_console_type(): elif serial_type in ['pipe']: return 'server' + libvirt_version.is_libvirt_feature_supported(params) serial_type = params.get('serial_dev_type', 'pty') sources_str = params.get('serial_sources', '') username = params.get('username') @@ -746,6 +748,7 @@ def get_console_type(): target_model = params.get('target_model', '') console_target_port = params.get('console_target_port', '0') second_serial_console = params.get('second_serial_console', 'no') == 'yes' + connect_to_console_without_serial_device = params.get('connect_to_console_without_serial_device', 'no') == 'yes' custom_pki_path = params.get('custom_pki_path', '/etc/pki/libvirt-chardev') auto_recover = params.get('auto_recover', 'no') client_pwd = params.get('client_pwd', None) @@ -821,6 +824,12 @@ def get_console_type(): if console_type == 'server': console = prepare_serial_console() + if connect_to_console_without_serial_device: + libvirt_version.is_libvirt_feature_supported(params) + for device_type in remove_devices: + vm_xml.remove_all_device_by_type(device_type) + vm_xml.sync() + res = virsh.start(vm_name) libvirt.check_result(res, expected_fails, []) if res.exit_status: @@ -835,8 +844,28 @@ def get_console_type(): console_type != 'server'): check_serial_console(console, username, password) + if connect_to_console_without_serial_device: + time.sleep(20) + # use raw virsh console command since we need to output message from virsh console VM + res = process.run("virsh console %s" % vm_name, shell=True, verbose=True, ignore_status=True) + error_msgs = params.get("error_msg") + libvirt.check_result(res, error_msgs) + + if params.get("hotunplug_serial", "no") == "yes": + error_msg = params.get("error_msg", "").format("detach") + res = virsh.detach_device(vm_name, serial_dev.xml, debug=True) + libvirt.check_result(res, error_msg) + + if params.get("hotplug_serial", "no") == "yes": + error_msg = params.get("error_msg", "").format("hotplug") + res = virsh.attach_device(vm_name, serial_dev.xml, debug=True) + libvirt.check_result(res, error_msg) + vm.destroy() finally: + # Recover VM. + if vm.is_alive(): + vm.destroy(gracefully=False) cleanup(objs_list) vm_xml_backup.sync() diff --git a/libvirt/tests/src/serial/serial_pty_log.py b/libvirt/tests/src/serial/serial_pty_log.py index 62451f3f3ae..ce49ebc231c 100644 --- a/libvirt/tests/src/serial/serial_pty_log.py +++ b/libvirt/tests/src/serial/serial_pty_log.py @@ -27,10 +27,10 @@ def check_pty_log_file(file_path, boot_prompt): with open(file_path, errors='ignore') as fp: contents = fp.read() logging.debug("The contents of log file are : %s" % contents) - ret = contents.find(boot_prompt) - if ret == -1: - return False - return True + ret = [] + for prompt in boot_prompt.split(','): + ret.append(contents.find(prompt) != -1) + return any(ret) def run(test, params, env): @@ -97,7 +97,7 @@ def update_qemu_conf(): # Need to wait for a while to get login prompt if not utils_misc.wait_for( - lambda: check_pty_log_file(log_file, boot_prompt), 6): + lambda: check_pty_log_file(log_file, boot_prompt), 15): test.fail("Failed to find the vm login prompt from %s" % log_file) except Exception as e: diff --git a/libvirt/tests/src/snapshot/check_delete_and_revert_snap_event_in_multiple_branch.py b/libvirt/tests/src/snapshot/check_delete_and_revert_snap_event_in_multiple_branch.py new file mode 100644 index 00000000000..2523562ec3d --- /dev/null +++ b/libvirt/tests/src/snapshot/check_delete_and_revert_snap_event_in_multiple_branch.py @@ -0,0 +1,155 @@ +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Copyright Redhat +# +# SPDX-License-Identifier: GPL-2.0 + +# Author: Nannan Li +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +import re + +from virttest import libvirt_version +from virttest import virsh +from virttest.libvirt_xml import vm_xml +from virttest.utils_libvirt import libvirt_disk + +from provider.snapshot import snapshot_base + +virsh_dargs = {"debug": True, "ignore_status": False} + + +def check_event_output(test, pattern, event_session, expect_exist=True): + """ + Check event output. + + :param test: test object + :param pattern: the check event pattern, list type + :param event_session: event session to get event output + :param expect_exist: expect the pattern exist or not + """ + output = virsh.EventTracker.finish_get_event(event_session) + event_session.close() + for check_patt in pattern: + is_existed = bool(re.findall(check_patt, output)) + if is_existed != expect_exist: + test.fail('Expect %s to get: %s from the event output:%s' % ( + '' if expect_exist else 'not', check_patt, output)) + else: + test.log.debug("Check event %s success in the event output", check_patt) + + +def delete_snap_and_check_event(test, params, del_snap, expected_event, + expect_exist=True): + """ + Delete snap and check expected event + + :param test: test object. + :param params: wrapped dict with all parameters + :param del_snap: the snapshot to be deleted + :param expected_event: expected event value + :param expect_exist: expected event exist or not. + """ + vm_name = params.get("main_vm") + + event_session = virsh.EventTracker.start_get_event(vm_name) + virsh.snapshot_delete(vm_name, del_snap, **virsh_dargs) + check_event_output(test, expected_event, event_session, expect_exist) + + +def run(test, params, env): + """ + :params test: test object + :params params: wrapped dict with all parameters + :params env: test object + """ + def setup_test(): + """ + Prepare the parent external snapshot with multiple children. + snapshot tree is like this + s1 + | + +- s2 + | | + | +- s3 + | + +- s4 + | + +- s5 + """ + test.log.info("TEST_SETUP: Prepare the parent external snapshot " + "with multiple children:") + virsh.start(vm_name) + vm.wait_for_login().close() + for sname in snap_names: + virsh.snapshot_create_as(vm.name, snap_options % (sname, sname, sname), + **virsh_dargs) + if sname == 's3': + virsh.snapshot_revert(vm_name, snap_names[0], **virsh_dargs) + + virsh.snapshot_list(vm_name, **virsh_dargs, options='--tree') + res = virsh.snapshot_current(vm_name, **virsh_dargs).stdout.strip() + if res != snap_names[-1]: + test.fail("Expect the current snap name is '%s' instead of" + " '%s'" % (snap_names[-1], res)) + + def run_test(): + """ + Delete the snapshots of current branch. + """ + test.log.info("TEST_STEP1,2,3: Delete the snap of active chain " + "and check event.") + delete_snap_and_check_event(test, params, snap_names[-1], del_event) + + test.log.info("TEST_STEP4: Revert the snap of inactive chain " + "and check event.") + event_session = virsh.EventTracker.start_get_event(vm_name) + virsh.snapshot_revert(vm_name, snap_names[1], **virsh_dargs) + check_event_output(test, revert_event, event_session) + + test.log.info("TEST_STEP5: Delete the third snap and check event.") + delete_snap_and_check_event(test, params, snap_names[2], + del_event, expect_exist=False) + + test.log.info("TEST_STEP6: Delete the third snap and check event.") + delete_snap_and_check_event(test, params, snap_names[3], + del_event, expect_exist=False) + + test.log.info("TEST_STEP7: Delete the first snap and check event.") + delete_snap_and_check_event(test, params, snap_names[0], + del_event) + + test.log.info("TEST_STEP8: Delete the first snap and check event.") + delete_snap_and_check_event(test, params, snap_names[1], + [del_event[1]] + extra_del_devent) + + def teardown_test(): + """ + Clean data. + """ + test.log.info("TEST_TEARDOWN: Clean up env.") + snap_names.reverse() + test_obj.virsh_dargs = {'ignore_status': True, 'debug': True} + test_obj.delete_snapshot(snap_names) + bkxml.sync() + + vm_name = params.get("main_vm") + bkxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + vm = env.get_vm(vm_name) + + snap_options = params.get("snap_options") + snap_names = eval(params.get("snap_names")) + del_event = eval(params.get("del_event")) + disk_source = libvirt_disk.get_first_disk_source(vm) + extra_del_devent = eval(params.get("extra_del_devent") % disk_source) + revert_event = eval(params.get("revert_event1"))+eval(params.get("revert_event2")) + + test_obj = snapshot_base.SnapshotTest(vm, test, params) + libvirt_version.is_libvirt_feature_supported(params) + + try: + setup_test() + run_test() + + finally: + teardown_test() diff --git a/libvirt/tests/src/snapshot/delete_disk_and_memory_snapshot.py b/libvirt/tests/src/snapshot/delete_disk_and_memory_snapshot.py new file mode 100644 index 00000000000..5d6f1f75a35 --- /dev/null +++ b/libvirt/tests/src/snapshot/delete_disk_and_memory_snapshot.py @@ -0,0 +1,179 @@ +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Copyright Redhat +# +# SPDX-License-Identifier: GPL-2.0 + +# Author: Nannan Li +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +import os.path + +from virttest import virsh +from virttest import libvirt_version +from virttest import utils_disk +from virttest.libvirt_xml import vm_xml +from virttest.utils_libvirt import libvirt_disk + +from provider.backingchain import blockcommand_base +from provider.backingchain import check_functions +from provider.virtual_disk import disk_base +from provider.snapshot import snapshot_base + +virsh_dargs = {"debug": True, "ignore_status": False} + + +def write_file(vm, params, file_name, format_disk=False): + """ + Write file to target disk + + :param vm: vm object. + :param params: Dictionary with the test parameters. + :param file_name: file name. + :param format_disk: only format disk for one time in vm. + """ + vm_status = params.get("vm_status") + target_disk = params.get("target_disk") + + if vm_status == "vm_paused" and vm.state() != "running": + virsh.resume(vm.name, **virsh_dargs) + session = vm.wait_for_login() + if format_disk: + cmd = "mkfs.ext4 /dev/%s;mount /dev/%s /mnt" % ( + target_disk, target_disk) + session.cmd_status_output(cmd) + utils_disk.dd_data_to_vm_disk(session, file_name, bs='1M', + count='2') + session.close() + + +def check_after_deleting_snap(test, vm, params, expected_hash, del_snap): + """ + Check two disks xml, guest file hash value, snapshot memory file. + + :param test: test object. + :param vm: vm object. + :param params: Dictionary with the test parameters. + :param expected_hash: expected file hash value in guest. + :param del_snap: the deleted snap order in snap names. + """ + disk_type = params.get("disk_type") + target_disk = params.get("target_disk") + file_path = params.get("file_path") + vm_status = params.get("vm_status") + check_obj = check_functions.Checkfunction(test, vm, params) + mem_file = params.get("mem_files")[int(del_snap)-1] + expected_source_len = 2 if del_snap == "1" else 1 + if vm_status == "vm_paused" and vm.state() != "running": + virsh.resume(vm.name, **virsh_dargs) + + vmxml = vm_xml.VMXML.new_from_dumpxml(vm.name) + new_disk_sources = disk_base.DiskBase.get_source_list( + vmxml, disk_type, target_disk) + + if len(new_disk_sources) != expected_source_len: + test.fail("New disk source list length should be %s, instead of %s " % + (new_disk_sources, expected_source_len)) + + new_source = libvirt_disk.get_first_disk_source(vm) + if params.get("original_disk_source") != new_source: + test.fail("Disk source should not change to %s" % new_source) + + session = vm.wait_for_login() + check_obj.check_hash_list([file_path], [expected_hash], session=session) + session.close() + + if os.path.exists(mem_file): + test.fail("The snap memory file %s is existed " % mem_file) + test.log.debug("Checking disks xml, file hash value, and snapshot " + "memory file were successful.") + + +def run(test, params, env): + """ + :params test: test object + :params params: wrapped dict with all parameters + :params env: test object + """ + def run_test(): + """ + Verify snapshot-delete disk and memory snapshot. + """ + test.log.info("TEST_STEP1: Attach a new disk to guest.") + vm.start() + vm.wait_for_login().close() + new_disk, _ = disk_obj.prepare_disk_obj(disk_type, disk_dict) + virsh.attach_device(vm_name, new_disk.xml, **virsh_dargs) + + test.log.info("TEST_STEP2: Mount new disk and write random data.") + write_file(vm, params, file_name=file_path, format_disk=True) + + test.log.info("TEST_STEP3,4: Create the 1st snapshot with snapshot xml") + if vm_status == "vm_paused": + virsh.suspend(vm_name, **virsh_dargs) + test_obj.create_snapshot_by_xml( + eval(snapshot_dict % (snap_names[0], params.get("mem_files")[0])), + eval(snapshot_disk_list % snap_file1)) + + test.log.info("TEST_STEP5: Write random data to new disk again.") + write_file(vm, params, file_name=file_path) + + test.log.info("TEST_STEP6,7:Create the 2nd snapshot with snapshot xml.") + if vm_status == "vm_paused": + virsh.suspend(vm_name, **virsh_dargs) + test_obj.create_snapshot_by_xml( + eval(snapshot_dict % (snap_names[1], params.get("mem_files")[1])), + eval(snapshot_disk_list % snap_file2)) + + test.log.info("TEST_STEP8: Write random data to new disk again.") + write_file(vm, params, file_name=file_path) + expected_hash, _ = block_obj.get_hash_value(check_item=file_path) + + test.log.info("TEST_STEP9: Update vm status.") + if vm_status == "vm_paused": + virsh.suspend(vm_name, **virsh_dargs) + + test.log.info("TEST_STEP10: Delete the 1st snapshot and check xml.") + virsh.snapshot_delete(vm_name, snap_names[0], **virsh_dargs) + check_after_deleting_snap(test, vm, params, expected_hash, "1") + + test.log.info("TEST_STEP11: Delete the 2nd snapshot and check xml.") + virsh.snapshot_delete(vm_name, snap_names[1], **virsh_dargs) + check_after_deleting_snap(test, vm, params, expected_hash, "2") + + def teardown_test(): + """ + Clean data. + """ + test.log.info("TEST_TEARDOWN: Clean up env.") + snap_names.reverse() + test_obj.teardown_test() + + vm_name = params.get("main_vm") + bkxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + params.update({"backup_vmxml": bkxml.copy()}) + vm = env.get_vm(vm_name) + + params.update({"original_disk_source": libvirt_disk.get_first_disk_source(vm)}) + snap_names = eval(params.get("snap_names")) + params.update({"mem_files": ["/tmp/%s" % snap_names[0], "/tmp/%s" % snap_names[1]]}) + disk_type = params.get("disk_type") + vm_status = params.get("vm_status") + file_path = params.get("file_path") + disk_dict = eval(params.get('disk_dict', '{}')) + snapshot_dict = params.get("snapshot_dict") + snapshot_disk_list = params.get("snapshot_disk_list") + + test_obj = snapshot_base.SnapshotTest(vm, test, params) + disk_obj = disk_base.DiskBase(test, vm, params) + block_obj = blockcommand_base.BlockCommand(test, vm, params) + snap_file1 = disk_obj.base_dir + "." + snap_names[0] + snap_file2 = disk_obj.base_dir + "." + snap_names[1] + + libvirt_version.is_libvirt_feature_supported(params) + + try: + run_test() + + finally: + teardown_test() diff --git a/libvirt/tests/src/snapshot/delete_disk_only_snapshot.py b/libvirt/tests/src/snapshot/delete_disk_only_snapshot.py new file mode 100644 index 00000000000..b7d3180100e --- /dev/null +++ b/libvirt/tests/src/snapshot/delete_disk_only_snapshot.py @@ -0,0 +1,165 @@ +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Copyright Redhat +# +# SPDX-License-Identifier: GPL-2.0 + +# Author: Nannan Li +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +from virttest import libvirt_version +from virttest import utils_disk +from virttest import virsh +from virttest.libvirt_xml import vm_xml +from virttest.utils_libvirt import libvirt_disk + +from provider.backingchain import blockcommand_base +from provider.snapshot import snapshot_base +from provider.virtual_disk import disk_base + + +def create_data_in_guest(params, session, partition=False): + """ + Create data in guest. + + :param params: dict, test parameters + :param session: vm session + :param partition: the flag to confirm if need do partition. + """ + disk2 = params.get("disk2") + file_name = params.get("file_name") + + if partition: + cmd = "mkfs.ext4 /dev/%s;mount /dev/%s /mnt" % (disk2, disk2) + session.cmd_status_output(cmd) + utils_disk.dd_data_to_vm_disk(session, file_name) + + +def check_xml_and_hash(params, test, session, disk_path, hash_value, + del_second_snap=False): + """ + Check guest xml and data file expected hash value + + :param params: dict, test parameters + :param test: test object + :param session: guest session + :param disk_path: disk path + :param hash_value: disk path + :param del_second_snap: the flag to confirm if it's after the step of deleting + the 2nd snap. + """ + disk_type = params.get("disk_type") + file_name = params.get("file_name") + disk1, disk2 = params.get("disk1"), params.get("disk2") + + new_xml = vm_xml.VMXML.new_from_dumpxml(params.get("main_vm")) + disk2_source = disk_base.DiskBase.get_source_list(new_xml, disk_type, disk2)[::-1] + disk1_source = disk_base.DiskBase.get_source_list(new_xml, disk_type, disk1) + + # Check new disk source. + if del_second_snap: + if disk2_source != [disk_path]: + test.fail("Expect to get %s in new disk, but got '%s'" % ( + [disk_path], disk2_source)) + else: + if disk2_source != [disk_path, params.get("snap_file2")]: + test.fail("Expect to get %s in new disk, but got '%s'" % ( + [disk_path, params.get("snap_file2")], disk2_source)) + + # Check system disk source. + if params.get("first_disk_source") != disk1_source[0]: + test.fail("Expect to get %s in system disk, but got '%s'" % ( + params.get("first_disk_source"), disk1_source[0])) + + # Check file hash value. + file_hash_new, _ = params.get("block_obj").get_hash_value( + session, check_item=file_name) + if hash_value != file_hash_new: + test.fail("Expect to get the same file hash value but got" + " '%s' and '%s'" % (hash_value, file_hash_new)) + test.log.debug("Check guest two disk xml and guest file hash successfully") + + +def run(test, params, env): + """ + Delete guest to disk only snapshot. + """ + def run_test(): + """ + Delete guest to disk only snapshot. + """ + test.log.info("TEST_STEP1:Prepare a running vm with new non-OS disk.") + new_path = disk_obj.add_vm_disk(disk_type, disk_dict) + virsh.start(vm_name) + vm_session = vm.wait_for_login() + + test.log.info("TEST_STEP2:Mount new disk to and generate random data.") + create_data_in_guest(params, vm_session, partition=True) + + test.log.info("TEST_STEP3:Create the 1st snapshot with snapshot xml.") + snap_file1 = disk_obj.base_dir+"."+snap_names[0] + test_obj.create_snapshot_by_xml( + eval(snapshot_dict % snap_names[0]), + eval(snapshot_disk_list % snap_file1), options=snap_options) + + test.log.info("TEST_STEP4:Generate random data to new disk") + create_data_in_guest(params, vm_session) + + test.log.info("TEST_STEP5:Create the 2nd snapshot with snapshot xml.") + params.update({"snap_file2": disk_obj.base_dir+"."+snap_names[1]}) + test_obj.create_snapshot_by_xml( + eval(snapshot_dict % snap_names[1]), + eval(snapshot_disk_list % params.get("snap_file2")), options=snap_options) + + test.log.info("TEST_STEP6:Generate random data to new disk for the same" + "file and And get the file's sha256sum value") + create_data_in_guest(params, vm_session) + file_hash, _ = block_obj.get_hash_value(vm_session, check_item=file_name) + + test.log.info("TEST_STEP7:Delete the inactive snapshot (1st snapshot)" + "and check guest xml, hash value") + virsh.snapshot_delete(vm_name, snap_names[0], **virsh_dargs) + check_xml_and_hash(params, test, vm_session, new_path, file_hash) + + test.log.info("TEST_STEP8:Delete the active snapshot (2nd snapshot) " + "and check guest xml, hash value") + virsh.snapshot_delete(vm_name, snap_names[1], **virsh_dargs) + check_xml_and_hash(params, test, vm_session, new_path, file_hash, + del_second_snap=True) + vm_session.close() + + def teardown_test(): + """ + Clean data. + """ + test.log.info("TEST_TEARDOWN: Clean up env.") + snap_names.reverse() + test_obj.teardown_test() + + vm_name = params.get("main_vm") + original_xml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + params['backup_vmxml'] = original_xml.copy() + vm = env.get_vm(vm_name) + + virsh_dargs = {"debug": True, "ignore_status": False} + disk_dict = eval(params.get("disk_dict", "{}")) + snap_names = eval(params.get("snap_names", '[]')) + snap_options = params.get("snap_options") + file_name = params.get("file_name") + disk_type = params.get("disk_type") + snapshot_dict = params.get("snapshot_dict") + snapshot_disk_list = params.get("snapshot_disk_list") + params.update({"first_disk_source": libvirt_disk.get_first_disk_source(vm)}) + + test_obj = snapshot_base.SnapshotTest(vm, test, params) + disk_obj = disk_base.DiskBase(test, vm, params) + block_obj = blockcommand_base.BlockCommand(test, vm, params) + params.update({"block_obj": block_obj}) + + libvirt_version.is_libvirt_feature_supported(params) + + try: + run_test() + + finally: + teardown_test() diff --git a/libvirt/tests/src/snapshot/delete_external_after_reverting_internal.py b/libvirt/tests/src/snapshot/delete_external_after_reverting_internal.py new file mode 100644 index 00000000000..d52089a35c3 --- /dev/null +++ b/libvirt/tests/src/snapshot/delete_external_after_reverting_internal.py @@ -0,0 +1,152 @@ +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Copyright Redhat +# +# SPDX-License-Identifier: GPL-2.0 + +# Author: Liang Cong +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +import os + +from virttest import data_dir +from virttest import libvirt_version +from virttest import utils_misc +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.guest_os_booting import guest_os_booting_base + + +def run(test, params, env): + """ + Delete external snapshot after reverting to internal snapshot. + """ + def check_dom_disks(): + """ + Check domain disk type and file type disk number. + """ + domxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + disks = domxml.get_disk_all_by_expr("type!=file", "device==disk") + if disks: + test.error("Unsupported non-file type disk found in domain.") + disks = domxml.get_disk_all_by_expr("type==file", "device==disk") + if len(disks) != 1: + test.error("Expected only 1 file type disk but found %s." % len(disks)) + + def check_internal_snap(): + """ + Check internal snapshot info. + """ + snap_info = virsh.snapshot_info(vm_name, internal_snap_name, **virsh_dargs) + if snap_info["Name"] != internal_snap_name or snap_info["Location"] != "internal": + test.fail("Expected internal snapshot named after '%s', but found %s snapshot named after '%s'." % ( + internal_snap_name, snap_info["Location"], snap_info["Name"])) + internal_snap_list = utils_misc.get_image_snapshot(disk_source) + if len(internal_snap_list) != 1: + test.fail("Expected only 1 internal snapshot in image, but found %s." % len( + internal_snap_list)) + + def check_disk_xml(xpath_list): + """ + Check domain disk xml according to xpath. + + :param xpath_list: expected xpath list. + """ + dom_xml = vm_xml.VMXML.new_from_dumpxml(vm_name) + test.log.debug("domain xml is: %s", dom_xml) + libvirt_vmxml.check_guest_xml_by_xpaths(dom_xml, xpath_list) + + def check_file_after_snapshot_delete(file, exist): + """ + Check snapshot related file after snapshot delete. + + :param file: str, snapshot related file path. + :param exist: bool, file should exist or not. + """ + if os.path.exists(file) != exist: + judgement_string = "" if exist else "not " + test.fail("file '%s' should %sexist after snapshot delete." % (file, judgement_string)) + + def run_test(): + """ + 1. Define a guest. + 2. Create an internal snapshot. + 3. Start the guest. + 4. Create an external snapshot. + 5. Revert snapshot to the internal snapshot. + 6. Delete the external snapshot. + 7. Check the snapshot related images. + """ + #since default guest is used, so step 1 virsh define is skipped. + test.log.info("TEST_STEP2:Create an internal snapshot.") + virsh.snapshot_create_as(vm_name, internal_snap_option, **virsh_dargs) + check_internal_snap() + + test.log.info("TEST_STEP3:Start the guest.") + vm.start() + vm.wait_for_login().close() + + test.log.info("TEST_STEP4:Create an external snapshot.") + virsh.snapshot_create_as(vm_name, external_snap_option, **virsh_dargs) + check_disk_xml(disk_xpath) + + test.log.info("TEST_STEP5:Revert snapshot to the internal snapshot.") + virsh.snapshot_revert(vm_name, internal_snap_name, **virsh_dargs) + dom_xml = vm_xml.VMXML.new_from_dumpxml(vm_name) + current_disk_dict = dom_xml.devices.by_device_tag('disk')[0].fetch_attrs() + original_disk_dict = original_disk.fetch_attrs() + if original_disk_dict != current_disk_dict: + test.fail("Expected domain disk is %s, but found %s." % + (original_disk_dict, current_disk_dict)) + + test.log.info("TEST_STEP6:Delete the external snapshot.") + virsh.snapshot_delete(vm_name, external_snap_name, **virsh_dargs) + + test.log.info("TEST_STEP7:Check the snapshot related images.") + for snap_file in external_snap_file_list: + check_file_after_snapshot_delete(snap_file, exist=False) + check_file_after_snapshot_delete(disk_source, exist=True) + + def teardown_test(): + """ + Clean test environment. + """ + test.log.info("TEST_TEARDOWN: Clean up env.") + if vm.is_alive(): + vm.destroy() + libvirt.clean_up_snapshots(vm_name) + for snap_file in external_snap_file_list: + if os.path.exists(snap_file): + os.remove(snap_file) + undefine_option = "--nvram" if firmware_type == "ovmf" else None + bkxml.sync(undefine_option) + + libvirt_version.is_libvirt_feature_supported(params) + vm_name = guest_os_booting_base.get_vm(params) + firmware_type = params.get("firmware_type") + internal_snap_name = params.get("internal_snap_name") + external_snap_name = params.get("external_snap_name") + external_mem_file = "%s/%s.%s" % (data_dir.get_tmp_dir(), vm_name, external_snap_name) + internal_snap_option = params.get("internal_snap_option") + external_snap_option = params.get("external_snap_option") % external_mem_file + + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + bkxml = vmxml.copy() + original_disk = vmxml.devices.by_device_tag('disk')[0] + vm = env.get_vm(vm_name) + disk_source = vm.get_first_disk_devices()["source"] + ori_image_file, _ = os.path.splitext(disk_source) + external_snapshot_file = "%s.%s" % (ori_image_file, external_snap_name) + external_snap_file_list = [external_mem_file, external_snapshot_file] + disk_xpath = eval(params.get("disk_xpath") % (external_snapshot_file, disk_source)) + virsh_dargs = {"debug": True, "ignore_status": False} + + try: + check_dom_disks() + run_test() + + finally: + teardown_test() diff --git a/libvirt/tests/src/snapshot/delete_external_snap_with_references.py b/libvirt/tests/src/snapshot/delete_external_snap_with_references.py new file mode 100644 index 00000000000..522ab1c179c --- /dev/null +++ b/libvirt/tests/src/snapshot/delete_external_snap_with_references.py @@ -0,0 +1,112 @@ +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Copyright Redhat +# +# SPDX-License-Identifier: GPL-2.0 + +# Author: Nannan Li +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +from virttest import libvirt_version +from virttest import virsh +from virttest.libvirt_xml import vm_xml +from virttest.utils_test import libvirt + +from provider.snapshot import snapshot_base + + +def run(test, params, env): + """ + :params test: test object + :params params: wrapped dict with all parameters + :params env: test object + """ + def setup_test(): + """ + Delete snapshots in the parent external snapshots + with multiple children. + """ + test.log.info("TEST_SETUP: Prepare the parent external snapshot" + " with multiple children") + virsh.start(vm_name) + vm.wait_for_login().close() + for sname in snap_names: + virsh.snapshot_create_as(vm.name, snap_options % (sname, sname, sname), + **virsh_dargs) + if sname == 's3': + virsh.snapshot_revert(vm_name, snap_names[0], **virsh_dargs) + res = virsh.snapshot_current(vm_name, **virsh_dargs).stdout.strip() + if res != snap_names[-1]: + test.fail("Expect the current snap name is '%s' instead of" + " '%s'" % (snap_names[-1], res)) + virsh.snapshot_list(vm_name, **virsh_dargs, options='--tree') + + def run_test_del_parent_snap(): + """ + Delete the parent snapshot with multiple children. + """ + test.log.info("TEST_STEP:Delete the parent snapshot with multi-child.") + if not vm.is_alive(): + virsh.start(vm_name) + vm.wait_for_login().close() + del_res = virsh.snapshot_delete(vm.name, snap_names[0], debug=True) + libvirt.check_exit_status(del_res, error_msg) + + def run_test_del_current_branch(): + """ + Delete the snapshots of current branch. + """ + test.log.info("TEST_STEP: Delete the snapshots of current branch.") + for times in range(1, 4): + curr_sname = virsh.snapshot_current(vm_name, **virsh_dargs).stdout.strip() + del_res = virsh.snapshot_delete(vm_name, curr_sname, debug=True) + if times == 3: + libvirt.check_exit_status(del_res, error_msg) + for index in del_index: + res = virsh.snapshot_delete(vm_name, snap_names[index], **virsh_dargs) + libvirt.check_exit_status(res) + + def run_test_del_non_current_branch(): + """ + Delete the snapshots of non-current branch + """ + test.log.info("TEST_STEP: Delete the snapshots of non-current branch.") + res = virsh.snapshot_delete(vm_name, snap_names[1], debug=True) + libvirt.check_exit_status(res, error_msg) + + for index in [2, 1] + del_index: + res = virsh.snapshot_delete(vm_name, snap_names[index], **virsh_dargs) + libvirt.check_exit_status(res) + + def teardown_test(): + """ + Clean data. + """ + test.log.info("TEST_TEARDOWN: Clean up env.") + snap_names.reverse() + test_obj.virsh_dargs = {'ignore_status': True, 'debug': True} + test_obj.delete_snapshot(snap_names) + bkxml.sync() + + vm_name = params.get("main_vm") + original_xml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + bkxml = original_xml.copy() + vm = env.get_vm(vm_name) + + snap_options = params.get("snap_options") + case = params.get("case") + run_test = eval("run_test_%s" % case) + error_msg = params.get("error_msg") + + test_obj = snapshot_base.SnapshotTest(vm, test, params) + virsh_dargs = {"debug": True, "ignore_status": False} + snap_names = ['s1', 's2', 's3', 's4', 's5'] + del_index = eval(params.get('del_index', '[]')) + libvirt_version.is_libvirt_feature_supported(params) + + try: + setup_test() + run_test() + + finally: + teardown_test() diff --git a/libvirt/tests/src/snapshot/delete_snapshot_after_disk_attached.py b/libvirt/tests/src/snapshot/delete_snapshot_after_disk_attached.py new file mode 100644 index 00000000000..784b7076e7d --- /dev/null +++ b/libvirt/tests/src/snapshot/delete_snapshot_after_disk_attached.py @@ -0,0 +1,137 @@ +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Copyright Redhat +# +# SPDX-License-Identifier: GPL-2.0 + +# Author: Nannan Li +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +import os +import re + +from virttest import libvirt_version +from virttest import virsh +from virttest.libvirt_xml import vm_xml + +from provider.snapshot import snapshot_base +from provider.virtual_disk import disk_base + +virsh_dargs = {"debug": True, "ignore_status": False} + + +def check_guest_domblklist(test, params, vm_name): + """ + Check current guest domblklist. + + :params: test, test object. + :params: params, cfg parameter dict. + :params: vm_name, guest name. + """ + disk_type = params.get('disk_type') + disk1, disk2 = params.get("disk1"), params.get("disk2") + + vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) + test.log.debug("Current vm xml is %s\n", vmxml) + disk1_sources = disk_base.DiskBase.get_source_list(vmxml, disk_type, disk1)[::-1] + disk2_sources = disk_base.DiskBase.get_source_list(vmxml, disk_type, disk2)[::-1] + if disk2_sources: + pattern = [r'%s\s*%s' % (disk1, disk1_sources[-1]), + r'%s\s*%s' % (disk2, disk2_sources[-1])] + else: + pattern = [r'%s\s*%s' % (disk1, disk1_sources[-1])] + + domblk_res = virsh.domblklist(vm_name, **virsh_dargs).stdout_text.strip() + for pat in pattern: + if not re.search(pat, domblk_res): + test.fail('Expected to get "%s" in "%s"' % (pat, domblk_res)) + + +def run(test, params, env): + """ + Verify deleting snapshot after disk attached. + """ + def run_test(): + """ + Verify deleting snapshot after disk attached. + """ + vm_name = params.get("main_vm") + original_xml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + params['backup_vmxml'] = original_xml.copy() + vm = env.get_vm(vm_name) + disk_type = params.get('disk_type') + snap_names = eval(params.get("snap_names", '[]')) + mem_path = params.get("mem_path") + disk1_snap_option = params.get("disk1_snap_option") + disk2_snap_option = params.get("disk2_snap_option") + disk_type, disk_dict = params.get("disk_type"), eval(params.get("disk_dict", '{}')) + disk1, disk2 = params.get("disk1"), params.get("disk2") + snap_deleting_ongoing_tag = params.get("snap_deleting_ongoing_tag") + + test.log.info("TEST_STEP1:Start guest with just system disk.") + vm.wait_for_login().close() + check_guest_domblklist(test, params, vm_name) + + test.log.info("TEST_STEP2: Create two disk only snaps for guest") + for sname in snap_names[0:2]: + virsh.snapshot_create_as(vm.name, disk1_snap_option % sname, + **virsh_dargs) + + test.log.info("TEST_STEP3: Attach a virtual disk ") + new_disk, disk2_path = disk_obj.prepare_disk_obj(disk_type, disk_dict) + virsh.attach_device(vm_name, new_disk.xml, **virsh_dargs) + check_guest_domblklist(test, params, vm_name) + + test.log.info("TEST_STEP4: Create disk and mem snapshot for new disk") + virsh.snapshot_create_as(vm_name, disk2_snap_option % ( + snap_names[2], snap_names[2]), **virsh_dargs) + check_guest_domblklist(test, params, vm_name) + if not os.path.exists(mem_path + snap_names[2]): + test.fail("Mem file '%s' does not exist" % mem_path + snap_names[2]) + + test.log.info("TEST_STEP5: Create disk only snapshot for guest.") + virsh.snapshot_create_as(vm.name, disk1_snap_option % snap_names[3], + **virsh_dargs) + check_guest_domblklist(test, params, vm_name) + + test.log.info("TEST_STEP6: Delete the third snap and check it " + "actually removed") + virsh.snapshot_delete(vm_name, snap_names[2], **virsh_dargs) + test_obj.check_snap_list(snap_names[2], expect_exist=False) + + vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) + disk2_sources = disk_obj.get_source_list(vmxml, disk_type, disk2) + snap3_path = disk2_path + ".%s" % snap_names[2] + if snap3_path in disk2_sources: + test.fail("Expect '%s' does not exist in new disk source list '%s'" % ( + snap3_path, disk2_sources)) + + expect_path = os.path.join(mem_path, snap_names[2]) + if os.path.exists(expect_path): + test.fail("Expect the mem file '%s' does not exist, but still found" % expect_path) + + snap_xml = virsh.snapshot_dumpxml( + vm_name, snap_names[1], **virsh_dargs).stdout_text.strip("\n") + if re.search(snap_deleting_ongoing_tag, snap_xml): + test.fail("Expect no '%s' in guest xml, but still found" % snap_deleting_ongoing_tag) + + def teardown_test(): + """ + Clean data. + """ + test.log.info("TEST_TEARDOWN: Clean up env.") + test_obj.teardown_test() + disk_type = params.get('disk_type') + disk_obj.cleanup_disk_preparation(disk_type) + + vm = env.get_vm(params.get("main_vm")) + test_obj = snapshot_base.SnapshotTest(vm, test, params) + disk_obj = disk_base.DiskBase(test, vm, params) + + libvirt_version.is_libvirt_feature_supported(params) + + try: + run_test() + + finally: + teardown_test() diff --git a/libvirt/tests/src/snapshot/delete_snapshot_metadata.py b/libvirt/tests/src/snapshot/delete_snapshot_metadata.py new file mode 100644 index 00000000000..291e71ed6f1 --- /dev/null +++ b/libvirt/tests/src/snapshot/delete_snapshot_metadata.py @@ -0,0 +1,115 @@ +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Copyright Redhat +# +# SPDX-License-Identifier: GPL-2.0 + +# Author: Nannan Li +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +import os + +from virttest import libvirt_version +from virttest import virsh +from virttest.libvirt_xml import vm_xml +from virttest.utils_libvirt import libvirt_disk + +from provider.snapshot import snapshot_base +from provider.virtual_disk import disk_base + +virsh_dargs = {"debug": True, "ignore_status": False} + + +def check_source_and_mem_file(test, params, new_disk_source, disk_files, mem_files): + """ + Check current vm two disks source path and mem file. + + :param: test: test object. + :param params: Dictionary with the test parameters + :param: new_disk_source: source path of new disk. + :param: disk_files: disk source files. + :param: mem_file: memory snapshot files. + """ + new_disk = params.get("new_disk") + original_disk = params.get("original_disk") + disk_type = params.get("disk_type") + original_disk_source = params.get("original_disk_source") + + vmxml = vm_xml.VMXML.new_from_dumpxml(params.get("main_vm")) + test.log.debug("Get current xml is :%s", vmxml) + + disk1_sources = disk_base.DiskBase.get_source_list(vmxml, disk_type, original_disk)[0] + disk2_sources = disk_base.DiskBase.get_source_list(vmxml, disk_type, new_disk)[::-1] + if disk1_sources != original_disk_source: + test.fail("Expect to get '%s' in system disk instead of '%s'" % ( + original_disk_source, disk1_sources)) + test.log.debug('Check system disk source list success') + if disk2_sources != [new_disk_source] + disk_files: + test.fail("Expect to get '%s' in new disk but get '%s'" % ( + [new_disk_source] + disk_files, disk2_sources)) + test.log.debug('Check the new disk source list success') + + for mf in mem_files: + if not os.path.exists(mf): + test.fail("Mem file '%s' does not exist" % mf) + + +def run(test, params, env): + """ + Test deleting snapshot's metadata. + """ + + def run_test(): + """ + Test deleting snapshot's metadata. + """ + del_option = params.get('del_option') + snap_name = eval(params.get("snap_name")) + snap_options = params.get("snap_options") + mem_path = params.get("mem_path") + disk_path = params.get("disk_path") + disk_dict = eval(params.get("disk_dict")) + disk_type = params.get("disk_type") + + test.log.info("TEST_STEP1: Prepare a new disk vdb") + new_disk_source = disk_obj.add_vm_disk(disk_type, disk_dict) + virsh.start(vm_name, **virsh_dargs) + vm.wait_for_login().close() + + test.log.info("TEST_STEP2:Create 3 external disk+memory snapshots," + "check the new disk source list and memory snapshot file.") + mem_files, disk_files = [], [] + for index, sname in enumerate(snap_name): + virsh.snapshot_create_as(vm_name, snap_options % (sname, index + 1, + index + 1), + **virsh_dargs) + mem_files.append(mem_path + str(index + 1)) + disk_files.append(disk_path + str(index + 1)) + check_source_and_mem_file(test, params, new_disk_source, disk_files, mem_files) + + test.log.info("TEST_STEP3: Delete the first snapshot with --metadata" + "check the new disk source list and memory snapshot file.") + virsh.snapshot_delete(vm_name, snap_name[0], options=del_option, **virsh_dargs) + check_source_and_mem_file(test, params, new_disk_source, disk_files, mem_files) + + def teardown_test(): + """ + Clean data. + """ + test.log.info("TEST_TEARDOWN: Clean up env.") + test_obj.teardown_test() + + libvirt_version.is_libvirt_feature_supported(params) + try: + vm_name = params.get("main_vm") + vm = env.get_vm(vm_name) + original_xml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + params['backup_vmxml'] = original_xml.copy() + params.update({"original_disk_source": libvirt_disk.get_first_disk_source(vm)}) + test_obj = snapshot_base.SnapshotTest(vm, test, params) + disk_obj = disk_base.DiskBase(test, vm, params) + + run_test() + + finally: + teardown_test() diff --git a/libvirt/tests/src/snapshot/revert_disk_external_snap.py b/libvirt/tests/src/snapshot/revert_disk_external_snap.py new file mode 100644 index 00000000000..b530f43c647 --- /dev/null +++ b/libvirt/tests/src/snapshot/revert_disk_external_snap.py @@ -0,0 +1,129 @@ +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Copyright Redhat +# +# SPDX-License-Identifier: GPL-2.0 + +# Author: Nannan Li +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +import os + +from virttest import data_dir +from virttest import libvirt_version +from virttest import virsh +from virttest.libvirt_xml import vm_xml + +from provider.snapshot import snapshot_base +from provider.virtual_disk import disk_base + +virsh_dargs = {"debug": True, "ignore_status": False} + + +def revert_snap_and_check_files(params, vm, test, snap_name, expected_files): + """ + Revert the snapshot name and check expected file. + + :param params: dict wrapped with params. + :param vm: vm object. + :param test: test object. + :param snap_name: snapshot name. + :param expected_files: expected file list. + """ + virsh.snapshot_revert(vm.name, snap_name, **virsh_dargs) + + vm.cleanup_serial_console() + vm.create_serial_console() + session = vm.wait_for_serial_login() + for file in expected_files: + output = session.cmd('ls %s' % file) + if file not in output: + test.fail("File %s not exist in %s" % (file, output)) + params.get("test_obj").check_current_snapshot(snap_name) + + test.log.debug("File %s exist in guest" % expected_files) + session.close() + + +def run(test, params, env): + """ + Revert guest to a disk external snapshot. + """ + def setup_test(): + """ + Prepare file and snapshot. + """ + test.log.info("TEST_SETUP: Create files and snaps in running guest.") + if with_data_file: + data_file = data_dir.get_data_dir() + "/datastore.img" + data_file_option = params.get("data_file_option", "") % data_file + image_path = disk_obj.add_vm_disk(disk_type, disk_dict, new_image_path="", + extra=data_file_option) + new_file.extend([data_file, image_path]) + vm.start() + test.log.debug("The current guest xml is: %s", virsh.dumpxml(vm_name).stdout_text) + session = vm.wait_for_serial_login() + mem_file = " " + for index, sname in enumerate(snap_names): + session.cmd("touch %s" % file_list[index]) + if snap_type == "disk_and_memory": + mem_file = sname + virsh.snapshot_create_as(vm.name, snap_options % (sname, mem_file), + **virsh_dargs) + test_obj.check_snap_list(sname) + + session.close() + + def run_test(): + """ + Revert guest and check file list. + """ + test.log.info("TEST_STEP1:Revert the 2nd snapshot and check files.") + revert_snap_and_check_files(params, vm, test, snap_names[1], + file_list[:2]) + + test.log.info("TEST_STEP2:Revert the first snapshot and check files.") + revert_snap_and_check_files(params, vm, test, snap_names[0], + [file_list[0]]) + + test.log.info("TEST_STEP3:Revert the last snap and check source files") + revert_snap_and_check_files(params, vm, test, snap_names[-1], + file_list) + + def teardown_test(): + """ + Clean data. + """ + test.log.info("TEST_TEARDOWN: Clean up env.") + for file in new_file: + if os.path.exists(file): + os.remove(file) + snap_names.reverse() + test_obj.teardown_test() + + vm_name = params.get("main_vm") + original_xml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + params['backup_vmxml'] = original_xml.copy() + vm = env.get_vm(vm_name) + + snap_names = eval(params.get("snap_names", '[]')) + snap_type = params.get("snap_type") + snap_options = params.get("snap_options") + file_list = eval(params.get("file_list")) + disk_target = params.get("disk_target", "vdb") + disk_type = params.get("disk_type", "file") + disk_dict = eval(params.get("disk_dict", "{}")) + with_data_file = "yes" == params.get("with_data_file", "no") + test_obj = snapshot_base.SnapshotTest(vm, test, params) + disk_obj = disk_base.DiskBase(test, vm, params) + params.update({"test_obj": test_obj}) + + libvirt_version.is_libvirt_feature_supported(params) + new_file = [] + + try: + setup_test() + run_test() + + finally: + teardown_test() diff --git a/libvirt/tests/src/snapshot/revert_memory_only_snap.py b/libvirt/tests/src/snapshot/revert_memory_only_snap.py new file mode 100644 index 00000000000..44138d05ba9 --- /dev/null +++ b/libvirt/tests/src/snapshot/revert_memory_only_snap.py @@ -0,0 +1,80 @@ +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Copyright Redhat +# +# SPDX-License-Identifier: GPL-2.0 + +# Author: Nannan Li +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +from virttest import libvirt_version +from virttest import virsh +from virttest.libvirt_xml import vm_xml + +from provider.snapshot import snapshot_base +from provider.virtual_disk import disk_base + + +def run(test, params, env): + """ + Revert guest to memory only snapshot. + """ + def run_test(): + """ + Revert guest to memory only snapshot. + """ + test.log.info("TEST_STEP1:Create memory only snaps for running guest.") + virsh.start(vm_name) + vm.wait_for_login().close() + for sname in snap_names: + virsh.snapshot_create_as(vm.name, snap_options % (sname, sname), + **virsh_dargs) + test_obj.check_snap_list(sname) + test.log.info("TEST_STEP2:Revert the second snap and check source path") + virsh.snapshot_revert(vm_name, snap_names[1], **virsh_dargs) + + def _check_source_num(): + vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) + source_list = disk_obj.get_source_list(vmxml, disk_type, target_disk) + if len(source_list) != 2: + test.fail('Expected disk source num should be 2 instead of %s ' + 'in xml %s' % (len(source_list), vmxml)) + _check_source_num() + + test.log.info("TEST_STEP3:Revert the first snap and check source path") + virsh.snapshot_revert(vm_name, snap_names[0], **virsh_dargs) + _check_source_num() + + test.log.info("TEST_STEP4:Revert the last snap and check source path") + virsh.snapshot_revert(vm_name, snap_names[2], **virsh_dargs) + _check_source_num() + + def teardown_test(): + """ + Clean data. + """ + test.log.info("TEST_TEARDOWN: Clean up env.") + snap_names.reverse() + test_obj.teardown_test() + + vm_name = params.get("main_vm") + original_xml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + params['backup_vmxml'] = original_xml.copy() + + vm = env.get_vm(vm_name) + + virsh_dargs = {"debug": True, "ignore_status": True} + snap_names = eval(params.get("snap_names", '[]')) + snap_options = params.get("snap_options") + disk_type = params.get("disk_type") + target_disk = params.get("target_disk") + test_obj = snapshot_base.SnapshotTest(vm, test, params) + disk_obj = disk_base.DiskBase(test, vm, params) + libvirt_version.is_libvirt_feature_supported(params) + + try: + run_test() + + finally: + teardown_test() diff --git a/libvirt/tests/src/snapshot/revert_snap_based_on_state.py b/libvirt/tests/src/snapshot/revert_snap_based_on_state.py new file mode 100644 index 00000000000..468773efdfc --- /dev/null +++ b/libvirt/tests/src/snapshot/revert_snap_based_on_state.py @@ -0,0 +1,97 @@ +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Copyright Redhat +# +# SPDX-License-Identifier: GPL-2.0 + +# Author: Nannan Li +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +from virttest import libvirt_version +from virttest import virsh +from virttest.libvirt_xml import vm_xml +from virttest.utils_test import libvirt +from virttest.utils_libvirt import libvirt_misc + +from provider.snapshot import snapshot_base + + +def run(test, params, env): + """ + Revert snapshots based on different domain state. + """ + + def get_snap_state(vm_name): + """ + Get list of snapshots state of domain. + + :param vm_name: name of domain + :return: dict of snapshot names and snapshot state, + e.g.: get {'s1': 'running', 's2': 'running'} + """ + result = virsh.command("snapshot-list %s" % vm_name, + **virsh_dargs).stdout_text.strip() + state_dict = libvirt_misc.convert_to_dict( + result, r"(\S*) *\d+.* \d*:\d*:\d* .\d* *(\S*)") + test.log.debug("Get snap name and state dict is :%s", state_dict) + return state_dict + + def run_test(): + """ + Revert snapshots based on different domain state. + """ + test.log.info("TEST_STEP1: Prepare a snap.") + if snap_state == "running": + virsh.start(vm_name, **virsh_dargs) + vm.wait_for_login().close() + virsh.snapshot_create_as(vm_name, snap_options % snap_name, + **virsh_dargs) + state_result = get_snap_state(vm_name) + if state_result[snap_name] != snap_state: + test.fail("%s state should be '%s' instead of '%s'" % ( + snap_name, snap_state, state_result[snap_name])) + else: + test.log.debug("Check snap state '%s' is correct" % snap_state) + + test.log.info("TEST_STEP2: Set domain state.") + if vm_state.replace(' ', '') != snap_state: + if vm_state == "shut off": + virsh.destroy(vm_name, **virsh_dargs) + elif vm_state == "running": + virsh.start(vm_name, **virsh_dargs) + vm.wait_for_login().close() + + test.log.info("TEST_STEP3: Revert the snapshot") + virsh.snapshot_revert(vm_name, snap_name, **virsh_dargs) + + test.log.info("TEST_STEP5: Check expected domain state") + if not libvirt.check_vm_state(vm_name, expected_state): + test.fail("VM state should be '%s' after reverting." % expected_state) + else: + test.log.debug("Check vm state '%s' is correct", expected_state) + + def teardown_test(): + """ + Clean data. + """ + test.log.info("TEST_TEARDOWN: Clean up env.") + test_obj.delete_snapshot(snap_name) + bkxml.sync() + + 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() + virsh_dargs = {"debug": True, "ignore_status": True} + snap_name = params.get("snap_name") + snap_options = params.get("snap_options") + snap_state = params.get("snap_state") + vm_state = params.get("vm_state") + expected_state = params.get("expected_state") + test_obj = snapshot_base.SnapshotTest(vm, test, params) + + libvirt_version.is_libvirt_feature_supported(params) + try: + run_test() + finally: + teardown_test() diff --git a/libvirt/tests/src/snapshot/revert_snap_for_guest_with_genid.py b/libvirt/tests/src/snapshot/revert_snap_for_guest_with_genid.py new file mode 100644 index 00000000000..c3a967c039b --- /dev/null +++ b/libvirt/tests/src/snapshot/revert_snap_for_guest_with_genid.py @@ -0,0 +1,94 @@ +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Copyright Redhat +# +# SPDX-License-Identifier: GPL-2.0 + +# Author: Nannan Li +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +import uuid + +from virttest import libvirt_version +from virttest import virsh +from virttest.libvirt_xml import vm_xml + +from provider.snapshot import snapshot_base + + +def check_genid(vm, test, old_genid, changed=False): + """ + Check if genid is changed. + + :params vm: vm object + :params test: test object + :params old_genid: the old genid value to compare + :params changed: Checking is new genid is changed, default False + """ + vmxml = vm_xml.VMXML.new_from_dumpxml(vm.name) + test.log.debug("The new xml is:\n%s", vmxml) + + new_genid = vmxml.get_genid() + if changed: + if new_genid == old_genid: + test.fail("Genid '%s' is same as old genid '%s'" % (new_genid, old_genid)) + else: + if new_genid != old_genid: + test.fail("Genid is updated from '%s' to '%s'" % (old_genid, new_genid)) + test.log.debug("Check genid successfully") + + +def run(test, params, env): + """ + Revert snapshot for guest which includes genid. + """ + def run_test(): + """ + Revert snapshot for guest which includes genid. + """ + test.log.info("TEST_STEP1:Prepare a running guest with genid.") + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + original_genid = str(uuid.uuid4()) + vmxml.setup_attrs(**{'genid': original_genid}) + vmxml.sync() + virsh.start(vm_name) + vm.wait_for_login().close() + + test.log.info("TEST_STEP2,3:Create disk snapshots and memory snapshots." + "Check snapshots and genid is not changed") + for sname in snap_names: + virsh.snapshot_create_as(vm.name, snap_options % (sname, sname, sname), + **virsh_dargs) + test_obj.check_snap_list(sname) + check_genid(vm, test, original_genid) + + test.log.info("TEST_STEP4: Revert snapshot to the first snap") + virsh.snapshot_revert(vm_name, snap_names[0], **virsh_dargs) + + test.log.info("TEST_STEP6:Check genid which has already been changed.") + check_genid(vm, test, original_genid, changed=True) + + def teardown_test(): + """ + Clean data. + """ + test.log.info("TEST_TEARDOWN: Clean up env.") + snap_names.reverse() + test_obj.teardown_test() + + vm_name = params.get("main_vm") + original_xml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + params['backup_vmxml'] = original_xml.copy() + vm = env.get_vm(vm_name) + + virsh_dargs = {"debug": True, "ignore_status": True} + snap_names = eval(params.get("snap_names", '[]')) + snap_options = params.get("snap_options") + test_obj = snapshot_base.SnapshotTest(vm, test, params) + + libvirt_version.is_libvirt_feature_supported(params) + try: + run_test() + + finally: + teardown_test() diff --git a/libvirt/tests/src/snapshot/revert_snap_with_flags.py b/libvirt/tests/src/snapshot/revert_snap_with_flags.py new file mode 100644 index 00000000000..17b46812a09 --- /dev/null +++ b/libvirt/tests/src/snapshot/revert_snap_with_flags.py @@ -0,0 +1,101 @@ +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Copyright Redhat +# +# SPDX-License-Identifier: GPL-2.0 + +# Author: Nannan Li +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +import re + +from avocado.utils import process + +from virttest import libvirt_version +from virttest import virsh +from virttest.libvirt_xml import vm_xml + +from provider.snapshot import snapshot_base + + +def check_vm_state_in_dom_list(test, vm_name, vm_state): + """ + Check vm state in virsh domain list. + + :param test: test object. + :param vm_name: vm name. + :param vm_state: expected vm state. + """ + doms = virsh.dom_list("--all", debug=True).stdout.strip() + if not re.search(r".*%s.*%s.*" % (vm_name, vm_state), doms): + test.fail( + "VM '%s' with the state %s is not found" % (vm_name, vm_state)) + + +def run(test, params, env): + """ + Revert snapshot for guest with different flags. + """ + def run_test(): + """ + Revert snapshot with --current --paused --running + --reset-nvram --force in order. + """ + test.log.info("TEST_STEP1:Prepare shutoff guest and create a snapshot.") + virsh.snapshot_create_as(vm_name, + snap1_options % (snap_names[0], snap_names[0]), + **virsh_dargs) + test_obj.check_snap_list(snap_names[0]) + + test.log.info("TEST_STEP2:Start guest and create a snapshot.") + vm.start() + vm.wait_for_login().close() + virsh.snapshot_create_as(vm_name, snap2_options % ( + snap_names[1], snap_names[1], snap_names[1]), **virsh_dargs) + test_obj.check_snap_list(snap_names[1]) + + test.log.info("TEST_STEP3: Revert to the second snap.") + virsh.snapshot_revert(vm_name, revert_flags[0], **virsh_dargs) + check_vm_state_in_dom_list(test, vm_name, vm_state="paused") + + test.log.info("TEST_STEP4: Revert snapshot to the first snap") + if vars_path: + vars_hash1 = process.run("sha256sum %s" % vars_path, ignore_status=False) + virsh.snapshot_revert(vm_name, snap_names[0], + options=revert_flags[1], **virsh_dargs) + if vars_path: + vars_hash2 = process.run("sha256sum %s" % vars_path, ignore_status=False) + if vars_hash1 == vars_hash2: + test.fail("Expect to get different hash values for '%s', " + "but got both '%s' " % (vars_path, vars_hash1)) + + test.log.info("TEST_STEP5: Revert snapshot to the second snap force") + virsh.snapshot_revert(vm_name, snap_names[1], + options=revert_flags[2], **virsh_dargs) + check_vm_state_in_dom_list(test, vm_name, vm_state="running") + + def teardown_test(): + """ + Clean data. + """ + test.log.info("TEST_TEARDOWN: Clean up env.") + snap_names.reverse() + test_obj.teardown_test() + + libvirt_version.is_libvirt_feature_supported(params) + vm_name = params.get("main_vm") + original_xml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + params['backup_vmxml'] = original_xml.copy() + vm = env.get_vm(vm_name) + virsh_dargs = {"debug": True, "ignore_status": False} + snap_names = eval(params.get("snap_names", '[]')) + revert_flags = eval(params.get("flags", "[]")) + vars_path = params.get("vars_path") + snap1_options, snap2_options = params.get("snap1_options"), params.get('snap2_options') + test_obj = snapshot_base.SnapshotTest(vm, test, params) + + try: + run_test() + + finally: + teardown_test() diff --git a/libvirt/tests/src/snapshot/revert_snapshot_after_xml_updated.py b/libvirt/tests/src/snapshot/revert_snapshot_after_xml_updated.py new file mode 100644 index 00000000000..cd7d6c5c0fa --- /dev/null +++ b/libvirt/tests/src/snapshot/revert_snapshot_after_xml_updated.py @@ -0,0 +1,243 @@ +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Copyright Redhat +# +# SPDX-License-Identifier: GPL-2.0 + +# Author: Nannan Li +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +import re + +from avocado.utils import process + +from virttest import libvirt_version +from virttest import virsh +from virttest.libvirt_xml import vm_xml + +from provider.snapshot import snapshot_base +from provider.virtual_disk import disk_base + +virsh_dargs = {"debug": True, "ignore_status": False} + + +def compare_value(test, actual_value, expected_value2): + if actual_value != expected_value2: + test.fail("Expect to get %s, but got %s" % (expected_value2, actual_value)) + + +def check_existed(test, res, pattern): + """ + Check if pattern exist in virsh.domblklist result. + + :param test: test object. + :param res: the result. + :param pattern: expected pattern. + """ + search = re.findall(pattern, res) + if not search: + test.fail("%s not exist in %s" % (pattern, res)) + else: + test.log.debug("Matched %s" % search) + + +def create_file(vm, file, session=None): + """ + Create specific file in guest + + :param vm: vm object. + :param file: the file to create. + :param session: the guest session. + """ + if not session: + session = vm.wait_for_login() + session.cmd("touch %s" % file) + session.close() + + +def check_file_exist(test, vm, params, revert_snap): + """ + Check file existed + + :param test: test object. + :param vm: file list to be checked. + :param params: Dictionary with the test parameters + :param revert_snap: the reverted snapshot order. + """ + vm_name = params.get("main_vm") + + if not vm.is_alive(): + virsh.start(vm_name) + vm.cleanup_serial_console() + vm.create_serial_console() + session = vm.wait_for_serial_login() + + if revert_snap == "1": + file_list = eval(params.get("file_list"))[0:1] + elif revert_snap == "2": + file_list = eval(params.get("file_list")) + + for file in file_list: + status, _ = session.cmd_status_output("cat %s " % file) + if status: + test.fail("%s not exist" % file) + session.close() + + +def update_xml(params, test, vm): + """ + Update guest xml according to the scenarios. + + :param params: test parameters object + :param test: test object + :param vm: vm object + """ + updated_type = params.get("updated_type") + disk_dict = eval(params.get("disk_dict", "{}")) + disk_type = params.get("disk_type") + vm_name = params.get("main_vm") + set_cpu = params.get("set_cpu") + mode_cmd = params.get("mode_cmd") + blkiotune_cmd = params.get("blkiotune_cmd") + + disk_obj = disk_base.DiskBase(test, vm, params) + if updated_type == "hotplug_disk": + disk, image_path = disk_obj.prepare_disk_obj(disk_type, disk_dict) + virsh.attach_device(vm_name, disk.xml, **virsh_dargs) + + elif updated_type == "hotplug_vcpus": + virsh.setvcpu(vm_name, set_cpu, "--enable", **virsh_dargs) + + elif updated_type == "blkiotune": + process.run(mode_cmd, shell=True) + + res = process.run("lsscsi", shell=True).stdout_text.strip() + params.update( + {"dev": re.findall(r"Linux\s*scsi_debug\s*\d+\s+(\S+)\s*", res)[0]}) + virsh.blkiotune(vm_name, options=blkiotune_cmd % params.get("dev"), + **virsh_dargs) + + +def check_result_after_revert(params, test, vm, revert_snap): + """ + Check the result after revert corresponding snapshot + + :param params: test parameters object + :param test: test object + :param vm: vm object + :param revert_snap: the reverted snapshot order + """ + vm_name = params.get("main_vm") + updated_type = params.get("updated_type") + original_vcpu = eval(params.get("original_vcpu", "{}")) + new_vcpu = eval(params.get("new_vcpu", "{}")) + system_disk_pattern = params.get("system_disk_pattern") + new_disk_pattern = params.get("new_disk_pattern") + blkiotune_weight = params.get("weight") + + if updated_type == "hotplug_disk": + res = virsh.domblklist(vm_name, debug=True).stdout_text.strip() + if revert_snap == "1": + check_existed(test, res, system_disk_pattern) + elif revert_snap == "2": + check_existed(test, res, system_disk_pattern) + check_existed(test, res, new_disk_pattern) + + elif updated_type == "hotplug_vcpus": + vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) + actual_vcpu = vmxml.vcpus.vcpu[1] + if revert_snap == "1": + compare_value(test, actual_vcpu["enabled"], original_vcpu["enabled"]) + compare_value(test, actual_vcpu["hotpluggable"], original_vcpu["hotpluggable"]) + elif revert_snap == "2": + compare_value(test, actual_vcpu["enabled"], new_vcpu["enabled"]) + compare_value(test, actual_vcpu["hotpluggable"], new_vcpu["hotpluggable"]) + + elif updated_type == "blkiotune": + vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) + blkiotune = vmxml.xmltreefile.find(".//blkiotune") + if revert_snap == "1": + compare_value(test, blkiotune != '', True) + elif revert_snap == "2": + compare_value( + test, blkiotune.find('.//device/write_bytes_sec').text, + blkiotune_weight + ) + check_file_exist(test, vm, params, revert_snap) + + +def run(test, params, env): + """ + Revert snapshots after the guest xml is updated. + """ + def setup_test(): + """ + Define guest if needed. + """ + if updated_type == "hotplug_vcpus": + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + vmxml.setup_attrs(**vm_attrs) + virsh.define(vmxml.xml, **virsh_dargs) + test.log.debug("New guest xml is:\n%s", + vm_xml.VMXML.new_from_inactive_dumpxml(vm_name)) + + def run_test(): + """ + Revert snapshots after the guest xml is updated. + Update guest xml scenario: + hotplug disk/hotplug vcpus/blkiotune + """ + test.log.info("TEST_STEP1:Prepare a running guest and create file.") + vm.start() + session = vm.wait_for_serial_login() + create_file(vm, file_list[0], session) + + test.log.info("TEST_STEP2: Create snapshot.") + virsh.snapshot_create_as( + vm_name, snap_options % (snap_names[0], snap_names[0], + snap_names[0]), **virsh_dargs) + test.log.info("TEST_STEP3: Update xml by %s and create file in guest." % updated_type) + update_xml(params, test, vm) + create_file(vm, file_list[1]) + + test.log.info("TEST_STEP4: Create another snapshot after xml updated.") + virsh.snapshot_create_as( + vm_name, snap_options % (snap_names[1], snap_names[1], + snap_names[1]), **virsh_dargs) + + test.log.info("TEST_STEP5: Revert to the 1st snapshot and check file.") + virsh.snapshot_revert(vm_name, snap_names[0], **virsh_dargs) + check_result_after_revert(params, test, vm, "1") + + test.log.info("TEST_STEP6: Revert to the 2nd snapshot and check file.") + virsh.snapshot_revert(vm_name, snap_names[1], **virsh_dargs) + check_result_after_revert(params, test, vm, "2") + + def teardown_test(): + """ + Clean data. + """ + test.log.info("TEST_TEARDOWN: Clean up env.") + snap_names.reverse() + test_obj.teardown_test() + + vm_name = params.get("main_vm") + original_xml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + params['backup_vmxml'] = original_xml.copy() + vm = env.get_vm(vm_name) + + snap_names = eval(params.get("snap_names", '[]')) + updated_type = params.get("updated_type") + snap_options = params.get("snap_options") + vm_attrs = eval(params.get("vm_attrs", "{}")) + file_list = eval(params.get("file_list", '[]')) + test_obj = snapshot_base.SnapshotTest(vm, test, params) + + libvirt_version.is_libvirt_feature_supported(params) + + try: + setup_test() + run_test() + + finally: + teardown_test() diff --git a/libvirt/tests/src/snapshot/snapshot_list_with_options.py b/libvirt/tests/src/snapshot/snapshot_list_with_options.py new file mode 100644 index 00000000000..7b4b7788ce7 --- /dev/null +++ b/libvirt/tests/src/snapshot/snapshot_list_with_options.py @@ -0,0 +1,92 @@ +# Copyright Redhat +# +# SPDX-License-Identifier: GPL-2.0 + +# Author: Meina Li + +from virttest import libvirt_version +from virttest import virsh +from virttest.libvirt_xml import vm_xml + +from provider.snapshot import snapshot_base + + +def run(test, params, env): + """ + Get guest snapshot list with different options. + """ + def create_snapshots(vm_name, snap_names): + """ + Create snapshots for guest. + + :params vm_name: the vm name + :params snap_names: the created snapshot names + """ + test.log.info("TEST_SETUP: Prepare shutoff guest and create a snapshot.") + virsh.snapshot_create_as(vm_name, "%s --disk-only" % snap_names[0], **virsh_dargs) + test.log.info("TEST_SETUP: Prepare running guest and create a disk only snapshot.") + if not vm.is_alive(): + vm.start() + vm.wait_for_login().close() + virsh.snapshot_create_as(vm_name, "%s --disk-only" % snap_names[1], **virsh_dargs) + test.log.info("TEST_SETUP: Prepare running guest and create a disk and mempry snapshot.") + for i in range(2, 4): + virsh.snapshot_create_as(vm_name, + "%s" % (snap_options % (snap_names[i], snap_names[i])), + **virsh_dargs) + for snap_name in snap_names: + test_obj.check_snap_list(snap_name) + + def check_snap_list(snap_list): + """ + Check the list snapshots of guest to match expected ones. + + :params snap_list: the snapshots created in setup + """ + if special_check: + list_dict = {} + cmd = "snapshot-list %s %s" % (vm_name, list_options) + list_result = virsh.command(cmd, **virsh_dargs).stdout_text.split() + list_dict[list_result[0]] = '' + for num in range(1, len(list_result), 2): + key = list_result[num] + value = list_result[num+1] + list_dict[key] = value + for key, value in expected_dict.items(): + if list_dict.get(key) != value: + test.fail("Get incorrect result %s, the expected result is %s" % + (list_result, expected_dict)) + test.log.debug("Get expected result for snapshot-list options %s", + list_options) + for snap_name in expected_list: + if snap_name not in snap_list: + test.fail("Snapshot %s doesn't exist" % snap_name) + else: + test.log.info("Snapshot %s is in expected snapshot list.", snap_name) + + vm_name = params.get("main_vm") + snap_names = eval(params.get("snap_names", "[]")) + snap_options = params.get("snap_options") + list_options = params.get("list_options") + expected_list = eval(params.get("expected_list", "[]")) + expected_dict = eval(params.get("expected_dict", "{}")) + special_check = "yes" == params.get("special_check", "no") + 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() + virsh_dargs = {"debug": True, "ignore_status": False} + test_obj = snapshot_base.SnapshotTest(vm, test, params) + + try: + test.log.info("STEP1: Create snapshots.") + create_snapshots(vm_name, snap_names) + test.log.info("STEP2: List snapshots.") + snap_list = virsh.snapshot_list(vm_name, list_options, **virsh_dargs) + test.log.info("STEP3: Check the listed snapshots.") + check_snap_list(snap_list) + finally: + snap_names.reverse() + test_obj.teardown_test() + bkxml.sync() diff --git a/libvirt/tests/src/sriov/capabilities/sriov_capabilities_iommu_support.py b/libvirt/tests/src/sriov/capabilities/sriov_capabilities_iommu_support.py index 282c5f224ac..039b48706ac 100644 --- a/libvirt/tests/src/sriov/capabilities/sriov_capabilities_iommu_support.py +++ b/libvirt/tests/src/sriov/capabilities/sriov_capabilities_iommu_support.py @@ -1,6 +1,3 @@ -import re - -from virttest import utils_misc from virttest.libvirt_xml import capability_xml @@ -8,11 +5,6 @@ def run(test, params, env): """ check virsh capabilities output includes iommu support element """ - kernel_cmd = utils_misc.get_ker_cmd() - res = re.search("iommu=on", kernel_cmd) - if not res: - test.error("iommu should be enabled in kernel cmd line - " - "'%s'." % kernel_cmd) cap_xml = capability_xml.CapabilityXML() if cap_xml.get_iommu().get('support') != 'yes': test.fail("IOMMU is disabled in capabilities: %s. " diff --git a/libvirt/tests/src/sriov/locked_memory_check/sriov_with_hotplug_memory.py b/libvirt/tests/src/sriov/locked_memory_check/sriov_with_hotplug_memory.py new file mode 100644 index 00000000000..92ff6c44609 --- /dev/null +++ b/libvirt/tests/src/sriov/locked_memory_check/sriov_with_hotplug_memory.py @@ -0,0 +1,139 @@ +from virttest import virsh + +from virttest.libvirt_xml import vm_xml +from virttest.utils_libvirt import libvirt_memory, libvirt_vmxml +from virttest.utils_test import libvirt + +from provider.sriov import sriov_base + + +def run(test, params, env): + """ + Hotplug memory to vm with hostdev type device and check the memory lock limit. + """ + def setup_test(vm_name, dev_type, iface_dict): + """ + Prepare vm xml with device and memory setting then start guest. + + :params vm_name: the vm name + :params dev_type: the device type, includes hostdev device and interface + :params iface_dict: the dict of hostdev interface/device + :params return: the tuple of vmxml and with_hostdev_device value + """ + test.log.info("SETUP_STEP1: prepare vm xml with memory setting.") + vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) + vmxml.setup_attrs(**vm_attrs) + vmxml.sync() + with_hostdev_device = False + if not without_hostdev: + test.log.info("SETUP_STEP2: prepare vm xml with device.") + sriov_test_obj.setup_default(dev_name=dev_name) + iface_dev = sriov_test_obj.create_iface_dev(dev_type, iface_dict) + libvirt.add_vm_device(vmxml, iface_dev) + with_hostdev_device = True + return vmxml, with_hostdev_device + + def check_memory_limit(vmxml, current_mem, with_hostdev_device=True, mem_changed=True): + """ + Check the locked memory limit. + + :params vmxml: the vm xml + :params current_mem: the expected current memory + :params with_hostdev_device: boolean to use check if the vm has hostdev device + :params mem_changed: boolean to use check if the MEMLOCK is changed + """ + if int(current_mem) != int(vmxml.get_current_mem() * 1024): + test.fail("The current memory is incorrect after hot-unplugged.") + + # With_hardlimit: MEMLOCK value is equal to the hard_limit value + if mem_set == "with_hardlimit": + expr_memlock = libvirt_memory.normalize_mem_size( + vmxml.memtune.hard_limit, + vmxml.memtune.hard_limit_unit) + + # Without_hardlimit: MEMLOCK value is current memory + 1G + if mem_set == "without_hardlimit": + if without_hostdev and not with_hostdev_device: + expr_memlock = one_G_bytes // 16 + if with_hostdev_device: + if not mem_changed: + expr_memlock = current_mem + one_G_bytes * 2 + else: + expr_memlock = current_mem + one_G_bytes + + if not libvirt_memory.comp_memlock(expr_memlock): + test.fail("Unable to get correct MEMLOCK!") + + def hotplug_mem_device(vm_name, mem_dict, current_mem): + """ + Hotplug the memory device and check locked memory limit. + + :params vm_name: the vm name + :params mem_dict: the dict of memory device + :params current_mem: the expected current memory + """ + mem_xml = libvirt_vmxml.create_vm_device_by_type("memory", mem_dict) + virsh.attach_device(vm_name, mem_xml.xml, debug=True, ignore_status=False) + vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) + check_memory_limit(vmxml, current_mem) + + vm_name = params.get("main_vm", "avocado-vt-vm1") + vm = env.get_vm(vm_name) + dev_type = params.get("dev_type", "") + dev_source = params.get("dev_source", "") + mem_set = params.get("mem_set", "") + mem_dict1 = eval(params.get("mem_dict1", "{}")) + mem_dict2 = eval(params.get("mem_dict2", "{}")) + without_hostdev = "yes" == params.get("without_hostdev", "no") + + vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) + backup_vmxml = vmxml.copy() + num_memory = int(vmxml.get_current_mem() / 2) + vm_attrs = eval(params.get("vm_attrs", "{}") % (num_memory, num_memory)) + + sriov_test_obj = sriov_base.SRIOVTest(vm, test, params) + if dev_type == "hostdev_device" and dev_source.startswith("pf"): + dev_name = sriov_test_obj.pf_dev_name + else: + dev_name = sriov_test_obj.vf_dev_name + iface_dict = sriov_test_obj.parse_iface_dict() + + one_G_bytes = 1073741824 + + try: + vmxml, with_hostdev_device = setup_test(vm_name, dev_type, iface_dict) + test.log.info("TEST_STEP: Start the vm and check locked memory limit.") + vm.start() + test.log.debug("The current guest xml is:%s", virsh.dumpxml(vm_name).stdout_text) + vm.wait_for_login(timeout=240).close() + default_mem = libvirt_memory.normalize_mem_size( + vmxml.get_current_mem(), + vmxml.get_current_mem_unit()) + check_memory_limit(vmxml, default_mem, with_hostdev_device) + if without_hostdev: + test.log.info("TEST_STEP: Hotplug iface device and check locked memory limit.") + iface_dev = sriov_test_obj.create_iface_dev(dev_type, iface_dict) + virsh.attach_device(vm_name, iface_dev.xml, debug=True, ignore_status=False) + vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) + check_memory_limit(vmxml, default_mem, with_hostdev_device=True) + test.log.info("TEST_STEP: Hotplug 1st memory device and check locked memory limit.") + first_mem = default_mem + one_G_bytes + hotplug_mem_device(vm_name, mem_dict1, first_mem) + test.log.info("TEST_STEP: Hotplug 2nd memory device and check locked memory limit.") + second_mem = first_mem + one_G_bytes + hotplug_mem_device(vm_name, mem_dict2, second_mem) + test.log.info("TEST_STEP: Hot-unplug 2nd memory device and check locked memory limit.") + memxml = vm_xml.VMXML.new_from_dumpxml(vm_name).get_devices('memory')[-1] + virsh.detach_device(vm_name, memxml.xml, ignore_status=False, debug=True, + wait_for_event=True) + vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) + check_memory_limit(vmxml, first_mem, mem_changed=False) + if without_hostdev: + test.log.info("TEST_STEP: Hot-unplug iface device and check locked memory limit.") + virsh.detach_device(vm_name, iface_dev.xml, debug=True, ignore_status=False, + wait_for_event=True, event_timeout=30) + vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) + check_memory_limit(vmxml, first_mem, with_hostdev_device=False) + finally: + sriov_test_obj.teardown_default(dev_name=dev_name) + backup_vmxml.sync() diff --git a/libvirt/tests/src/sriov/network/sriov_check_network_connections.py b/libvirt/tests/src/sriov/network/sriov_check_network_connections.py new file mode 100644 index 00000000000..ade32808a2a --- /dev/null +++ b/libvirt/tests/src/sriov/network/sriov_check_network_connections.py @@ -0,0 +1,46 @@ +from virttest import virsh + +from virttest.libvirt_xml import vm_xml +from virttest.utils_libvirt import libvirt_network +from virttest.utils_libvirt import libvirt_vmxml + +from provider.sriov import sriov_base + + +def run(test, params, env): + """ + Check the number of connections on hostdev network + """ + vm_name = params.get("main_vm", "avocado-vt-vm1") + vm = env.get_vm(vm_name) + sriov_test_obj = sriov_base.SRIOVTest(vm, test, params) + network_dict = sriov_test_obj.parse_network_dict() + net_name = network_dict.get("name") + iface_dict = eval(params.get("iface_dict", "{}")) + iface_nums = int(params.get("iface_nums", "2")) + + try: + sriov_test_obj.setup_default(network_dict=network_dict) + for idx in range(iface_nums): + libvirt_vmxml.modify_vm_device( + vm_xml.VMXML.new_from_inactive_dumpxml(vm_name), + 'interface', iface_dict, idx) + test.log.debug(f"vm xml: {vm_xml.VMXML.new_from_dumpxml(vm_name)}") + + test.log.info("TEST_STEP: Start a VM with hostdev interfaces.") + vm.start() + vm.wait_for_serial_login().close() + + test.log.info(f"TEST_STEP: Check if there are {iface_nums} network connections.") + libvirt_network.check_network_connection(net_name, iface_nums) + + test.log.info(f"TEST_STEP: Destroy and start network and vm.") + virsh.net_destroy(net_name, debug=True, ignore_status=False) + virsh.net_start(net_name, debug=True, ignore_status=False) + vm.destroy() + vm.start() + + test.log.info(f"TEST_STEP: Check if there are {iface_nums} network connections.") + libvirt_network.check_network_connection(net_name, iface_nums) + finally: + sriov_test_obj.teardown_default(network_dict=network_dict) diff --git a/libvirt/tests/src/sriov/plug_unplug/sriov_attach_detach_device.py b/libvirt/tests/src/sriov/plug_unplug/sriov_attach_detach_device.py index f60530786a7..85cb4e49bc9 100644 --- a/libvirt/tests/src/sriov/plug_unplug/sriov_attach_detach_device.py +++ b/libvirt/tests/src/sriov/plug_unplug/sriov_attach_detach_device.py @@ -45,6 +45,7 @@ def run_test(): vm_hostdev = vm_xml.VMXML.new_from_dumpxml(vm.name)\ .devices.by_device_tag(device_type)[0] virsh.detach_device(vm.name, vm_hostdev.xml, debug=True, + wait_for_event=True, ignore_status=False) cur_hostdevs = vm_xml.VMXML.new_from_dumpxml(vm.name)\ .devices.by_device_tag(device_type) diff --git a/libvirt/tests/src/sriov/plug_unplug/sriov_attach_detach_device_after_restarting_service.py b/libvirt/tests/src/sriov/plug_unplug/sriov_attach_detach_device_after_restarting_service.py index ccb7cdfd304..868ace7a5ec 100644 --- a/libvirt/tests/src/sriov/plug_unplug/sriov_attach_detach_device_after_restarting_service.py +++ b/libvirt/tests/src/sriov/plug_unplug/sriov_attach_detach_device_after_restarting_service.py @@ -1,3 +1,5 @@ +import time + from provider.sriov import sriov_base from virttest import utils_libvirtd @@ -36,7 +38,7 @@ def run_test(): iface_dev = sriov_test_obj.create_iface_dev(dev_type, iface_dict) virsh.attach_device(vm.name, iface_dev.xml, debug=True, ignore_status=False) - + time.sleep(10) test.log.info("TEST_STEP3: Detach the hostdev interface/device") virsh.detach_device(vm.name, iface_dev.xml, debug=True, ignore_status=False) diff --git a/libvirt/tests/src/sriov/plug_unplug/sriov_attach_detach_device_vfio_variant_driver.py b/libvirt/tests/src/sriov/plug_unplug/sriov_attach_detach_device_vfio_variant_driver.py new file mode 100644 index 00000000000..f5c93e903ee --- /dev/null +++ b/libvirt/tests/src/sriov/plug_unplug/sriov_attach_detach_device_vfio_variant_driver.py @@ -0,0 +1,98 @@ +import time + +from virttest import utils_net +from virttest import utils_sriov +from virttest import utils_test +from virttest import virsh + +from virttest.libvirt_xml import vm_xml +from virttest.utils_libvirt import libvirt_vfio +from virttest.utils_libvirt import libvirt_vmxml + + +def run(test, params, env): + """ + Attach/detach device of hostdev type with vfio variant driver to/from guest + """ + def parse_iface_dict(pf_pci): + """ + Parse interface dictionary from parameters + """ + mac_addr = utils_net.generate_mac_address_simple() + + vf_pci_addr = utils_sriov.pci_to_addr(vf_pci) + if params.get('iface_dict'): + iface_dict = eval(params.get('iface_dict', '{}')) + else: + if vf_pci_addr.get('type'): + del vf_pci_addr['type'] + iface_dict = eval(params.get('hostdev_dict', '{}')) + driver_dict = eval(params.get("pf_pci", "{}")) + if driver_dict: + iface_dict.update(driver_dict) + managed = params.get("managed") + if managed: + iface_dict.update({"manged": managed}) + test.log.debug(f"Iface dict: {iface_dict}") + + return iface_dict + + dev_type = params.get("dev_type", "hostdev_interface") + device_type = "hostdev" if dev_type == "hostdev_device" else "interface" + expr_driver = params.get("expr_driver", "mlx5_vfio_pci") + test_pf = params.get("test_pf", "ens3f0np0") + pf_pci = utils_sriov.get_pf_pci(test_pf=test_pf) + iface_number = int(params.get("iface_number", "1")) + ping_dest = params.get("ping_dest", "www.redhat.com") + + vm_name = params.get("main_vm", "avocado-vt-vm1") + vm = env.get_vm(vm_name) + new_xml = vm_xml.VMXML.new_from_inactive_dumpxml(vm.name) + orig_vm_xml = new_xml.copy() + try: + libvirt_vmxml.remove_vm_devices_by_type(vm, 'interface') + libvirt_vmxml.remove_vm_devices_by_type(vm, 'hostdev') + + test.log.info("TEST_STEP: Start the VM") + vm.start() + vm_session = vm.wait_for_serial_login(timeout=240) + # FIXME: If the "IP" command is executed immediately after the interface + # is attached, it will be hung. + time.sleep(10) + + for idx in range(iface_number): + test.log.info("TEST_STEP: Attach a hostdev interface/device to VM") + vf_pci = utils_sriov.get_vf_pci_id(pf_pci, idx) + iface_dict = parse_iface_dict(vf_pci) + iface_dev = libvirt_vmxml.create_vm_device_by_type(device_type, iface_dict) + virsh.attach_device(vm.name, iface_dev.xml, ignore_status=False, + debug=True) + actual_vm_hostdev = vm_xml.VMXML.new_from_dumpxml(vm.name)\ + .devices.by_device_tag(device_type)[idx] + act_hostdev_dict = actual_vm_hostdev.fetch_attrs() + test.log.debug(f"Actual XML: {actual_vm_hostdev}") + if act_hostdev_dict.get("driver")["driver_attr"].get("name") != "vfio": + test.fail("The hostdev driver is not set to VFIO.") + libvirt_vfio.check_vfio_pci(vf_pci, exp_driver=expr_driver) + if utils_test.ping(ping_dest, count=3, timeout=5, session=vm_session): + test.fail("Failed to ping %s." % ping_dest) + + vm_hostdevs = vm_xml.VMXML.new_from_dumpxml(vm.name)\ + .devices.by_device_tag(device_type) + for vm_dev in vm_hostdevs: + test.log.info("TEST_STEP: Detach a hostdev interface/device from VM") + virsh.detach_device(vm.name, vm_dev.xml, debug=True, + wait_for_event=True, ignore_status=False) + vm_hostdevs = vm_xml.VMXML.new_from_dumpxml(vm.name)\ + .devices.by_device_tag(device_type) + if vm_hostdevs: + test.fail("Got hostdev interface/device(%s) after detaching the " + "device!" % vm_hostdevs) + libvirt_vfio.check_vfio_pci(vf_pci, exp_driver="mlx5_core") + virsh.reboot(vm.name, ignore_status=False, debug=True) + vm.cleanup_serial_console() + vm.create_serial_console() + vm.wait_for_serial_login().close() + + finally: + orig_vm_xml.sync() diff --git a/libvirt/tests/src/sriov/plug_unplug/sriov_attach_detach_interface_special_situations.py b/libvirt/tests/src/sriov/plug_unplug/sriov_attach_detach_interface_special_situations.py index ebe0f4c2698..b6496258413 100644 --- a/libvirt/tests/src/sriov/plug_unplug/sriov_attach_detach_interface_special_situations.py +++ b/libvirt/tests/src/sriov/plug_unplug/sriov_attach_detach_interface_special_situations.py @@ -27,10 +27,8 @@ def setup_test(): debug=True, ignore_status=False) elif test_scenario == "module_auto_reload": - modules = ["vfio_pci", "vfio_iommu_type1"] - test.log.info("TEST_SETUP: Remove modules: %s." % modules) - for module_name in modules: - KernelModuleHandler(module_name).unload_module() + test.log.info("TEST_SETUP: Remove vfio module.") + KernelModuleHandler("vfio").unload_module() def check_vm_iface_after_detaching(test_scenario): """ diff --git a/libvirt/tests/src/sriov/scalability/sriov_scalability_max_vfs.py b/libvirt/tests/src/sriov/scalability/sriov_scalability_max_vfs.py index 85b44380e04..936561fa61b 100644 --- a/libvirt/tests/src/sriov/scalability/sriov_scalability_max_vfs.py +++ b/libvirt/tests/src/sriov/scalability/sriov_scalability_max_vfs.py @@ -1,7 +1,3 @@ -from provider.interface import interface_base -from provider.sriov import check_points -from provider.sriov import sriov_base - from virttest import utils_misc from virttest import utils_sriov from virttest import virsh @@ -11,6 +7,10 @@ from virttest.utils_libvirt import libvirt_vmxml from virttest.utils_test import libvirt +from provider.interface import interface_base +from provider.sriov import check_points +from provider.sriov import sriov_base + def get_vm_iface_num(vm_name): """ @@ -79,7 +79,7 @@ def setup_test(): test.log.info("TEST_SETUP: Remove VM's interface devices.") libvirt_vmxml.remove_vm_devices_by_type(vm, 'interface') - test.log.info("TEST_SETUP: Cold plug 64 interfaces to VM.") + test.log.info(f"TEST_SETUP: Cold plug {iface_num} interfaces to VM.") opts = "network %s --config" % list(net_info.values())[0] for i in range(vf_no): iface_dict = { @@ -94,11 +94,13 @@ def setup_test(): if i % 8 == 0: iface_dict['address']['attrs'].update({'multifunction': 'on'}) iface_dev = interface_base.create_iface("network", iface_dict) - virsh.attach_device(vm.name, iface_dev.xml, flagstr="--config", debug=True, ignore_status=False) - net_name_2 = list(net_info.values())[1] - opts = "network %s --config" % net_name_2 - virsh.attach_interface(vm_name, opts, debug=True, ignore_status=False) - compare_vm_iface(test, get_vm_iface_num(vm_name), vf_no+1) + virsh.attach_device(vm.name, iface_dev.xml, flagstr="--config", + debug=True, ignore_status=False) + for i in range(iface_num - vf_no): + net_name_2 = list(net_info.values())[1] + opts = "network %s --config" % net_name_2 + virsh.attach_interface(vm_name, opts, debug=True, ignore_status=False) + compare_vm_iface(test, get_vm_iface_num(vm_name), iface_num) def teardown_test(): """ @@ -126,7 +128,11 @@ def run_test(): 5. Try to hot plug the 65th hostdev interface """ test.log.info("TEST_STEP1: Start the VM and check networks.") - vm.start() + result = virsh.start(vm.name, debug=True) + libvirt.check_exit_status(result, start_error) + if start_error: + return + vm.create_serial_console() vm_session = vm.wait_for_serial_login(timeout=240) res = vm_session.cmd_status_output( 'lspci |grep Ether')[1].strip().splitlines() @@ -180,6 +186,8 @@ def compare_vm_iface(test, vm_iface_num, expr_no): driver = utils_sriov.get_pf_info_by_pci(pf_pci).get('driver') net_info = get_net_dict(pf_info) vf_no = int(params.get("vf_no", "63")) + iface_num = int(params.get("iface_num", "64")) + start_error = "yes" == params.get("start_error", "no") vm_name = params.get("main_vm", "avocado-vt-vm1") vm = env.get_vm(vm_name) diff --git a/libvirt/tests/src/sriov/vIOMMU/attach_iommu_device.py b/libvirt/tests/src/sriov/vIOMMU/attach_iommu_device.py new file mode 100644 index 00000000000..7ff0bb3f169 --- /dev/null +++ b/libvirt/tests/src/sriov/vIOMMU/attach_iommu_device.py @@ -0,0 +1,44 @@ +from virttest import libvirt_version +from virttest import virsh + +from virttest.libvirt_xml import vm_xml +from virttest.utils_libvirt import libvirt_vmxml +from virttest.utils_test import libvirt + + +def run(test, params, env): + """ + Hotplug or coldplug iommu device to guest + """ + libvirt_version.is_libvirt_feature_supported(params) + iommu_dict = eval(params.get('iommu_dict', '{}')) + attach_option = params.get("attach_option", "") + err_msg = params.get("err_msg") + + vm_name = params.get("main_vm", "avocado-vt-vm1") + vm = env.get_vm(vm_name) + vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) + backup_vmxml = vmxml.copy() + try: + if attach_option and vm.is_alive(): + vm.destroy() + elif not attach_option and not vm.is_alive(): + vm.start() + vm.wait_for_login().close() + if libvirt_version.version_compare(10, 5, 0) and attach_option: + vmxml = vm_xml.VMXML.new_from_dumpxml(vm.name) + features = vmxml.features + if not features.has_feature('ioapic') and iommu_dict.get('model') == "intel": + features.add_feature('ioapic', 'driver', 'qemu') + vmxml.features = features + vmxml.sync() + err_msg = '' + + libvirt_vmxml.remove_vm_devices_by_type(vm, 'iommu') + iommu_dev = libvirt_vmxml.create_vm_device_by_type('iommu', iommu_dict) + test.log.debug(f"iommu device: {iommu_dev}") + res = virsh.attach_device(vm.name, iommu_dev.xml, debug=True, + flagstr=attach_option) + libvirt.check_result(res, err_msg) + finally: + backup_vmxml.sync() diff --git a/libvirt/tests/src/sriov/vIOMMU/hotplug_device_with_iommu_enabled.py b/libvirt/tests/src/sriov/vIOMMU/hotplug_device_with_iommu_enabled.py new file mode 100644 index 00000000000..12e821a688e --- /dev/null +++ b/libvirt/tests/src/sriov/vIOMMU/hotplug_device_with_iommu_enabled.py @@ -0,0 +1,119 @@ +import os +import time + +from virttest import data_dir +from virttest import utils_disk +from virttest import utils_net +from virttest import virsh + +from virttest.libvirt_xml import vm_xml +from virttest.utils_libvirt import libvirt_disk +from virttest.utils_libvirt import libvirt_vmxml + +from provider.sriov import sriov_base +from provider.viommu import viommu_base +from provider.sriov import check_points as sriov_check_points + + +def run(test, params, env): + """ + Hotplug devices with iommu enabled to a vm with an iommu device + """ + def detach_dev(device_type, dev_iommu_info, vm_session): + """ + Detach device and check iommu group if needed + + :param device_type: Device type + :param dev_iommu_info: Device's iommu group info + :param vm_session: VM session + """ + dev_obj = vm_xml.VMXML.new_from_dumpxml(vm_name).get_devices(device_type)[-1] + virsh.detach_device(vm_name, dev_obj.xml, wait_for_event=True, + debug=True, ignore_status=False) + if not dev_iommu_info: + return + for dev_info in dev_iommu_info: + if dev_info: + res = vm_session.cmd_status_output('ifconfig') + test.log.debug(res) + s, o = vm_session.cmd_status_output("ls %s" % dev_info) + test.log.debug(f"{device_type} iommu check: {o}") + if not s: + test.fail("The %s should be removed from the iommu group" % device_type) + + cleanup_ifaces = params.get("cleanup_ifaces", "yes") + disk_dict = eval(params.get('disk_dict', '{}')) + + ping_dest = params.get('ping_dest') + iommu_dict = eval(params.get('iommu_dict', '{}')) + test_devices = eval(params.get("test_devices", "[]")) + need_sriov = "yes" == params.get("need_sriov", "no") + + vm_name = params.get("main_vm", "avocado-vt-vm1") + vm = env.get_vm(vm_name) + sroiv_test_obj = None + new_disk_path = None + + test_obj = viommu_base.VIOMMUTest(vm, test, params) + if need_sriov: + sroiv_test_obj = sriov_base.SRIOVTest(vm, test, params) + + try: + test_obj.setup_iommu_test(iommu_dict=iommu_dict, cleanup_ifaces=cleanup_ifaces) + test_obj.prepare_controller() + test.log.info("TEST_STEP: Start the VM.") + if not vm.is_alive(): + vm.start() + vm.cleanup_serial_console() + vm.create_serial_console() + vm_session = vm.wait_for_serial_login( + timeout=int(params.get('login_timeout'))) + pre_devices = viommu_base.get_devices_pci(vm_session, test_devices) + if disk_dict: + test.log.info("TEST_STEP: Attach a disk device to VM.") + disk_dict = test_obj.update_disk_addr(disk_dict) + disk_size = params.get("size", "200M") + new_disk_path = os.path.join(data_dir.get_data_dir(), "images", "test.qcow2") + libvirt_disk.create_disk("file", new_disk_path, disk_size, disk_format="qcow2") + disk_dict.update({'source': {'attrs': {'file': new_disk_path}}}) + disk_obj = libvirt_vmxml.create_vm_device_by_type('disk', disk_dict) + virsh.attach_device(vm.name, disk_obj.xml, debug=True, ignore_status=False, wait_for_event=True) + + if need_sriov: + test_obj.params["iface_dict"] = str(sroiv_test_obj.parse_iface_dict()) + iface_dict = test_obj.parse_iface_dict() + + if cleanup_ifaces == "yes": + iface_obj = libvirt_vmxml.create_vm_device_by_type("interface", iface_dict) + virsh.attach_device(vm.name, iface_obj.xml, debug=True, ignore_status=False) + # Sleep 20s to stabilize the attached interface + time.sleep(20) + + test.log.info("TEST_STEP: Check dmesg message about iommu inside the vm.") + vm_session.cmd("dmesg | grep -i 'Adding to iommu group'", timeout=300) + dev_iommu_groups = viommu_base.check_vm_iommu_group(vm_session, test_devices, pre_devices) + test.log.debug(f"Device iommu groups info: {dev_iommu_groups}") + + if "block" in test_devices: + test.log.info("TEST_STEP: Check VM disk io.") + new_disk = libvirt_disk.get_non_root_disk_name(vm_session)[0] + utils_disk.dd_data_to_vm_disk(vm_session, new_disk) + test.log.info("TEST_STEP: Detach the disk.") + detach_dev("disk", dev_iommu_groups["block"], vm_session) + + test.log.info("TEST_STEP: Check VM network.") + if need_sriov: + sriov_check_points.check_vm_network_accessed(vm_session, ping_dest=ping_dest) + else: + + s, o = utils_net.ping(ping_dest, count=5, timeout=240, session=vm_session) + if s: + test.fail("Failed to ping %s! status: %s, output: %s." % (ping_dest, s, o)) + + test.log.info("TEST_STEP: Detach the interface.") + detach_dev("interface", dev_iommu_groups.get("Eth"), vm_session) + + finally: + test_obj.teardown_iommu_test() + if new_disk_path and os.path.exists(new_disk_path): + os.remove(new_disk_path) diff --git a/libvirt/tests/src/sriov/vIOMMU/intel_iommu_aw_bits.py b/libvirt/tests/src/sriov/vIOMMU/intel_iommu_aw_bits.py new file mode 100644 index 00000000000..fabd465b5a2 --- /dev/null +++ b/libvirt/tests/src/sriov/vIOMMU/intel_iommu_aw_bits.py @@ -0,0 +1,40 @@ +from virttest import virsh + +from virttest.libvirt_xml import vm_xml +from virttest.utils_test import libvirt + +from provider.viommu import viommu_base + + +def run(test, params, env): + """ + Start vm with different iommu address width values. + """ + iommu_dict = eval(params.get('iommu_dict', '{}')) + aw_bits_value = params.get("aw_bits_value") + err_msg = params.get("err_msg") + status_error = "yes" == params.get("status_error", "no") + + vm_name = params.get("main_vm", "avocado-vt-vm1") + vm = env.get_vm(vm_name) + test_obj = viommu_base.VIOMMUTest(vm, test, params) + try: + test_obj.setup_iommu_test(iommu_dict=iommu_dict) + + test.log.info("TEST_STEP: Start the VM.") + result = virsh.start(vm.name, debug=True) + libvirt.check_exit_status(result, status_error) + if status_error: + if err_msg: + libvirt.check_result(result, err_msg) + return + vm.cleanup_serial_console() + vm.create_serial_console() + vm_session = vm.wait_for_serial_login( + timeout=int(params.get('login_timeout'))) + test.log.debug(vm_xml.VMXML.new_from_dumpxml(vm.name)) + + test.log.info("TEST_STEP: Check dmesg message.") + vm_session.cmd("dmesg | grep -i 'Host address width %s'" % aw_bits_value) + finally: + test_obj.teardown_iommu_test() diff --git a/libvirt/tests/src/sriov/vIOMMU/intel_iommu_with_dma_translation.py b/libvirt/tests/src/sriov/vIOMMU/intel_iommu_with_dma_translation.py new file mode 100644 index 00000000000..cda4e9e539a --- /dev/null +++ b/libvirt/tests/src/sriov/vIOMMU/intel_iommu_with_dma_translation.py @@ -0,0 +1,49 @@ +from avocado.utils import cpu +from virttest import virsh +from virttest.libvirt_xml import vm_xml + +from provider.viommu import viommu_base + + +def run(test, params, env): + """ + Start vm with Intel iommu and dma_translation attribute. + """ + vm_name = params.get("main_vm", "avocado-vt-vm1") + vm = env.get_vm(vm_name) + dma_translation = params.get("dma_translation") + guest_vcpus = params.get("guest_vcpus") + eim_dict = eval(params.get("eim_dict", "{}")) + iommu_dict = eval(params.get("iommu_dict", "{}")) + with_more_vcpus = "yes" == params.get("with_more_vcpus", "no") + test_obj = viommu_base.VIOMMUTest(vm, test, params) + + try: + iommu_dict['driver'].update(eim_dict) + test.log.info("TEST STEP1: Prepare guest xml with intel iommu device.") + test_obj.setup_iommu_test(iommu_dict=iommu_dict) + if with_more_vcpus: + vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) + guest_vcpus = cpu.online_count() + vmxml.vcpu = int(guest_vcpus) + vmxml.sync() + test.log.info("TEST STEP2: Start the guest.") + vm.start() + test.log.debug("The current guest xml ls: %s", + virsh.dumpxml(vm_name).stdout_text) + test.log.info("TEST STEP3: Check the message for iommu group and DMA.") + vm.cleanup_serial_console() + vm.create_serial_console() + vm_session = vm.wait_for_serial_login(timeout=1000) + dma_status, dma_o = vm_session.cmd_status_output("dmesg | grep -i 'Not attempting DMA translation'") + iommu_status, iommu_o = vm_session.cmd_status_output("dmesg | grep -i 'Adding to iommu group'") + if dma_translation == "on" and (not dma_status or iommu_status): + test.fail("Can't get expected dma message %s when enabling dma_translation." % dma_o) + if dma_translation == "off" and (dma_status or not iommu_status): + test.fail("Can't get expected iommu message %s when disabling dma_translation." % iommu_o) + if with_more_vcpus: + s, o = vm_session.cmd_status_output("cat /proc/cpuinfo | grep processor| wc -l") + if int(o) != int(guest_vcpus): + test.fail("Can't get expected vCPU number, the actual number is %s" % o) + finally: + test_obj.teardown_iommu_test() diff --git a/libvirt/tests/src/sriov/vIOMMU/intel_iommu_without_enabling_caching_mode.py b/libvirt/tests/src/sriov/vIOMMU/intel_iommu_without_enabling_caching_mode.py new file mode 100644 index 00000000000..71c914ba0cc --- /dev/null +++ b/libvirt/tests/src/sriov/vIOMMU/intel_iommu_without_enabling_caching_mode.py @@ -0,0 +1,45 @@ +from virttest import virsh + +from virttest.utils_test import libvirt + +from provider.sriov import sriov_base + + +def run(test, params, env): + """ + This case is to test hostdev interface with IOMMU device but no + cache_mode=on. + """ + attach_option = params.get("attach_option", "") + err_msg = params.get("err_msg") + dev_type = params.get("dev_type", "") + iommu_dict = eval(params.get('iommu_dict', '{}')) + + vm_name = params.get("main_vm", "avocado-vt-vm1") + vm = env.get_vm(vm_name) + + test_obj = sriov_base.SRIOVTest(vm, test, params) + iface_dict = test_obj.parse_iface_dict() + + try: + test_obj.setup_iommu_test(iommu_dict=iommu_dict, cleanup_ifaces=False) + + if attach_option and vm.is_alive(): + vm.destroy() + elif not attach_option and not vm.is_alive(): + vm.start() + vm.wait_for_login().close() + + iface_dev = test_obj.create_iface_dev(dev_type, iface_dict) + test.log.info("TEST_STEP: Attach hostdev interface.") + res = virsh.attach_device(vm.name, iface_dev.xml, debug=True, + flagstr=attach_option) + if attach_option: + libvirt.check_exit_status(res) + test.log.info("TEST_STEP: Start vm with hostdev.") + res = virsh.start(vm.name, debug=True) + + libvirt.check_result(res, err_msg) + + finally: + test_obj.teardown_iommu_test() diff --git a/libvirt/tests/src/sriov/vIOMMU/intel_iommu_without_ioapic.py b/libvirt/tests/src/sriov/vIOMMU/intel_iommu_without_ioapic.py new file mode 100644 index 00000000000..b7b3cb52524 --- /dev/null +++ b/libvirt/tests/src/sriov/vIOMMU/intel_iommu_without_ioapic.py @@ -0,0 +1,45 @@ +from virttest import libvirt_version +from virttest import virsh +from virttest.libvirt_xml import vm_xml +from virttest.utils_libvirt import libvirt_vmxml + + +def run(test, params, env): + """ + libvirt will automatically add "" + if is set for the intel iommu device + """ + libvirt_version.is_libvirt_feature_supported(params) + iommu_dict = eval(params.get('iommu_dict', '{}')) + auto_add_ioapic = params.get("auto_add_ioapic", "no") == "yes" + feature_name = params.get("feature_name", "ioapic") + + vm_name = params.get("main_vm", "avocado-vt-vm1") + vm = env.get_vm(vm_name) + vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) + backup_vmxml = vmxml.copy() + try: + test.log.info(f"TEST_STEP: Remove {feature_name} feature if needed.") + features = vmxml.features + if features.has_feature(feature_name): + features.remove_feature(feature_name) + vmxml.features = features + + test.log.info("TEST_STEP: Define VM with intel iommu device.") + iommu_dev = libvirt_vmxml.create_vm_device_by_type('iommu', iommu_dict) + vmxml.add_device(iommu_dev) + vmxml.xmltreefile.write() + vmxml.sync() + + vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) + features = vmxml.features + tmp_msg = "" if auto_add_ioapic else "not " + msg = (f"{feature_name} should {tmp_msg}be " + f"added automatically! Actual feature list: {features}") + if auto_add_ioapic == features.has_feature(feature_name): + test.log.debug(msg) + else: + test.fail(msg) + virsh.start(vm.name, debug=True, ignore_status=False) + finally: + backup_vmxml.sync() diff --git a/libvirt/tests/src/sriov/vIOMMU/sriov_iommu_alias.py b/libvirt/tests/src/sriov/vIOMMU/iommu_alias.py similarity index 85% rename from libvirt/tests/src/sriov/vIOMMU/sriov_iommu_alias.py rename to libvirt/tests/src/sriov/vIOMMU/iommu_alias.py index abedab04a3a..d436842e6f6 100644 --- a/libvirt/tests/src/sriov/vIOMMU/sriov_iommu_alias.py +++ b/libvirt/tests/src/sriov/vIOMMU/iommu_alias.py @@ -1,4 +1,4 @@ -from provider.sriov import sriov_base +from provider.viommu import viommu_base from virttest.libvirt_xml import vm_xml @@ -18,7 +18,7 @@ def check_xml(vm, exp_alias, iommu_pci_addr): cur_iommu = vm_xml.VMXML.new_from_dumpxml(vm.name)\ .devices.by_device_tag("iommu") if not cur_iommu: - test.fail("Unalbe to get iommu device!") + test.fail("Unable to get iommu device!") iommu_attrs = cur_iommu[0].fetch_attrs() test.log.debug("iommu_attrs: %s", iommu_attrs) @@ -41,11 +41,11 @@ def check_xml(vm, exp_alias, iommu_pci_addr): vm_name = params.get("main_vm", "avocado-vt-vm1") vm = env.get_vm(vm_name) - sriov_test_obj = sriov_base.SRIOVTest(vm, test, params) + test_obj = viommu_base.VIOMMUTest(vm, test, params) try: - sriov_test_obj.setup_iommu_test(iommu_dict=iommu_dict) + test_obj.setup_iommu_test(iommu_dict=iommu_dict) vm.start() check_xml(vm, exp_alias, iommu_has_addr) finally: - sriov_test_obj.teardown_default() + test_obj.teardown_iommu_test() diff --git a/libvirt/tests/src/sriov/vIOMMU/iommu_device_lifecycle.py b/libvirt/tests/src/sriov/vIOMMU/iommu_device_lifecycle.py new file mode 100644 index 00000000000..4d77baf66b4 --- /dev/null +++ b/libvirt/tests/src/sriov/vIOMMU/iommu_device_lifecycle.py @@ -0,0 +1,104 @@ +import os + +from virttest import utils_misc +from virttest import utils_net +from virttest import virsh + +from virttest.libvirt_xml import vm_xml +from virttest.utils_libvirt import libvirt_vmxml + +from provider.save import save_base +from provider.sriov import sriov_base +from provider.viommu import viommu_base +from provider.sriov import check_points as sriov_check_points + +VIRSH_ARGS = {'debug': True, 'ignore_status': False} + + +def run(test, params, env): + """ + Test lifecycle for vm with vIOMMU enabled with different devices. + """ + cleanup_ifaces = "yes" == params.get("cleanup_ifaces", "yes") + ping_dest = params.get('ping_dest', "127.0.0.1") + iommu_dict = eval(params.get('iommu_dict', '{}')) + test_scenario = params.get("test_scenario") + need_sriov = "yes" == params.get("need_sriov", "no") + + vm_name = params.get("main_vm", "avocado-vt-vm1") + vm = env.get_vm(vm_name) + + rand_id = utils_misc.generate_random_string(3) + save_path = f'/var/tmp/{vm_name}_{rand_id}.save' + test_obj = viommu_base.VIOMMUTest(vm, test, params) + if need_sriov: + sroiv_test_obj = sriov_base.SRIOVTest(vm, test, params) + try: + test.log.info("TEST_SETUP: Update VM XML.") + test_obj.setup_iommu_test(iommu_dict=iommu_dict, + cleanup_ifaces=cleanup_ifaces) + test_obj.prepare_controller() + for dev in ["disk", "video"]: + dev_dict = eval(params.get('%s_dict' % dev, '{}')) + if dev == "disk": + dev_dict = test_obj.update_disk_addr(dev_dict) + libvirt_vmxml.modify_vm_device( + vm_xml.VMXML.new_from_dumpxml(vm.name), dev, dev_dict) + if need_sriov: + iface_dicts = sroiv_test_obj.parse_iface_dict() + test.log.debug(iface_dicts) + test_obj.params["iface_dict"] = str(sroiv_test_obj.parse_iface_dict()) + iface_dict = test_obj.parse_iface_dict() + if cleanup_ifaces: + libvirt_vmxml.modify_vm_device( + vm_xml.VMXML.new_from_dumpxml(vm.name), + "interface", iface_dict) + + test.log.info("TEST_STEP: Start the VM.") + vm.start() + test.log.debug(vm_xml.VMXML.new_from_dumpxml(vm.name)) + if test_scenario in ["reboot_many_times", "reset"]: + vm.cleanup_serial_console() + vm.create_serial_console() + if test_scenario == "reset": + test.log.info("TEST_STEP: Reset the VM.") + session = vm.wait_for_serial_login( + timeout=int(params.get('login_timeout'))) + virsh.reset(vm.name, **VIRSH_ARGS) + _match, _text = session.read_until_last_line_matches( + [r"[Ll]ogin:\s*"], timeout=240, internal_timeout=0.5) + session.close() + else: + for _ in range(int(params.get('loop_time', '5'))): + test.log.info("TEST_STEP: Reboot the VM.") + session = vm.wait_for_serial_login( + timeout=int(params.get('login_timeout'))) + session.sendline(params.get("reboot_command")) + _match, _text = session.read_until_last_line_matches( + [r"[Ll]ogin:\s*"], timeout=240, internal_timeout=0.5) + session.close() + + session = vm.wait_for_serial_login( + timeout=int(params.get('login_timeout'))) + + if need_sriov: + sriov_check_points.check_vm_network_accessed(session, ping_dest=ping_dest) + else: + s, o = utils_net.ping(ping_dest, count=5, timeout=10, session=session) + if s: + test.fail("Failed to ping %s! status: %s, output: %s." % (ping_dest, s, o)) + else: + pid_ping, upsince = save_base.pre_save_setup(vm, serial=True) + if test_scenario == "save_restore": + test.log.info("TEST_STEP: Save and restore the VM.") + virsh.save(vm.name, save_path, **VIRSH_ARGS) + virsh.restore(save_path, **VIRSH_ARGS) + elif test_scenario == "suspend_resume": + test.log.info("TEST_STEP: Suspend and resume the VM.") + virsh.suspend(vm.name, **VIRSH_ARGS) + virsh.resume(vm.name, **VIRSH_ARGS) + save_base.post_save_check(vm, pid_ping, upsince, serial=True) + finally: + test_obj.teardown_iommu_test() + if os.path.exists(save_path): + os.remove(save_path) diff --git a/libvirt/tests/src/sriov/vIOMMU/iommu_device_settings.py b/libvirt/tests/src/sriov/vIOMMU/iommu_device_settings.py index b29fa03da1c..40a6fd30139 100644 --- a/libvirt/tests/src/sriov/vIOMMU/iommu_device_settings.py +++ b/libvirt/tests/src/sriov/vIOMMU/iommu_device_settings.py @@ -1,11 +1,13 @@ -from virttest import libvirt_version from virttest import utils_disk +from virttest import utils_net from virttest.libvirt_xml import vm_xml from virttest.utils_libvirt import libvirt_vmxml from provider.sriov import sriov_base -from provider.sriov import check_points +from provider.viommu import viommu_base + +from provider.sriov import check_points as sriov_check_points def run(test, params, env): @@ -13,25 +15,48 @@ def run(test, params, env): Start vm with iommu device and kinds of virtio devices with iommu=on, and check network and disk function. """ - libvirt_version.is_libvirt_feature_supported(params) cleanup_ifaces = "yes" == params.get("cleanup_ifaces", "yes") ping_dest = params.get('ping_dest') iommu_dict = eval(params.get('iommu_dict', '{}')) test_devices = eval(params.get("test_devices", "[]")) + dev_in_same_iommu_group = eval(params.get("dev_in_same_iommu_group", "[]")) + need_sriov = "yes" == params.get("need_sriov", "no") vm_name = params.get("main_vm", "avocado-vt-vm1") vm = env.get_vm(vm_name) - test_obj = sriov_base.SRIOVTest(vm, test, params) + sroiv_test_obj = None + + test_obj = viommu_base.VIOMMUTest(vm, test, params) + if need_sriov: + sroiv_test_obj = sriov_base.SRIOVTest(vm, test, params) + try: test_obj.setup_iommu_test(iommu_dict=iommu_dict, cleanup_ifaces=cleanup_ifaces) test_obj.prepare_controller() + vm.start() + vm.cleanup_serial_console() + vm.create_serial_console() + vm_session = vm.wait_for_serial_login( + timeout=int(params.get('login_timeout'))) + pre_devices = viommu_base.get_devices_pci(vm_session, test_devices) + vm.destroy() + for dev in ["disk", "video"]: dev_dict = eval(params.get('%s_dict' % dev, '{}')) - if dev == "disk": + if dev == "disk" and dev_dict: dev_dict = test_obj.update_disk_addr(dev_dict) + if dev_dict["target"].get("bus") != "virtio": + libvirt_vmxml.modify_vm_device( + vm_xml.VMXML.new_from_dumpxml(vm.name), dev, {'driver': None}) + libvirt_vmxml.modify_vm_device( vm_xml.VMXML.new_from_dumpxml(vm.name), dev, dev_dict) + if need_sriov: + iface_dicts = sroiv_test_obj.parse_iface_dict() + test.log.debug(iface_dicts) + test_obj.params["iface_dict"] = str(sroiv_test_obj.parse_iface_dict()) iface_dict = test_obj.parse_iface_dict() + if cleanup_ifaces: libvirt_vmxml.modify_vm_device( vm_xml.VMXML.new_from_dumpxml(vm.name), @@ -39,18 +64,27 @@ def run(test, params, env): test.log.info("TEST_STEP: Start the VM.") vm.start() - vm.cleanup_serial_console() - vm.create_serial_console() vm_session = vm.wait_for_serial_login( timeout=int(params.get('login_timeout'))) test.log.debug(vm_xml.VMXML.new_from_dumpxml(vm.name)) test.log.info("TEST_STEP: Check dmesg message about iommu inside the vm.") vm_session.cmd("dmesg | grep -i 'Adding to iommu group'") - check_points.check_vm_iommu_group(vm_session, test_devices) + viommu_base.check_vm_iommu_group(vm_session, test_devices, pre_devices) + if dev_in_same_iommu_group: + devices_pci_info = viommu_base.get_devices_pci(vm_session, dev_in_same_iommu_group) + devices_pci = [x for y in devices_pci_info.values() for x in y] + dev_dir = str(viommu_base.get_iommu_dev_dir(vm_session, devices_pci[0])) + for dev in devices_pci: + vm_session.cmd(f"ls {dev_dir} |grep {dev}") test.log.info("TEST_STEP: Check if the VM disk and network are woring well.") utils_disk.dd_data_to_vm_disk(vm_session, "/mnt/test") - check_points.check_vm_network_accessed(vm_session, ping_dest=ping_dest) + if need_sriov: + sriov_check_points.check_vm_network_accessed(vm_session, ping_dest=ping_dest) + else: + s, o = utils_net.ping(ping_dest, count=5, timeout=10, session=vm_session) + if s: + test.fail("Failed to ping %s! status: %s, output: %s." % (ping_dest, s, o)) finally: test_obj.teardown_iommu_test() diff --git a/libvirt/tests/src/sriov/vIOMMU/iommu_repeated_reset.py b/libvirt/tests/src/sriov/vIOMMU/iommu_repeated_reset.py new file mode 100644 index 00000000000..7df626b448e --- /dev/null +++ b/libvirt/tests/src/sriov/vIOMMU/iommu_repeated_reset.py @@ -0,0 +1,76 @@ +import os +from time import sleep +from random import uniform + +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 virttest import utils_logfile + +from provider.viommu import viommu_base + + +def run(test, params, env): + """ + Start vm with iommu device and kinds of virtio devices with iommu=on, and + check network and disk function. + """ + + def setup_test(): + utils_logfile.clear_log_file(log_file_name, '/var/log/libvirt/qemu') + test_obj.setup_iommu_test(iommu_dict=iommu_dict, cleanup_ifaces=False) + test_obj.prepare_controller() + test.log.debug("---------------------------------------------------------------------------") + dev_dict = eval(params.get('disk_dict', '{}')) + test.log.debug(f"disk_dict: {dev_dict}") + if dev_dict: + dev_dict = test_obj.update_disk_addr(dev_dict) + if dev_dict["target"].get("bus") != "virtio": + libvirt_vmxml.modify_vm_device( + vm_xml.VMXML.new_from_dumpxml(vm.name), 'disk', {'driver': None}) + + libvirt_vmxml.modify_vm_device( + vm_xml.VMXML.new_from_dumpxml(vm.name), 'disk', dev_dict) + + iommu_dict = eval(params.get('iommu_dict', '{}')) + + vm_name = params.get("main_vm", "avocado-vt-vm1") + log_file_name = f"{vm_name}.log" + log_file = os.path.join("/var/log/libvirt/qemu", log_file_name) + vm = env.get_vm(vm_name) + + test_obj = viommu_base.VIOMMUTest(vm, test, params) + + try: + setup_test() + + test.log.info("TEST_STEP: Start the VM and wait for login.") + vm.start() + vm.wait_for_login().close() + test.log.info("TEST_STEP: Reboot the VM and wait for event 'reboot'") + virsh.reboot(vm_name, wait_for_event=True, debug=True, ignore_status=False) + test.log.debug("TEST_STEP: verify user is able to login also after restarts") + vm.wait_for_login().close() + + max_wait_ms = int(params.get('max_wait_ms', 0)) + max_repeat = int(params.get('max_repeat', 10)) + + for _ in range(max_repeat): + if max_wait_ms > 0: + wait_time = uniform(0, max_wait_ms) / 1000 + test.log.debug(f"waiting before reset {wait_time}s") + sleep(wait_time) + virsh.reset(vm_name) + + test.log.debug(vm_xml.VMXML.new_from_dumpxml(vm.name)) + + test.log.debug("TEST_STEP: verify user is able to login also after restarts") + vm.wait_for_login().close() + log_messages = params.get('log_messages', "") + str_in_log = (params.get('str_in_log', "False") == "True") + test.log.debug("TEST_STEP: check log for error messages") + libvirt.check_logfile(log_messages, log_file, str_in_log) + + finally: + test_obj.teardown_iommu_test() diff --git a/libvirt/tests/src/sriov/vIOMMU/migration_iommu_device.py b/libvirt/tests/src/sriov/vIOMMU/migration_iommu_device.py index f9bc95a9751..a246bbc9dc0 100644 --- a/libvirt/tests/src/sriov/vIOMMU/migration_iommu_device.py +++ b/libvirt/tests/src/sriov/vIOMMU/migration_iommu_device.py @@ -1,11 +1,10 @@ -from virttest import libvirt_version from virttest import virsh from virttest.libvirt_xml import vm_xml from virttest.utils_libvirt import libvirt_vmxml -from provider.sriov import sriov_base from provider.migration import base_steps +from provider.viommu import viommu_base def run(test, params, env): @@ -65,14 +64,13 @@ def setup_test(): "interface", iface_dict) migration_obj.setup_default() - libvirt_version.is_libvirt_feature_supported(params) cleanup_ifaces = "yes" == params.get("cleanup_ifaces", "yes") iommu_dict = eval(params.get('iommu_dict', '{}')) iface_dict = eval(params.get('iface_dict', '{}')) vm_name = params.get("main_vm", "avocado-vt-vm1") vm = env.get_vm(vm_name) - test_obj = sriov_base.SRIOVTest(vm, test, params) + test_obj = viommu_base.VIOMMUTest(vm, test, params) migration_obj = base_steps.MigrationBase(test, vm, params) try: @@ -82,8 +80,11 @@ def setup_test(): migration_obj.verify_default() check_iommu_xml(vm, params) - test.log.info("TEST_STEP: Migrate back the VM to the source host.") - migration_obj.run_migration_back() - migration_obj.migration_test.ping_vm(vm, params) + migrate_vm_back = "yes" == params.get("migrate_vm_back", "yes") + if migrate_vm_back: + test.log.info("TEST_STEP: Migrate back the VM to the source host.") + migration_obj.run_migration_back() + migration_obj.migration_test.ping_vm(vm, params) + migration_obj.check_vm_cont_ping(False) finally: test_obj.teardown_iommu_test() diff --git a/libvirt/tests/src/sriov/vIOMMU/viommu_netperf.py b/libvirt/tests/src/sriov/vIOMMU/viommu_netperf.py new file mode 100644 index 00000000000..b8c20a2893a --- /dev/null +++ b/libvirt/tests/src/sriov/vIOMMU/viommu_netperf.py @@ -0,0 +1,39 @@ +from virttest.libvirt_xml import vm_xml +from virttest.utils_libvirt import libvirt_vmxml + +from provider.viommu import viommu_base +from provider.virtual_network import network_base + + +def run(test, params, env): + """ + Run netperf testing between host and vm with iommu device + """ + cleanup_ifaces = "yes" == params.get("cleanup_ifaces", "yes") + iommu_dict = eval(params.get('iommu_dict', '{}')) + + vms = params.get('vms').split() + vm_objs = [env.get_vm(vm_i) for vm_i in vms] + + test_objs = [viommu_base.VIOMMUTest(vm, test, params) for vm in vm_objs] + + try: + test.log.info("TEST_SETUP: Update VM XML.") + for test_obj in test_objs: + test_obj.setup_iommu_test(iommu_dict=iommu_dict, + cleanup_ifaces=cleanup_ifaces) + + iface_dict = test_objs[0].parse_iface_dict() + if cleanup_ifaces: + vmxml_lists = list(map(vm_xml.VMXML.new_from_inactive_dumpxml, vms)) + [libvirt_vmxml.modify_vm_device(vmxml_i, 'interface', iface_dict) for vmxml_i in vmxml_lists] + + test.log.info('TEST_STEP: Start the VM(s)') + [vm_inst.start() for vm_inst in vm_objs] + [vm_inst.wait_for_login() for vm_inst in vm_objs] + + test.log.info("TEST_STEP: Run netperf testing between host(vm) and vm.") + network_base.exec_netperf_test(params, env) + finally: + for test_obj in test_objs: + test_obj.teardown_iommu_test() diff --git a/libvirt/tests/src/sriov/vIOMMU/viommu_transfer_file.py b/libvirt/tests/src/sriov/vIOMMU/viommu_transfer_file.py new file mode 100644 index 00000000000..956feb8367d --- /dev/null +++ b/libvirt/tests/src/sriov/vIOMMU/viommu_transfer_file.py @@ -0,0 +1,39 @@ +from virttest import utils_test + +from virttest.libvirt_xml import vm_xml +from virttest.utils_libvirt import libvirt_vmxml + +from provider.viommu import viommu_base + + +def run(test, params, env): + """ + Transfer a file between host and vm with iommu device + """ + cleanup_ifaces = "yes" == params.get("cleanup_ifaces", "yes") + iommu_dict = eval(params.get('iommu_dict', '{}')) + + vm_name = params.get("main_vm", "avocado-vt-vm1") + vm = env.get_vm(vm_name) + + test_obj = viommu_base.VIOMMUTest(vm, test, params) + + try: + test.log.info("TEST_SETUP: Update VM XML.") + test_obj.setup_iommu_test(iommu_dict=iommu_dict, + cleanup_ifaces=cleanup_ifaces) + + iface_dict = test_obj.parse_iface_dict() + if cleanup_ifaces: + libvirt_vmxml.modify_vm_device( + vm_xml.VMXML.new_from_dumpxml(vm.name), + "interface", iface_dict) + + test.log.info("TEST_STEP: Start the VM.") + vm.start() + test.log.debug(vm_xml.VMXML.new_from_dumpxml(vm.name)) + + test.log.info("TEST_STEP: Transfer a file between host and vm.") + utils_test.run_file_transfer(test, params, env) + finally: + test_obj.teardown_iommu_test() diff --git a/libvirt/tests/src/sriov/vIOMMU/viommu_unload_driver.py b/libvirt/tests/src/sriov/vIOMMU/viommu_unload_driver.py new file mode 100644 index 00000000000..f943b838e00 --- /dev/null +++ b/libvirt/tests/src/sriov/vIOMMU/viommu_unload_driver.py @@ -0,0 +1,138 @@ +import os +import time + +from avocado.utils import crypto +from avocado.utils import process + +from virttest import data_dir +from virttest import utils_misc +from virttest import utils_net + +from virttest.libvirt_xml import vm_xml +from virttest.utils_libvirt import libvirt_vmxml + +from provider.viommu import viommu_base + + +def run(test, params, env): + """ + Verify the vm with iommu enabled interface work properly + after loading/unloading the driver. + """ + def all_threads_done(threads): + """ + Check whether all threads have finished + """ + for thread in threads: + if thread.is_alive(): + return False + else: + continue + return True + + def all_threads_alive(threads): + """ + Check whether all threads is alive + """ + for thread in threads: + if not thread.is_alive(): + return False + else: + continue + return True + + cleanup_ifaces = "yes" == params.get("cleanup_ifaces", "yes") + iommu_dict = eval(params.get('iommu_dict', '{}')) + filesize = int(params.get("filesize", 512)) + transfer_timeout = int(params.get("transfer_timeout", 1000)) + + vm_name = params.get("main_vm", "avocado-vt-vm1") + vm = env.get_vm(vm_name) + + test_obj = viommu_base.VIOMMUTest(vm, test, params) + + try: + test.log.info("TEST_SETUP: Update VM XML.") + test_obj.setup_iommu_test(iommu_dict=iommu_dict, + cleanup_ifaces=cleanup_ifaces) + + iface_dict = test_obj.parse_iface_dict() + if cleanup_ifaces: + libvirt_vmxml.modify_vm_device( + vm_xml.VMXML.new_from_dumpxml(vm.name), + "interface", iface_dict) + + test.log.info("TEST_STEP: Start the VM.") + vm.start() + vm_session = vm.wait_for_login() + test.log.debug(vm_xml.VMXML.new_from_dumpxml(vm.name)) + + test.log.info("TEST_STEP: Get interface driver.") + ethname = utils_net.get_linux_ifname(vm_session, vm.get_mac_address(0)) + output = vm_session.cmd_output(f"readlink -f /sys/class/net/{ethname}/device/driver") + nic_driver = os.path.basename(output) + + test.log.info("TEST_STEP: Prepare file on host and guest.") + tmp_dir = data_dir.get_tmp_dir() + host_path = os.path.join(tmp_dir, "host_file_%s" % + utils_misc.generate_random_string(8)) + guest_path = os.path.join("/home", "guest_file_%s" % + utils_misc.generate_random_string(8)) + cmd = "dd if=/dev/zero of=%s bs=1M count=%d" % (host_path, filesize) + process.run(cmd) + file_checksum = crypto.hash_file(host_path, algorithm="md5") + vm.copy_files_to(host_path, guest_path, timeout=transfer_timeout) + if vm_session.cmd_status("md5sum %s | grep %s" % + (guest_path, file_checksum)): + test.cancel("File MD5SUMs changed after copy to guest") + + test.log.info("TEST_STEP: Transfer files between host and guest.") + threads = [] + file_paths = [] + host_file_paths = [] + for sess_index in range(int(params.get("sessions_num", "5"))): + sess_path = os.path.join("/home", "dst-%s" % sess_index) + host_sess_path = os.path.join(tmp_dir, "dst-%s" % sess_index) + thread1 = utils_misc.InterruptedThread( + vm.copy_files_to, (host_path, sess_path), + {"timeout": transfer_timeout}) + + thread2 = utils_misc.InterruptedThread( + vm.copy_files_from, (guest_path, host_sess_path), + {"timeout": transfer_timeout}) + thread1.start() + threads.append(thread1) + thread2.start() + threads.append(thread2) + file_paths.append(sess_path) + host_file_paths.append(host_sess_path) + + utils_misc.wait_for(lambda: all_threads_alive(threads), 60, 10, 1, text="check if all threads are alive") + time.sleep(5) + + test.log.info("TEST_STEP: Unload and load the driver.") + vm.cleanup_serial_console() + vm.create_serial_console() + vm_serial = vm.wait_for_serial_login(timeout=120) + while not all_threads_done(threads): + vm_serial.cmd("modprobe -r %s" % nic_driver, timeout=120) + time.sleep(2) + vm_serial.cmd("modprobe %s" % nic_driver, timeout=120) + time.sleep(2) + + for copied_file in file_paths: + if vm_serial.cmd_status("md5sum %s | grep %s" % (copied_file, file_checksum)): + test.fail("Guest file MD5SUMs changed after copying %s" % copied_file) + for copied_file in host_file_paths: + if process.run("md5sum %s | grep %s" % + (copied_file, file_checksum), shell=True, verbose=True, + ignore_status=True).exit_status: + test.fail("Host file MD5SUMs changed after copying %s" % copied_file) + + finally: + test.log.info("TEST_TEARDOWN: Cleanup the env.") + for thread in threads: + thread.join() + for copied_file in host_file_paths: + process.system("rm -rf %s" % copied_file) + test_obj.teardown_iommu_test() diff --git a/libvirt/tests/src/sriov/vIOMMU/sriov_virtio_iommu_with_addtional_attributes.py b/libvirt/tests/src/sriov/vIOMMU/virtio_iommu_with_addtional_attributes.py similarity index 85% rename from libvirt/tests/src/sriov/vIOMMU/sriov_virtio_iommu_with_addtional_attributes.py rename to libvirt/tests/src/sriov/vIOMMU/virtio_iommu_with_addtional_attributes.py index 708daf29b06..9bb77833952 100644 --- a/libvirt/tests/src/sriov/vIOMMU/sriov_virtio_iommu_with_addtional_attributes.py +++ b/libvirt/tests/src/sriov/vIOMMU/virtio_iommu_with_addtional_attributes.py @@ -1,4 +1,4 @@ -from provider.sriov import sriov_base +from provider.viommu import viommu_base from virttest.libvirt_xml import xcepts from virttest.utils_libvirt import libvirt_virtio @@ -13,7 +13,7 @@ def run(test, params, env): vm_name = params.get("main_vm", "avocado-vt-vm1") vm = env.get_vm(vm_name) - sriov_test_obj = sriov_base.SRIOVTest(vm, test, params) + test_obj = viommu_base.VIOMMUTest(vm, test, params) try: libvirt_virtio.add_iommu_dev(vm, iommu_dict) @@ -26,4 +26,4 @@ def run(test, params, env): else: test.fail("Defining the VM should fail, but run successfully!") finally: - sriov_test_obj.teardown_default() + test_obj.teardown_iommu_test() diff --git a/libvirt/tests/src/storage/virsh_pool.py b/libvirt/tests/src/storage/virsh_pool.py index 01912f43ce7..8278aad5ac5 100644 --- a/libvirt/tests/src/storage/virsh_pool.py +++ b/libvirt/tests/src/storage/virsh_pool.py @@ -423,7 +423,8 @@ def check_pool_info(pool_info, check_point, value): # So a directory based storage pool is thus pretty much always active, # and so as the SCSI pool. if pool_type not in ['dir', 'scsi']: - if pool_type == 'disk' and libvirt_version.version_compare(8, 1, 0): + if (pool_type == 'disk' and libvirt_version.version_compare(8, 1, 0)) or \ + (pool_type == 'logical' and libvirt_version.version_compare(9, 9, 0)): utlv.check_exit_status(result) else: result = virsh.pool_start(pool_name, ignore_status=True) diff --git a/libvirt/tests/src/virsh_cmd/pool/virsh_pool_autostart.py b/libvirt/tests/src/storage/virsh_pool_autostart.py similarity index 80% rename from libvirt/tests/src/virsh_cmd/pool/virsh_pool_autostart.py rename to libvirt/tests/src/storage/virsh_pool_autostart.py index c1662febe1e..6f193e0b0dd 100755 --- a/libvirt/tests/src/virsh_cmd/pool/virsh_pool_autostart.py +++ b/libvirt/tests/src/storage/virsh_pool_autostart.py @@ -1,14 +1,19 @@ import os +import re +import time import logging as log from avocado.utils import process from avocado.core import exceptions -from virttest import utils_libvirtd from virttest import libvirt_storage +from virttest import utils_libvirtd from virttest import virsh -from virttest.utils_test import libvirt as utlv from virttest.libvirt_xml import pool_xml +from virttest.libvirt_xml import vm_xml +from virttest.utils_libvirt import libvirt_vmxml +from virttest.utils_test import libvirt as utlv +from virttest.utils_libvirt import libvirt_disk from virttest.staging import lv_utils from virttest import libvirt_version @@ -45,10 +50,18 @@ def run(test, params, env): status_error = "yes" == params.get("status_error", "no") readonly_mode = "yes" == params.get("readonly_mode", "no") pre_def_pool = "yes" == params.get("pre_def_pool", "yes") + with_empty_vg = "yes" == params.get("with_empty_vg", "no") disk_type = params.get("disk_type", "") vg_name = params.get("vg_name", "") lv_name = params.get("lv_name", "") update_policy = params.get("update_policy") + libvirt_version.is_libvirt_feature_supported(params) + destroy_pool_used_by_guest = params.get("destroy_pool_used_by_guest") + disk_dict = params.get("disk_dict") + vm_name = params.get("main_vm", "avocado-vt-vm1") + vm = env.get_vm(vm_name) + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + bkxml = vmxml.copy() # Readonly mode ro_flag = False @@ -90,7 +103,7 @@ def check_pool(pool_name, pool_type, checkpoint, actual_value = libvirt_pool.pool_autostart(pool_name) if actual_value != expect_value: if not expect_error: - if checkpoint == 'State' and pool_type in ("dir", "scsi", "disk"): + if checkpoint == 'State' and pool_type in ("dir", "scsi", "disk", "logical"): debug_msg = "Dir/scsi/disk pool should be active when libvirtd restart. " debug_msg += "See https://bugzilla.redhat.com/show_bug.cgi?id=1238610" logging.debug(debug_msg) @@ -129,7 +142,15 @@ def change_source_path(new_path, update_policy="set"): if pre_def_pool: # Step(1) # Pool define - pvt.pre_pool(**params) + if with_empty_vg and pool_type == "logical": + new_disk = utlv.setup_or_cleanup_iscsi(True) + pool_options = "--source-dev %s" % new_disk + virsh.pool_define_as(pool_name, pool_type, pool_target, + extra=pool_options, debug=True) + virsh.pool_build(pool_name, "--overwrite", debug=True) + virsh.pool_start(pool_name, ignore_status=False, debug=True) + else: + pvt.pre_pool(**params) # Remove the partition for disk pool # For sometimes the partition will cause pool start failed if pool_type == "disk": @@ -137,6 +158,20 @@ def change_source_path(new_path, update_policy="set"): # Get pool uuid: if pool_ref == "uuid" and not pool_uuid: pool = pool_ins.get_pool_uuid(pool_name) + if destroy_pool_used_by_guest: + virsh.pool_start(pool_name, debug=True, ignore_status=False) + # Avoid running vol_list too quickly + time.sleep(3) + res = virsh.vol_list(pool_name, debug=True, + ignore_status=False).stdout_text + vol = re.findall(r"(\S+)\ +(\S+)", str(res.strip()))[1] + if not vol: + test.fail('Expect to get vol in %s pool' % pool_name) + libvirt_vmxml.modify_vm_device( + vmxml, 'disk', eval(disk_dict % (pool_name, vol[0])), index=1) + virsh.start(vm_name) + vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) + test.log.debug("Get guest xml is:\n%s", vmxml) # Setup logical block device # Change pool source path @@ -191,6 +226,15 @@ def change_source_path(new_path, update_policy="set"): if not result.exit_status: check_pool(pool_name, pool_type, checkpoint='Autostart', expect_value="yes", expect_error=status_error) + if destroy_pool_used_by_guest: + session = vm.wait_for_login() + disk_name, _ = libvirt_disk.get_non_root_disk_name(session) + test.log.debug("Get new disk name is:%s", disk_name) + session.close() + + virsh.pool_destroy(pool_name, debug=True, ignore_status=False) + utils_libvirtd.Libvirtd().restart() + libvirt_disk.check_virtual_disk_io(vm, disk_name) # Step(3) # Restart libvirtd and check pool status @@ -229,6 +273,8 @@ def change_source_path(new_path, update_policy="set"): # Clean up logging.debug("Try to clean up env") try: + if destroy_pool_used_by_guest: + bkxml.sync() if clean_mount is True: for src in source_list: process.system("umount %s" % pool_target) @@ -238,6 +284,8 @@ def change_source_path(new_path, update_policy="set"): utlv.delete_local_disk(disk_type, vgname=vg_name, lvname=lv_name) lv_utils.vg_remove(vg_name) utlv.setup_or_cleanup_iscsi(False) + if with_empty_vg: + utlv.setup_or_cleanup_iscsi(False) if os.path.exists(p_xml): os.remove(p_xml) except exceptions.TestFail as details: diff --git a/libvirt/tests/src/svirt/dac/dac_seclabel_per_device.py b/libvirt/tests/src/svirt/dac/dac_seclabel_per_device.py index ce7af0f7b31..ff22ac7fbf5 100644 --- a/libvirt/tests/src/svirt/dac/dac_seclabel_per_device.py +++ b/libvirt/tests/src/svirt/dac/dac_seclabel_per_device.py @@ -50,6 +50,7 @@ def run(test, params, env): test_device = params.get("test_device") test_scenario = params.get("test_scenario") # Get general variables. + err_msg = params.get("err_msg") added_user = None source_path = None @@ -80,6 +81,13 @@ def run(test, params, env): except xcepts.LibvirtXMLError as details: if not status_error: test.fail(details) + else: + if err_msg: + if err_msg not in str(details): + test.fail(details) + else: + return + test.log.debug("VM XML: %s.", VMXML.new_from_inactive_dumpxml(vm_name)) res = virsh.start(vm.name) else: diff --git a/libvirt/tests/src/svirt/selinux/selinux_seclabel_per_device.py b/libvirt/tests/src/svirt/selinux/selinux_seclabel_per_device.py index d15ef5dcfaf..760dea7b06b 100644 --- a/libvirt/tests/src/svirt/selinux/selinux_seclabel_per_device.py +++ b/libvirt/tests/src/svirt/selinux/selinux_seclabel_per_device.py @@ -39,6 +39,20 @@ def get_dev_dict(device_type, params): return dev_dict, seclabel_attr +def attach_device(vm, test_device, dev_dict): + """ + Attaches the device as specified to the VM. + + :param vm: VM instance + :param test_device: the device type, e.g. disk + :param dev_dict: the device definition + """ + + dev_obj = libvirt_vmxml.create_vm_device_by_type(test_device, dev_dict) + dev_obj.setup_attrs(**dev_dict) + return virsh.attach_device(vm.name, dev_obj.xml, flagstr="--current", debug=True) + + def run(test, params, env): """ Start VM or hotplug a device with per-device selinux setting @@ -67,12 +81,18 @@ def run(test, params, env): if test_scenario != "hot_plug": test.log.info("TEST_STEP: Start VM with per-device dac setting.") try: - libvirt_vmxml.modify_vm_device(vmxml, test_device, dev_dict) + if test_device != 'disk': + libvirt_vmxml.modify_vm_device(vmxml, test_device, dev_dict) + else: + res = attach_device(vm, test_device, dev_dict) except xcepts.LibvirtXMLError as details: if not status_error: test.fail(details) + else: + return test.log.debug("VM XML: %s.", VMXML.new_from_inactive_dumpxml(vm_name)) - res = virsh.start(vm.name) + if not ('res' in locals() and res.exit_status != 0): + res = virsh.start(vm.name) else: test.log.info("TEST_STEP: Hot plug a device with dac setting.") if test_device == 'serial': @@ -81,9 +101,7 @@ def run(test, params, env): vm.start() vm.wait_for_login().close() - dev_obj = libvirt_vmxml.create_vm_device_by_type(test_device, dev_dict) - dev_obj.setup_attrs(**dev_dict) - res = virsh.attach_device(vm.name, dev_obj.xml, debug=True) + res = attach_device(vm, test_device, dev_dict) libvirt.check_exit_status(res, status_error) if seclabel_attr.get("label") and not status_error: diff --git a/libvirt/tests/src/svirt/umask_value/svirt_umask_files_accessed_by_qemu.py b/libvirt/tests/src/svirt/umask_value/svirt_umask_files_accessed_by_qemu.py index cab63676bc5..0aaceab9c30 100644 --- a/libvirt/tests/src/svirt/umask_value/svirt_umask_files_accessed_by_qemu.py +++ b/libvirt/tests/src/svirt/umask_value/svirt_umask_files_accessed_by_qemu.py @@ -7,6 +7,7 @@ from virttest import utils_libvirtd from virttest.libvirt_xml import vm_xml from virttest.libvirt_xml.vm_xml import VMXML +from avocado.utils import memory as avocado_mem def run(test, params, env): @@ -30,6 +31,13 @@ def run(test, params, env): if os.path.exists(hp_path): shutil.rmtree(hp_path) utils_libvirtd.Libvirtd().restart() + + # calculate the target_hugepage from VM memory and actual HP size + actual_hp_size = avocado_mem.get_huge_page_size() + target_hugepages = int(vmxml.memory / actual_hp_size) + params["target_hugepages"] = target_hugepages + test.log.debug(f"Requred VM memory {vmxml.memory}, calculated tareget_hugepages: {target_hugepages}") + hp_cfg = test_setup.HugePageConfig(params) hp_cfg.set_hugepages() diff --git a/libvirt/tests/src/timer_management.py b/libvirt/tests/src/timer_management.py index 1a1b4278851..9478068c826 100644 --- a/libvirt/tests/src/timer_management.py +++ b/libvirt/tests/src/timer_management.py @@ -71,6 +71,7 @@ def set_clock_xml(test, vm, params): newtimers.append(newtimer) vmclockxml.timers = newtimers vmxml.clock = vmclockxml + vmxml.remove_all_device_by_type('interface') logging.debug("New vm XML:\n%s", vmxml) vmxml.sync() # Return timer elements for test verify @@ -92,7 +93,7 @@ def vm_clock_source(vm, target, value=''): clock_file = 'current_clocksource' else: exceptions.TestError("Clock source target must be 'available' or 'current'") - session = vm.wait_for_login() + session = vm.wait_for_serial_login() session.cmd("cd %s" % CLOCK_SOURCE_PATH) set_clock = False if value: @@ -121,10 +122,11 @@ def get_time(vm=None, time_type=None, windows=False): :return: Epoch time or timezone """ if vm: - session = vm.wait_for_login() + session = vm.wait_for_serial_login() if time_type == "utc": cmd = "date -u +%Y/%m/%d/%H/%M/%S" ts, timestr = session.cmd_status_output(cmd) + logging.debug("VM UTC time is %s", timestr) elif windows is True: # Date in this format: Sun 09/14/2014 or 2014/09/14 Sun # So deal with it after getting date @@ -197,7 +199,7 @@ def set_vm_timezone(test, vm, timezone="America/New_York", windows=False): cmd_o = '' if not windows: timezone_file = "/usr/share/zoneinfo/%s" % timezone - session = vm.wait_for_login() + session = vm.wait_for_serial_login() if session.cmd_status("ls %s" % timezone_file): session.close() test.error("Not correct timezone:%s" % timezone_file) @@ -214,7 +216,7 @@ def set_vm_timezone(test, vm, timezone="America/New_York", windows=False): if timezone not in list(timezone_codes.keys()): test.error("Not supported timezone, please add it.") cmd = "tzutil /s \"%s\"" % timezone_codes[timezone] - session = vm.wait_for_login() + session = vm.wait_for_serial_login() cmd_s, cmd_o = session.cmd_status_output(cmd) session.close() if cmd_s: @@ -303,6 +305,8 @@ def manipulate_vm(vm, operation, params=None): os.remove(save_path) except OSError: pass + vm.cleanup_serial_console() + vm.create_serial_console() else: err_msg = "Unsupported operation in this function: %s" % operation return err_msg @@ -347,6 +351,7 @@ def test_timers_in_vm(test, vm, params): # Set host timezone set_host_timezone(test, host_tz) + syncup_host_time(test) # Confirm vm is down for editing if vm.is_alive(): @@ -357,7 +362,7 @@ def test_timers_in_vm(test, vm, params): # Logging vm to set time vm.start() - vm.wait_for_login() + vm.wait_for_serial_login() set_vm_timezone(test, vm, vm_tz, windows_test) # manipulate vm if necessary, linux guest only @@ -452,7 +457,7 @@ def test_specific_timer(test, vm, params): start_error = "yes" == params.get("timer_start_error", "no") if vm.is_dead(): vm.start() - vm.wait_for_login() + vm.wait_for_serial_login() # Not config VM clock if the timer is unsupported in VM config_clock_in_vm = True for timer in timers: @@ -472,7 +477,7 @@ def test_specific_timer(test, vm, params): # Logging vm to verify whether setting is work try: vm.start() - vm.wait_for_login() + vm.wait_for_serial_login() if start_error: test.fail("Start vm succeed, but expect fail.") except virt_vm.VMStartError as detail: @@ -522,6 +527,17 @@ def test_specific_timer(test, vm, params): " while present is yes" % t_name) +def syncup_host_time(test): + """ + Sync up host time to ntp server before testing. + """ + try: + process.run("chronyd -q 'server clock.redhat.com iburst'", shell=True) + process.run("hwclock --systohc", shell=True) + except Exception as e: + logging.error("sync up host time to ntp server error: %s", e) + + def run(test, params, env): """ Test vm time according timer management of XML configuration. diff --git a/libvirt/tests/src/libvirt_usb_hotplug_controller.py b/libvirt/tests/src/usb/libvirt_usb_hotplug_controller.py similarity index 100% rename from libvirt/tests/src/libvirt_usb_hotplug_controller.py rename to libvirt/tests/src/usb/libvirt_usb_hotplug_controller.py diff --git a/libvirt/tests/src/libvirt_usb_hotplug_device.py b/libvirt/tests/src/usb/libvirt_usb_hotplug_device.py similarity index 100% rename from libvirt/tests/src/libvirt_usb_hotplug_device.py rename to libvirt/tests/src/usb/libvirt_usb_hotplug_device.py diff --git a/libvirt/tests/src/usb_device.py b/libvirt/tests/src/usb/usb_device.py similarity index 97% rename from libvirt/tests/src/usb_device.py rename to libvirt/tests/src/usb/usb_device.py index e938c831abf..7e0279fae47 100644 --- a/libvirt/tests/src/usb_device.py +++ b/libvirt/tests/src/usb/usb_device.py @@ -10,6 +10,8 @@ from virttest.libvirt_xml.devices.controller import Controller from virttest.libvirt_xml.devices.hub import Hub +from provider.usb import usb_base + # Using as lower capital is not the best way to do, but this is just a # workaround to avoid changing the entire file. @@ -57,6 +59,10 @@ def run(test, params, env): device_type = params.get("device_type", "") device_mode = params.get("device_mode", "") port_num = params.get("port_num", "") + usb_cmd = None + if device_name == "redirdev": + add_pkg, usb_cmd = usb_base.get_host_pkg_and_cmd() + pkgs_host = params.get("pkgs_host", "") + add_pkg pkgs_host = params.get("pkgs_host", "") pkgs_guest = params.get("pkgs_guest", "") usb_hub = "yes" == params.get("usb_hub", "no") @@ -321,10 +327,8 @@ def check_alias(device_alias): # start usbredirserver vendor_id = addr['vendor_id'].lstrip("0x") product_id = addr['product_id'].lstrip("0x") - ps = process.SubProcess("usbredirserver -p {} {}:{}".format - (port, vendor_id, product_id), - shell=True) - server_id = ps.start() + usb_base.start_redirect_server(params, usb_cmd, + vendor_id, product_id) if redirdev_alias: alias_str = "ua-redir" + str(i) + random_id device_alias[port] = alias_str @@ -400,6 +404,6 @@ def check_alias(device_alias): finally: if 'session' in locals(): session.close() - if 'server_id' in locals(): - process.run("killall usbredirserver") + if usb_cmd: + usb_base.kill_redirect_server(usb_cmd) vmxml_backup.sync() diff --git a/libvirt/tests/src/passthrough/usb/usb_passthrough.py b/libvirt/tests/src/usb/usb_passthrough.py similarity index 100% rename from libvirt/tests/src/passthrough/usb/usb_passthrough.py rename to libvirt/tests/src/usb/usb_passthrough.py diff --git a/libvirt/tests/src/virsh_cmd/domain/virsh_attach_detach_disk.py b/libvirt/tests/src/virsh_cmd/domain/virsh_attach_detach_disk.py index 82b16fc11fa..52df542f751 100644 --- a/libvirt/tests/src/virsh_cmd/domain/virsh_attach_detach_disk.py +++ b/libvirt/tests/src/virsh_cmd/domain/virsh_attach_detach_disk.py @@ -5,6 +5,7 @@ import aexpect from avocado.utils import process +from avocado.core import exceptions from virttest import virt_vm from virttest import virsh @@ -15,7 +16,7 @@ from virttest.staging.service import Factory from virttest.staging import lv_utils from virttest.utils_libvirt import libvirt_pcicontr -from virttest import utils_disk +from virttest.utils_libvirt import libvirt_disk from virttest import utils_misc from virttest import data_dir from virttest import libvirt_version @@ -49,7 +50,7 @@ def check_info_in_audit_log_file(test_cmd, device_source): % device_source) return process.run(cmd, ignore_status=True, shell=True).exit_status == 0 - def check_vm_partition(vm, device, os_type, target_name, old_parts): + def check_vm_partition(vm, device, os_type, target_name): """ Check VM disk's partition. @@ -65,8 +66,12 @@ def check_vm_partition(vm, device, os_type, target_name, old_parts): attached = False if os_type == "linux": session = vm.wait_for_login() - new_parts = utils_disk.get_parts_list(session) - added_parts = list(set(new_parts).difference(set(old_parts))) + added_parts = [] + try: + added_disks = libvirt_disk.get_non_root_disk_names(session) + added_parts = [x[0] for x in added_disks] + except exceptions.TestError as e: + logging.debug(e) logging.debug("Added parts: %s" % added_parts) for i in range(len(added_parts)): if device == "disk": @@ -225,9 +230,6 @@ def _check_disk(target): # Start vm and get all partitions in vm. if vm.is_dead(): vm.start() - session = vm.wait_for_login() - old_parts = utils_disk.get_parts_list(session) - session.close() vm.destroy(gracefully=False) # Back up xml file. @@ -464,7 +466,7 @@ def _check_disk(target): # Check in VM after command. check_vm_after_cmd = True check_vm_after_cmd = check_vm_partition(vm, device, os_type, - device_target, old_parts) + device_target) # Check disk type after attach. check_disk_type = True diff --git a/libvirt/tests/src/virsh_cmd/domain/virsh_attach_detach_interface.py b/libvirt/tests/src/virsh_cmd/domain/virsh_attach_detach_interface.py index 7d9eb530092..c0169c48ea0 100644 --- a/libvirt/tests/src/virsh_cmd/domain/virsh_attach_detach_interface.py +++ b/libvirt/tests/src/virsh_cmd/domain/virsh_attach_detach_interface.py @@ -283,7 +283,13 @@ def run(test, params, env): # Get iface name if iface_type is direct if iface_type == "direct": - iface_source = utils_net.get_net_if(state="UP")[0] + links = utils_net.get_net_if(state="UP") + for link in links: + if utils_net.get_net_if_addrs(link)["ipv4"]: + iface_source = link + break + if not iface_source: + test.error("Couldn't find host interface with IP") # Get a bridge name for test if iface_type is bridge. # If there is no bridge other than virbr0, try to create one # or fail test diff --git a/libvirt/tests/src/virsh_cmd/domain/virsh_attach_device.py b/libvirt/tests/src/virsh_cmd/domain/virsh_attach_device.py index 01b8555b699..8e5d521306d 100644 --- a/libvirt/tests/src/virsh_cmd/domain/virsh_attach_device.py +++ b/libvirt/tests/src/virsh_cmd/domain/virsh_attach_device.py @@ -466,11 +466,14 @@ class SerialPipe(SerialFile): @staticmethod def make_source(filepath): - try: - os.unlink(filepath) - except OSError: - pass - os.mkfifo(filepath) + pipe_suffixes = [".in", ".out"] + for suffix in pipe_suffixes: + pipe_path = filepath + suffix + try: + os.unlink(pipe_path) + except OSError: + pass + os.mkfifo(pipe_path) def init_device(self, index): return super(SerialPipe, self).init_device(index) # stub for now diff --git a/libvirt/tests/src/virsh_cmd/domain/virsh_attach_device_matrix.py b/libvirt/tests/src/virsh_cmd/domain/virsh_attach_device_matrix.py index 2efa57612af..18f283d045f 100644 --- a/libvirt/tests/src/virsh_cmd/domain/virsh_attach_device_matrix.py +++ b/libvirt/tests/src/virsh_cmd/domain/virsh_attach_device_matrix.py @@ -7,6 +7,7 @@ from virttest import data_dir from virttest import utils_misc from virttest.libvirt_xml import vm_xml +from virttest.utils_libvirt import libvirt_disk from virttest.utils_test import libvirt @@ -225,11 +226,11 @@ def check_result(disk_source, disk_type, disk_target, libvirt.create_local_disk("file", device_source, "1") # Get disk xml file. - disk_params = {'type_name': "file", 'device_type': device, - 'target_dev': device_target, 'target_bus': "virtio", - 'source_file': device_source, 'driver_name': "qemu", - 'driver_type': "raw"} - disk_xml = libvirt.create_disk_xml(disk_params) + disk_xml_obj = libvirt_disk.create_primitive_disk_xml( + "file", device, + device_target, "virtio", + "raw", {"attrs": {"file": device_source}}, None) + disk_xml = disk_xml_obj.xml # Copy disk xml for virsh.detach in the following code new_xml_path = os.path.join(data_dir.get_tmp_dir(), "disk_copy.xml") diff --git a/libvirt/tests/src/virsh_cmd/domain/virsh_blkdeviotune.py b/libvirt/tests/src/virsh_cmd/domain/virsh_blkdeviotune.py index 07eae2c3fc4..f71634eddc1 100644 --- a/libvirt/tests/src/virsh_cmd/domain/virsh_blkdeviotune.py +++ b/libvirt/tests/src/virsh_cmd/domain/virsh_blkdeviotune.py @@ -25,7 +25,7 @@ def check_blkdeviotune(params): vm = params.get("vm") options = params.get("blkdevio_options") device = params.get("device_name", "") - result = virsh.blkdeviotune(vm_name, device) + result = virsh.blkdeviotune(vm_name, device, ignore_status=False) dicts = {} # Parsing command output and putting them into python dictionary. cmd_output = result.stdout.strip().splitlines() diff --git a/libvirt/tests/src/virsh_cmd/domain/virsh_change_media.py b/libvirt/tests/src/virsh_cmd/domain/virsh_change_media.py index e5a4c23d458..16dc261a094 100644 --- a/libvirt/tests/src/virsh_cmd/domain/virsh_change_media.py +++ b/libvirt/tests/src/virsh_cmd/domain/virsh_change_media.py @@ -242,6 +242,8 @@ def update_device(vm_name, init_iso, options, start_vm): process.run("mkfs.ext3 -F %s" % source, shell=True) all_options = action + options + " " + source + if vm.is_alive(): + vm.wait_for_login().close() result = virsh.change_media(vm_ref, target_device, all_options, ignore_status=True, debug=True) if status_error: diff --git a/libvirt/tests/src/virsh_cmd/domain/virsh_console.py b/libvirt/tests/src/virsh_cmd/domain/virsh_console.py index 58e8a7928d0..caaa32d9ac0 100644 --- a/libvirt/tests/src/virsh_cmd/domain/virsh_console.py +++ b/libvirt/tests/src/virsh_cmd/domain/virsh_console.py @@ -81,7 +81,7 @@ def vm_console_config(vm, test, device='ttyS0', def check_duplicated_console(command, force_command, status_error, login_user, - login_passwd, test): + login_passwd, test, prompt_regex): """ Test opening a second console with another console active using --force option or not. @@ -93,7 +93,7 @@ def check_duplicated_console(command, force_command, status_error, login_user, :param login_passwd: Password for logging into the VM. :param test: Test Object """ - session = aexpect.ShellSession(command) + session = aexpect.ShellSession(command, prompt=prompt_regex) if not status_error: # Test duplicated console session res = process.run(command, timeout=CMD_TIMEOUT, @@ -104,7 +104,7 @@ def check_duplicated_console(command, force_command, status_error, login_user, "but succeeded with:\n%s" % res) # Test duplicated console session with force option - force_session = aexpect.ShellSession(force_command) + force_session = aexpect.ShellSession(force_command, prompt=prompt_regex) force_status = utils_test.libvirt.verify_virsh_console( force_session, login_user, login_passwd, timeout=CMD_TIMEOUT, debug=True) @@ -116,7 +116,7 @@ def check_duplicated_console(command, force_command, status_error, login_user, def check_disconnect_on_shutdown(vm, command, status_error, login_user, - login_passwd, test): + login_passwd, test, prompt_regex): """ Test whether an active console will disconnect after shutting down the VM. @@ -127,11 +127,15 @@ def check_disconnect_on_shutdown(vm, command, status_error, login_user, :param login_passwd: Password for logging into the VM. :param test: Test Object """ - session = aexpect.ShellSession(command) + session = aexpect.ShellSession(command, prompt=prompt_regex) if not status_error: log = "" console_cmd = "shutdown -h now" try: + # Do not use remote.handle_prompts here because it will inhibit + # errors. + # Login will fail if extra kernel messages are printed after login + # prompt. We should keep the failure to force QE do the check. while True: match, text = session.read_until_last_line_matches( [r"[E|e]scape character is", r"login:", @@ -200,6 +204,7 @@ def run(test, params, env): domid = "" uri = params.get("virsh_uri") unprivileged_user = params.get('unprivileged_user') + prompt_regex = params.get("prompt_regex", r"(.*)(\[.+@.+\]#)\s(.*)$") # PAPR guests don't usually have a true serial device (ttyS0), # they only have the hypervisor console (/dev/hvc0) @@ -260,7 +265,7 @@ def run(test, params, env): else: command = "virsh console %s" % vm_ref force_command = "virsh console %s --force" % vm_ref - console_session = aexpect.ShellSession(command) + console_session = aexpect.ShellSession(command, prompt=prompt_regex) status = utils_test.libvirt.verify_virsh_console( console_session, login_user, login_passwd, @@ -268,9 +273,9 @@ def run(test, params, env): console_session.close() check_duplicated_console(command, force_command, status_error, - login_user, login_passwd, test) + login_user, login_passwd, test, prompt_regex) check_disconnect_on_shutdown(vm, command, status_error, login_user, - login_passwd, test) + login_passwd, test, prompt_regex) finally: # Recover state of vm. if vm_state == "paused": diff --git a/libvirt/tests/src/virsh_cmd/domain/virsh_detach_device.py b/libvirt/tests/src/virsh_cmd/domain/virsh_detach_device.py index c9f7c8501a6..5e83837ec7b 100644 --- a/libvirt/tests/src/virsh_cmd/domain/virsh_detach_device.py +++ b/libvirt/tests/src/virsh_cmd/domain/virsh_detach_device.py @@ -11,6 +11,7 @@ from virttest import remote from virttest import data_dir from virttest import utils_misc +from virttest.utils_libvirt.libvirt_disk import get_non_root_disk_name from virttest.utils_test import libvirt from virttest.libvirt_xml import vm_xml @@ -246,6 +247,7 @@ def _detach_device(by_alias, detach_target): ignore_status=True) device_xml = create_device_xml(params, tmp_dir, device_source) + target_name = device_target if not no_attach: s_attach = virsh.attach_device(vm_name, device_xml, flagstr="--config", debug=True).exit_status @@ -254,7 +256,10 @@ def _detach_device(by_alias, detach_target): "detach-device") vm.start() - vm.wait_for_serial_login() + session = vm.wait_for_serial_login() + if not no_attach and device == 'disk' and s_attach == 0: + target_name, _ = get_non_root_disk_name(session) + session.close() # Add acpiphp module before testing if VM's os type is rhle5.* if device in ['disk', 'cdrom']: @@ -343,7 +348,7 @@ def __interface_exists(): check_vm_after_cmd = True if device in ['disk', 'cdrom']: check_vm_after_cmd = check_vm_partition(vm, device, os_type, - device_target) + target_name) # Destroy VM. if vm.is_alive(): diff --git a/libvirt/tests/src/virsh_cmd/domain/virsh_detach_device_alias.py b/libvirt/tests/src/virsh_cmd/domain/virsh_detach_device_alias.py index 0a3d047574c..4c2ccb716b8 100644 --- a/libvirt/tests/src/virsh_cmd/domain/virsh_detach_device_alias.py +++ b/libvirt/tests/src/virsh_cmd/domain/virsh_detach_device_alias.py @@ -1,10 +1,14 @@ +import logging as log import os +import platform import uuid -import logging as log +import re +import time from virttest import data_dir from virttest import virsh from virttest import utils_misc +from virttest import utils_sys from virttest.libvirt_xml import vm_xml from virttest.libvirt_xml.devices.disk import Disk from virttest.libvirt_xml.devices.watchdog import Watchdog @@ -14,6 +18,7 @@ from virttest.utils_libvirt import libvirt_vmxml from avocado.utils import process +from provider.usb import usb_base # Using as lower capital is not the best way to do, but this is just a @@ -21,6 +26,34 @@ logging = log.getLogger('avocado.' + __name__) +def get_suitable_pci_device(test): + """ + Get a suitable pci device ID for attaching to the vm. + The host PCI devices will vary on different hardware, so it is hard + to always get an usable pci device. + + :param test: test object + :return: str, the pci device full id or None + """ + pci_ids = utils_sys.get_host_bridge_id() + if not pci_ids: + test.error("Not Found any pci devices") + + if platform.machine() != "aarch64": + good_pci = utils_misc.get_full_pci_id(pci_ids[-1]).split("\n")[0] + return good_pci + else: + suitable_pci_ids = [id for id in pci_ids if id != "0000:00"] + for pci_id in suitable_pci_ids: + full_ids = utils_misc.get_full_pci_id(pci_id) + good_pci = "%s:00.0" % pci_id + if full_ids.count(good_pci): + test.log.debug("PCI ID '%s' is chosen", good_pci) + return good_pci + test.log.warning("No suitable PCI ID is chosen") + return None + + def run(test, params, env): """ Test detach-device-alias command with @@ -39,7 +72,6 @@ def run(test, params, env): hostdev_type = params.get("detach_hostdev_type", "") hostdev_managed = params.get("detach_hostdev_managed") controller_dict = eval(params.get('controller_dict', '{}')) - pci_filter = params.get("pci_filter", "") # controller params contr_type = params.get("detach_controller_type") contr_model = params.get("detach_controller_mode") @@ -47,7 +79,7 @@ def run(test, params, env): redir_type = params.get("detach_redirdev_type") redir_bus = params.get("detach_redirdev_bus") redir_params = eval(params.get("redir_params", "{}")) - port = params.get("port") + port_num = params.get("port_num") # channel params channel_type = params.get("detach_channel_type") channel_dict = eval(params.get("channel_dict", "{}")) @@ -68,6 +100,8 @@ def run(test, params, env): input_dict = eval(params.get('input_dict', '{}')) device_alias = "ua-" + str(uuid.uuid4()) + if redir_type: + usb_cmd = usb_base.get_host_pkg_and_cmd()[1] def check_device_by_alias(dev_type, dev_alias, expect_exist=True): """ @@ -125,9 +159,15 @@ def start_usbredirserver(): """ lsusb_list = process.run('lsusb').stdout_text.splitlines() - ps = process.SubProcess("usbredirserver -p {} {}".format - (port, lsusb_list[0].split()[5]), shell=True) - server_id = ps.start() + for usb_info in lsusb_list: + if re.search("hub", usb_info, re.IGNORECASE): + continue + if len(usb_info.split()[5].split(':')) == 2: + vendor_id, product_id = usb_info.split()[5].split(':') + if not (vendor_id and product_id): + test.fail("vendor/product id is not available") + server_id = usb_base.start_redirect_server(params, usb_cmd, vendor_id, product_id) + time.sleep(2) return server_id # backup xml @@ -159,10 +199,7 @@ def start_usbredirserver(): dev_type='controller', dev_dict=controller_dict, index=int(params.get("index"))) - - pci_id = utils_misc.get_full_pci_id( - utils_misc.get_pci_id_using_filter(pci_filter)[-1]) - + pci_id = get_suitable_pci_device(test) if not vm.is_alive(): vm.start() vm.wait_for_login() @@ -266,7 +303,9 @@ def start_usbredirserver(): vmxml.remove_all_device_by_type('input') input_dict.update({"alias": {"name": device_alias}}) if input_type == "passthrough": - event = process.run("ls /dev/input/event*", shell=True).stdout + event = process.run("ls /dev/input/event*", shell=True, ignore_status=True).stdout + if len(event) == 0: + test.cancel("Not found any input devices") input_dict.update({"source_evdev": event.decode('utf-8').split()[0]}) input_obj = Input(type_name=input_type) diff --git a/libvirt/tests/src/virsh_cmd/domain/virsh_domdirtyrate_calc.py b/libvirt/tests/src/virsh_cmd/domain/virsh_domdirtyrate_calc.py index 7570ee807fe..d5be7f6e664 100644 --- a/libvirt/tests/src/virsh_cmd/domain/virsh_domdirtyrate_calc.py +++ b/libvirt/tests/src/virsh_cmd/domain/virsh_domdirtyrate_calc.py @@ -1,11 +1,11 @@ -import time import logging as log +import time from virttest import virsh from virttest import libvirt_version from virttest.libvirt_xml import vm_xml -from virttest.utils_test import libvirt from virttest.utils_stress import install_stressapptest +from virttest import utils_misc logging = log.getLogger('avocado.' + __name__) @@ -52,9 +52,11 @@ def check_dirty_rate(dirty_rate): tolerance = 0.75 if abs(int(dirty_rate)/int(ram_size) - 1) > tolerance: - test.fail("Dirty rate calculated %s has a big difference " - "with the ram size %s loaded in guest " - % (dirty_rate, ram_size)) + logging.debug("Dirty rate calculated %s has a big difference " + "with the ram size %s loaded in guest " + % (dirty_rate, ram_size)) + return False + return True def check_output(): """ @@ -64,10 +66,10 @@ def check_output(): out_list = res.stdout_text.strip().splitlines()[1:] out_dict = {} out_dict = dict(item.strip().split("=") for item in out_list) - if out_dict["dirtyrate.calc_status"] != calc_status: - test.fail("Calculating dirty rate should be completed " - "after %s seconds" % period) + logging.debug("Calculating dirty rate should be completed " + "after approx. %s seconds" % period) + return False if out_dict["dirtyrate.calc_period"] != period: test.fail("Calculating period is not the same with " "the setting period %s" % period) @@ -78,9 +80,20 @@ def check_output(): if mode == "dirty-ring": for cpu_num in range(vm.get_cpu_count()): dirty_rate = out_dict["dirtyrate.vcpu.%s.megabytes_per_second" % cpu_num] - check_dirty_rate(dirty_rate) + return check_dirty_rate(dirty_rate) else: - check_dirty_rate(dirty_rate) + return check_dirty_rate(dirty_rate) + + def wait_for_output(): + """ + Trigger calculation and wait for expected result + """ + result = virsh.domdirtyrate_calc(vm_name, + options=option, + ignore_status=False, + debug=True) + time.sleep(1.2*int(period)) + return check_output() vm_name = params.get("main_vm") status_error = "yes" == params.get("status_error", "no") @@ -108,15 +121,18 @@ def check_output(): load_stress(vm) - result = virsh.domdirtyrate_calc(vm_name, options=option, ignore_status=True, debug=True) - - time.sleep(int(period)) - libvirt.check_exit_status(result) - if status_error: return else: - check_output() + result = utils_misc.wait_for(lambda: wait_for_output(), + step=int(period), + text="Waiting for the dirty rate", + timeout=60, + ignore_errors=True) + if not result: + test.fail("Didn't get the right dirty rate.") + else: + logging.debug("Dirty rate as expected.") finally: if vm.is_alive(): diff --git a/libvirt/tests/src/virsh_cmd/domain/virsh_domfstrim.py b/libvirt/tests/src/virsh_cmd/domain/virsh_domfstrim.py index 526898f3d34..a1b73139b03 100644 --- a/libvirt/tests/src/virsh_cmd/domain/virsh_domfstrim.py +++ b/libvirt/tests/src/virsh_cmd/domain/virsh_domfstrim.py @@ -20,6 +20,16 @@ logging = log.getLogger('avocado.' + __name__) +def try_set_selinux_label(session): + """ + Per default selinux will block the guest agent + from trimming the device. Try to set label for this test + + :param session: VM console session + """ + session.cmd_output("setsebool -P virt_qemu_ga_read_nonsecurity_files on", timeout=120) + + def run(test, params, env): """ Test domfstrim command, make sure that all supported options work well @@ -100,6 +110,7 @@ def recompose_xml(vm_name, scsi_disk): if not vm.is_alive(): vm.start() session = vm.wait_for_login() + try_set_selinux_label(session) bef_list = session.cmd_output("fdisk -l|grep ^/dev|" "cut -d' ' -f1").split("\n") session.close() @@ -186,7 +197,7 @@ def _full_mapped(): def _trim_completed(): """ Do empty fstrim check - :return: True of False + :return: True or False """ cmd_result = virsh.domfstrim(vm_name, minimum, mountpoint, options, unprivileged_user=unprivileged_user, diff --git a/libvirt/tests/src/virsh_cmd/domain/virsh_domif_setlink_getlink.py b/libvirt/tests/src/virsh_cmd/domain/virsh_domif_setlink_getlink.py index a59e2c2cc5d..87d3fb509b2 100644 --- a/libvirt/tests/src/virsh_cmd/domain/virsh_domif_setlink_getlink.py +++ b/libvirt/tests/src/virsh_cmd/domain/virsh_domif_setlink_getlink.py @@ -10,6 +10,7 @@ from virttest import utils_misc from virttest import utils_libvirtd from virttest.libvirt_xml import vm_xml +from virttest.utils_libvirt import libvirt_vmxml from virttest.utils_test import libvirt @@ -68,7 +69,18 @@ def guest_cmd_check(cmd, session, pattern): logging.debug(e) return re.search(pattern, str(e.__str__)) - def guest_if_state(if_name, session): + def guest_ifstate_check(ifname, expected_state, session): + """ + Check guest interface dev state in session + """ + iface_info = utils_net.get_linux_iface_info(mac=mac_address, session=session) + logging.debug("guest iface %s info: %s" % (ifname, iface_info)) + if iface_info['ifname'] == ifname: + return iface_info['operstate'] == expected_state + else: + test.fail("Did not get expected % from mac %s" % (ifname, mac_address)) + + def guest_link_state(if_name, session): """ Get the domain link state from the guest """ @@ -100,7 +112,7 @@ def check_update_device(vm, if_name, session): if ret.exit_status: logging.error("Failed to update device to up state") return False - if not utils_misc.wait_for(lambda: guest_if_state(if_name, session), 5): + if not utils_misc.wait_for(lambda: guest_link_state(if_name, session), 5): logging.error("Guest link should be up now") return False @@ -112,7 +124,7 @@ def check_update_device(vm, if_name, session): if ret.exit_status: logging.error("Failed to update device to down state") return False - if utils_misc.wait_for(lambda: guest_if_state(if_name, session), 5): + if utils_misc.wait_for(lambda: guest_link_state(if_name, session), 5): logging.error("Guest link should be down now") return False @@ -149,6 +161,9 @@ def check_update_device(vm, if_name, session): # generate a new one suitable for the model if vm.is_alive(): vm.destroy() + if model_type != 'virtio': + vmxml = vm_xml.VMXML.new_from_dumpxml(vm.name) + libvirt_vmxml.modify_vm_device(vmxml, 'interface', {'driver': None}) iface_dict = {'model': model_type, 'del_addr': 'yes'} libvirt.modify_vm_iface(vm_name[0], "update_iface", iface_dict) # Vm status @@ -239,6 +254,9 @@ def check_update_device(vm, if_name, session): error_msg = None if status_error == "no" and not post_action: + # Close then establish a connection with the serial console + vm.cleanup_serial_console() + vm.create_serial_console() # Serial login the vm to check link status # Start vm check the link statue session = vm.wait_for_serial_login(username=username, @@ -248,10 +266,10 @@ def check_update_device(vm, if_name, session): # Check link state in guest if check_link_state: if (if_operation == "up" and - not guest_if_state(guest_if_name, session)): + not guest_link_state(guest_if_name, session)): error_msg = "Link state should be up in guest" if (if_operation == "down" and - guest_if_state(guest_if_name, session)): + guest_link_state(guest_if_name, session)): error_msg = "Link state should be down in guest" if error_msg: test.fail(error_msg) @@ -264,21 +282,18 @@ def check_update_device(vm, if_name, session): # Set the link up make host connect with vm domif_setlink(vm_name[0], device, "up", "") if not utils_misc.wait_for( - lambda: guest_if_state(guest_if_name, session), 5): + lambda: guest_link_state(guest_if_name, session), 5): test.fail("Link state isn't up in guest") # Ignore status of this one cmd = 'ip link set %s down;' % guest_if_name session.cmd_status_output(cmd, timeout=10) - pattern = "%s:.*state DOWN.*" % guest_if_name - pattern_cmd = 'ip addr show dev %s' % guest_if_name - guest_cmd_check(pattern_cmd, session, pattern) + guest_ifstate_check(guest_if_name, 'DOWN', session) cmd = 'ip link set %s up;' % guest_if_name session.cmd_status_output(cmd, timeout=10) - pattern = "%s:.*state UP.*" % guest_if_name - if not utils_misc.wait_for(lambda: guest_cmd_check( - pattern_cmd, session, pattern), timeout=20): + if not utils_misc.wait_for(lambda: guest_ifstate_check( + guest_if_name, 'UP', session), timeout=20): test.fail("Could not bring up interface %s inside guest" % guest_if_name) else: # negative test diff --git a/libvirt/tests/src/virsh_cmd/domain/virsh_domjobinfo.py b/libvirt/tests/src/virsh_cmd/domain/virsh_domjobinfo.py index 4dd8b77223a..34faaf83532 100644 --- a/libvirt/tests/src/virsh_cmd/domain/virsh_domjobinfo.py +++ b/libvirt/tests/src/virsh_cmd/domain/virsh_domjobinfo.py @@ -4,6 +4,8 @@ import time import locale +from avocado.utils import process as host_process + from virttest import virsh from virttest import data_dir from virttest import utils_libvirtd @@ -140,6 +142,7 @@ def cmp_jobinfo(result, info_list, job_type, actions): if os.path.exists(tmp_pipe): os.unlink(tmp_pipe) os.mkfifo(tmp_pipe) + host_process.run('chcon -t virtqemud_t %s' % tmp_pipe, ignore_status=False, shell=True) # Target file param is not needed for managedsave operation if action == "managedsave ": diff --git a/libvirt/tests/src/virsh_cmd/domain/virsh_domtime.py b/libvirt/tests/src/virsh_cmd/domain/virsh_domtime.py index c4eaec7567c..b699a3a6898 100644 --- a/libvirt/tests/src/virsh_cmd/domain/virsh_domtime.py +++ b/libvirt/tests/src/virsh_cmd/domain/virsh_domtime.py @@ -74,7 +74,7 @@ def run_cmd(session, cmd): cmd, duration, output.strip()) return output, duration - def get_guest_times(session): + def get_guest_times(session, get_local_hw): """ Retrieve different guest time as a dict for checking. Keys: @@ -84,34 +84,37 @@ def get_guest_times(session): domtime: Guest system time in UTC got from virsh domtime command :param session: Session from which to access guest + :param get_local_hw: if to use hwclock to get info """ times = {} get_begin = time.time() - # Guest RTC local timezone time - output, _ = run_cmd(session, 'hwclock') - try: - time_str, _ = re.search(r"(.+) (\S+ seconds)", output).groups() + # Guest RTC local timezone time + if get_local_hw: + output, _ = run_cmd(session, 'hwclock') try: - # output format 1: Tue 01 Mar 2016 01:53:46 PM CST - # Remove timezone info from output - new_str = re.sub(r'\s+\S+$', '', time_str) - times['local_hw'] = datetime.datetime.strptime( - new_str, r"%a %d %b %Y %I:%M:%S %p") - except ValueError: - # There are known three possible output format for `hwclock` - # output format 2: Sat Feb 14 07:31:33 2009 - times['local_hw'] = datetime.datetime.strptime( - time_str, r"%a %b %d %H:%M:%S %Y") - except AttributeError: - try: # output format 3: 2019-03-22 05:16:18.224511-04:00 - time_str = output.split(".")[0] - times['local_hw'] = datetime.datetime.strptime( - time_str, r"%Y-%m-%d %H:%M:%S") - except ValueError: - test.fail("Unknown hwclock output format in guest: %s", output) - delta = time.time() - get_begin - times['local_hw'] -= datetime.timedelta(seconds=delta) + time_str, _ = re.search(r"(.+) (\S+ seconds)", output).groups() + + try: + # output format 1: Tue 01 Mar 2016 01:53:46 PM CST + # Remove timezone info from output + new_str = re.sub(r'\s+\S+$', '', time_str) + times['local_hw'] = datetime.datetime.strptime( + new_str, r"%a %d %b %Y %I:%M:%S %p") + except ValueError: + # There are known three possible output format for `hwclock` + # output format 2: Sat Feb 14 07:31:33 2009 + times['local_hw'] = datetime.datetime.strptime( + time_str, r"%a %b %d %H:%M:%S %Y") + except AttributeError: + try: # output format 3: 2019-03-22 05:16:18.224511-04:00 + time_str = output.split(".")[0] + times['local_hw'] = datetime.datetime.strptime( + time_str, r"%Y-%m-%d %H:%M:%S") + except ValueError: + test.fail("Unknown hwclock output format in guest: %s", output) + delta = time.time() - get_begin + times['local_hw'] -= datetime.timedelta(seconds=delta) # Guest system local timezone time try: @@ -353,6 +356,9 @@ def stop_vm(): vm = env.get_vm(vm_name) readonly = (params.get("readonly_test", "no") == "yes") + restore_time = "yes" == params.get("restore_time", "yes") + get_local_hw = "yes" == params.get("get_local_hw", "yes") + # Backup domain XML xml_backup = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) try: @@ -365,7 +371,7 @@ def stop_vm(): # have day light savings, to affect the time session.cmd("timedatectl set-timezone Asia/Kolkata") try: - init_guest_times, _ = get_guest_times(session) + init_guest_times, _ = get_guest_times(session, get_local_hw) guest_tz_diff = init_guest_times['local_sys'] - init_guest_times['utc_sys'] logging.debug("Timezone diff on guest is %d hours.", (guest_tz_diff.total_seconds() // 3600)) @@ -393,7 +399,7 @@ def stop_vm(): org_host_loc_time = datetime.datetime.strptime(time_st, r"%a %b %d %H:%M:%S %Y") # Get original guest times - org_times, guest_duration = get_guest_times(session) + org_times, guest_duration = get_guest_times(session, get_local_hw) # Run some operations to stop guest system stop_time = stop_vm() @@ -410,7 +416,7 @@ def stop_vm(): if not shutdown: # Get current guest times - cur_times, _ = get_guest_times(session) + cur_times, _ = get_guest_times(session, get_local_hw) check_time(res, org_times, cur_times) finally: @@ -420,7 +426,7 @@ def stop_vm(): utils_time.sync_timezone_linux(vm) # Sync guest time with host if channel and agent and not shutdown: - res = virsh.domtime(vm_name, now=True) + res = virsh.domtime(vm_name, now=restore_time) if res.exit_status: session.close() test.error("Failed to recover guest time:\n%s" diff --git a/libvirt/tests/src/virsh_cmd/domain/virsh_domxml_from_native.py b/libvirt/tests/src/virsh_cmd/domain/virsh_domxml_from_native.py index 7d665e70db4..ddd2b55ee93 100644 --- a/libvirt/tests/src/virsh_cmd/domain/virsh_domxml_from_native.py +++ b/libvirt/tests/src/virsh_cmd/domain/virsh_domxml_from_native.py @@ -34,7 +34,7 @@ def virsh_convxml(guest_args): pid = vm.get_pid() cmdline = process.run("cat -v /proc/%d/cmdline" % pid).stdout_text cmdline = re.sub(r'\^@', ' ', cmdline) - cmdline_tmp = re.sub(r'\s-drive\s[^\s]+', '\s', cmdline) + cmdline_tmp = re.sub(r'\s-drive\s[^\s]+', ' ', cmdline) # Libvirt requires the binary path for domxml-from-native to succeed # /proc/pid/cmdline would give qemu cmdline with binary without diff --git a/libvirt/tests/src/virsh_cmd/domain/virsh_edit.py b/libvirt/tests/src/virsh_cmd/domain/virsh_edit.py index b8e9b1dbac6..3e223c62d40 100644 --- a/libvirt/tests/src/virsh_cmd/domain/virsh_edit.py +++ b/libvirt/tests/src/virsh_cmd/domain/virsh_edit.py @@ -117,8 +117,10 @@ def edit_vcpu(source): dic_mode["recover"]]) else: status = libvirt.exec_virsh_edit(vm_name, [dic_mode["recover"]]) + logging.info(status) vmxml.sync() if status and new_vcpus != expected_vcpu: + logging.debug("new_vcpus, expected_vcpu: %s, %s", new_vcpus, expected_vcpu) return False return status diff --git a/libvirt/tests/src/virsh_cmd/domain/virsh_emulatorpin.py b/libvirt/tests/src/virsh_cmd/domain/virsh_emulatorpin.py index dadb85a6ad2..47cdfa3beae 100644 --- a/libvirt/tests/src/virsh_cmd/domain/virsh_emulatorpin.py +++ b/libvirt/tests/src/virsh_cmd/domain/virsh_emulatorpin.py @@ -38,7 +38,7 @@ def get_emulatorpin_from_cgroup(params, test): cpuset_file = os.path.join(cpuset_path, "cpuset.cpus") try: - with open(cpuset_file, "rU") as f_emulatorpin_params: + with open(cpuset_file, "r") as f_emulatorpin_params: emulatorpin_params_from_cgroup = f_emulatorpin_params.readline() return emulatorpin_params_from_cgroup except IOError: @@ -254,9 +254,6 @@ def run(test, params, env): check_cpus_allowed_list = "yes" == params.get("check_cpus_allowed_list", "") host_cpus_num = cpu.online_count() - if all_cpuset and int(host_cpus_num) % 8 != 0: - test.cancel("Host cpu number is expected to be multiple of 8, " - "but found %s" % host_cpus_num) # Backup original vm vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) vmxml_backup = vmxml.copy() diff --git a/libvirt/tests/src/virsh_cmd/domain/virsh_guestinfo.py b/libvirt/tests/src/virsh_cmd/domain/virsh_guestinfo.py index e40087a4a32..601d080a90f 100644 --- a/libvirt/tests/src/virsh_cmd/domain/virsh_guestinfo.py +++ b/libvirt/tests/src/virsh_cmd/domain/virsh_guestinfo.py @@ -8,6 +8,7 @@ from virttest import data_dir from virttest import libvirt_version from virttest import utils_misc +from virttest.utils_test import VMStress from virttest.utils_test import libvirt @@ -45,20 +46,40 @@ def check_attached_disk_info(disk_info, target_name): :param target_name: the target name for the attached disk :return: the attached disk info returned from virsh guestinfo --disk """ - attached_disk_info_reported = False + serial_num_reported = False + bus_type_reported = False disk_logical_name = '/dev/%s' % target_name for i in range(int(disk_info['disk.count'])): prefix = 'disk.' + str(i) + '.' try: - if disk_info[prefix + 'alias'] == target_name: - if (disk_info[prefix + 'name'] == disk_logical_name and - disk_info[prefix + 'partition'] == 'no' and - disk_info[prefix + 'serial'] == serial_num): - attached_disk_info_reported = True - break + if (disk_info[prefix + 'alias'] == target_name and + disk_info[prefix + 'name'] == disk_logical_name and + disk_info[prefix + 'partition'] == 'no'): + support_dict = {} + support_dict["func_supported_since_libvirt_ver"] = "(7, 3, 0)" + if libvirt_version.is_libvirt_feature_supported(support_dict, ignore_error=True): + if disk_info[prefix + 'serial'] == serial_num: + serial_num_reported = True + logging.debug("Disk serial num is returned in guestinfo") + else: + return False + else: + # If serial is unsupported, treat it as already reported + serial_num_reported = True + support_dict["func_supported_since_libvirt_ver"] = "(11, 2, 0)" + if libvirt_version.is_libvirt_feature_supported(support_dict, ignore_error=True): + if disk_info[prefix + 'guest_bus'] == disk_target_bus: + bus_type_reported = True + logging.debug("Disk bus type is returned in guestinfo") + else: + return False + else: + # If bus_type is unsupported, treat it as already reported + bus_type_reported = True + break except KeyError: logging.error("Num %i is not the attached disk", i) - return attached_disk_info_reported + return serial_num_reported and bus_type_reported def check_guest_os_info(): """ @@ -304,7 +325,7 @@ def check_guest_interface_info(): if_info = {} session = vm.wait_for_login() try: - ip_cmd = 'ip a' + ip_cmd = 'ip -c=never a' ip_lines = session.cmd_output(ip_cmd).strip().splitlines() if_info = parse_interface_info(ip_lines) finally: @@ -312,6 +333,26 @@ def check_guest_interface_info(): logging.debug("if_info is %s", if_info) return if_info + def check_load_info_by_agent(load_info): + """ + Check the cpu load information reported by guest agent + + :param load_info: dict, load information from guestinfo command with --load + like {"load.1m":"0.917969","load.5m":"1.265625","load.15m":"0.906738"} + """ + load_info_field = eval(params.get("load_info_field")) + for item, value in load_info.items(): + if item not in load_info_field: + test.fail("Expect load info fields:%s, but found %s" % (load_info_field, item)) + try: + if float(value) <= 0: + test.fail("Incorrect load info value %s for field %s" % (value, item)) + except ValueError as err: + test.fail("Invalid load info value %s for field %s" % (value, item)) + test.log.debug("Verify load info from guest agent - PASS") + + libvirt_version.is_libvirt_feature_supported(params) + vm_name = params.get("main_vm") option = params.get("option", " ") added_user_name = params.get("added_user_name") @@ -322,10 +363,11 @@ def check_guest_interface_info(): disk_target_name = params.get("disk_target_name") disk_name = params.get("disk_name") serial_num = params.get("serial_num") + disk_target_bus = params.get("disk_target_bus") readonly_mode = ("yes" == params.get("readonly_mode")) + stress_in_vm = ("yes" == params.get("stress_in_vm")) + remove_exist = ("yes" == params.get("remove_exist_qa")) - if not libvirt_version.version_compare(6, 0, 0): - test.cancel("Guestinfo command is not supported before version libvirt-6.0.0 ") import dateutil.parser added_user_session = None @@ -338,7 +380,12 @@ def check_guest_interface_info(): virsh_dargs["readonly"] = True if start_ga and prepare_channel: - vm.prepare_guest_agent(start=True, channel=True) + vm.prepare_guest_agent(start=True, channel=True, remove_existing=remove_exist) + + if stress_in_vm: + params.update({"stress_dependency_packages_list": "['gcc', 'make']"}) + vm_stress = VMStress(vm, "stress", params) + vm_stress.load_stress_tool() if "user" in option: add_user(added_user_name, added_user_passwd) @@ -372,6 +419,9 @@ def check_guest_interface_info(): test.fail("The disk info reported by agent cmd is not correct. " "result: %s" % info_from_agent_cmd) return + elif "load" in option: + check_load_info_by_agent(info_from_agent_cmd) + return else: if "filesystem" in option: info_from_guest = check_guest_filesystem_info(info_from_agent_cmd) diff --git a/libvirt/tests/src/virsh_cmd/domain/virsh_guestvcpus.py b/libvirt/tests/src/virsh_cmd/domain/virsh_guestvcpus.py index 2e61860cb46..84b124ba653 100644 --- a/libvirt/tests/src/virsh_cmd/domain/virsh_guestvcpus.py +++ b/libvirt/tests/src/virsh_cmd/domain/virsh_guestvcpus.py @@ -1,5 +1,6 @@ import logging as log +from avocado.utils import cpu from virttest import virsh from virttest import cpu as cpuutil @@ -19,109 +20,62 @@ def run(test, params, env): The command query or modify state of vcpu in the vm 1. Prepare test environment, start vm with guest agent 2. Perform virsh guestvcpus query/enable/disable operation - 3. Check the cpus in the vm - 4. Recover test environment + 3. Check the vcpu number by virsh command via guest agent + 4. Check the vcpu number within the guest + 5. In combine tests, repeat steps 2-4 + 6. Recover test environment """ vm_name = params.get("main_vm") vm = env.get_vm(vm_name) vcpus_num = int(params.get("vcpus_num", "20")) vcpus_placement = params.get("vcpus_placement", "static") + max_test_combine = params.get("max_test_combine", "") option = params.get("option", "") combine = params.get("combine", "") - invalid_domain = params.get("invalid_domain", "") - domain_name = params.get("domain_name", "") - invalid_cpulist = params.get("invalid_cpulist", "") status_error = params.get("status_error", "no") - error_msg = eval(params.get('error_msg', '[]')) vcpus_list = "" - offline_vcpus = "" # Back up domain XML vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) vmxml_bakup = vmxml.copy() + # Max test: set vcpus_num to the host online cpu number + if max_test_combine == "yes": + vcpus_num = cpu.online_count() + logging.debug("Host online CPU number: %s", str(vcpus_num)) + try: # Modify vm with static vcpus if vm.is_alive(): vm.destroy() vmxml.placement = vcpus_placement vmxml.set_vm_vcpus(vm_name, vcpus_num, vcpus_num, topology_correction=True) - logging.debug("Define guest with '%s' vcpus" % str(vcpus_num)) + logging.debug("Define guest with '%s' vcpus", str(vcpus_num)) # Start guest agent in vm vm.prepare_guest_agent() - # Normal test: disable/ enable guest vcpus + # Normal test: disable/enable guest vcpus if option and status_error == "no": - for cpu in range(1, vcpus_num): - virsh.guestvcpus(vm_name, str(cpu), option, debug=True) + for vcpu in range(1, vcpus_num): + virsh.guestvcpus(vm_name, str(vcpu), option, debug=True) + check_cpu_count(test, params, env, vcpus_num, option) - # Normal test: combine: --disable 1-max then --enable 1 - if combine == "yes" and status_error == "no": + # Combine: --disable 1-max then --enable + if (max_test_combine == "yes" or combine == "yes") and status_error == "no": vcpus_list = '1' + '-' + str(vcpus_num - 1) option = "--disable" virsh.guestvcpus(vm_name, vcpus_list, option, debug=True) - vcpus_list = '1' - option = "--enable" - virsh.guestvcpus(vm_name, vcpus_list, option, debug=True) - - # Error test: invalid_domain - if invalid_domain == "yes": - vm_name = domain_name - # Error test: invalid_cpulist - if invalid_cpulist == "yes": - if option == "--enable": - vcpus_list = str(vcpus_num) - else: - vcpus_list = '0' + '-' + str(vcpus_num - 1) - ret = virsh.guestvcpus(vm_name, vcpus_list, option) - else: - # Query guest vcpus - ret = virsh.guestvcpus(vm_name) - output = ret.stdout.strip() + check_cpu_count(test, params, env, vcpus_num, option) - # Check test results - if status_error == "yes": - libvirt.check_result(ret, error_msg) - else: - # Check the test result of query - ret_output = dict([item.strip() for item in line.split(":")] - for line in output.split("\n")) + # Max test: --enable 1-max (no change to vcpus_list) + # Normal test: --enable 1 if combine == "yes": - online_vcpus = '0-1' - elif option == "--disable": - online_vcpus = '0' - else: - online_vcpus = '0' + '-' + str(vcpus_num - 1) - - if ret_output["online"] != online_vcpus: - test.fail("Query result is different from" - " the '%s' command." % option) + vcpus_list = '1' - # Check the cpu in guest - session = vm.wait_for_login() - vm_cpu_info = cpuutil.get_cpu_info(session) - session.close() - - if combine == "yes": - online_vcpus = '0,1' - elif option == "--disable": - online_vcpus = '0' - offline_vcpus = '1' + '-' + str(vcpus_num - 1) - else: - online_vcpus = '0' + '-' + str(vcpus_num - 1) - - if offline_vcpus: - if (vm_cpu_info["Off-line CPU(s) list"] != offline_vcpus or - vm_cpu_info["On-line CPU(s) list"] != online_vcpus): - test.fail("CPUs in vm is different from" - " the %s command." % option) - elif vm_cpu_info["On-line CPU(s) list"] != online_vcpus: - test.fail("On-line CPUs in vm is different" - " from the %s command." % option) - else: - logging.debug("lscpu in vm '%s' is: \n '%s'" % - (vm_name, vm_cpu_info)) + option = "--enable" + virsh.guestvcpus(vm_name, vcpus_list, option, debug=True) + check_cpu_count(test, params, env, vcpus_num, option) finally: # Recover VM @@ -129,3 +83,82 @@ def run(test, params, env): vm.destroy(gracefully=False) logging.info("Restoring vm...") vmxml_bakup.sync() + + +def check_cpu_count(test, params, env, vcpus_num, option=""): + """ + Makes any changes necessary for the error test and then + runs the vcpu checks specified in steps 3 and 4 of run() + + 3. Check the vcpu number by virsh command via guest agent + 4. Check the vcpu number within the guest + """ + vm_name = params.get("main_vm") + vm = env.get_vm(vm_name) + combine = params.get("combine", "") + invalid_domain = params.get("invalid_domain", "") + domain_name = params.get("domain_name", "") + invalid_cpulist = params.get("invalid_cpulist", "") + status_error = params.get("status_error", "no") + error_msg = eval(params.get('error_msg', '[]')) + vcpus_list = "" + offline_vcpus = "" + + # Error test: invalid_domain + if invalid_domain == "yes": + vm_name = domain_name + # Error test: invalid_cpulist + if invalid_cpulist == "yes": + if option == "--enable": + vcpus_list = str(vcpus_num) + else: + vcpus_list = '0' + '-' + str(vcpus_num - 1) + ret = virsh.guestvcpus(vm_name, vcpus_list, option) + else: + # Query guest vcpus + ret = virsh.guestvcpus(vm_name) + output = ret.stdout.strip() + + # Check test results + if status_error == "yes": + libvirt.check_result(ret, error_msg) + else: + # Check the test result of query + ret_output = dict([item.strip() for item in line.split(":")] + for line in output.split("\n")) + if combine == "yes" and option == "--enable": + online_vcpus = '0-1' + elif option == "--disable": + online_vcpus = '0' + else: + # either normal --enable test or max test on the --enable step + online_vcpus = '0' + '-' + str(vcpus_num - 1) + + if ret_output["online"] != online_vcpus: + test.fail("Expected online vcpus to be %s, " + "but found %s." % (online_vcpus, ret_output["online"])) + + # Check the vcpu number within the guest + session = vm.wait_for_login() + vm_cpu_info = cpuutil.get_cpu_info(session) + session.close() + + if combine == "yes" and option == "--enable": + online_vcpus = '0,1' + elif option == "--disable": + online_vcpus = '0' + offline_vcpus = '1' + '-' + str(vcpus_num - 1) + else: + # either normal --enable test or max test on the --enable step + online_vcpus = '0' + '-' + str(vcpus_num - 1) + + if offline_vcpus: + if (vm_cpu_info["Off-line CPU(s) list"] != offline_vcpus or + vm_cpu_info["On-line CPU(s) list"] != online_vcpus): + test.fail("CPUs in vm is different from" + " the `virsh guestvcpus %s` command." % option) + elif vm_cpu_info["On-line CPU(s) list"] != online_vcpus: + test.fail("On-line CPUs in vm is different" + " from the `virsh guestvcpus %s` command." % option) + logging.debug("lscpu in vm '%s' is: \n '%s'", + vm_name, vm_cpu_info) diff --git a/libvirt/tests/src/virsh_cmd/domain/virsh_iothreadadd.py b/libvirt/tests/src/virsh_cmd/domain/virsh_iothreadadd.py index df59d8077f4..81d5a4db3ef 100644 --- a/libvirt/tests/src/virsh_cmd/domain/virsh_iothreadadd.py +++ b/libvirt/tests/src/virsh_cmd/domain/virsh_iothreadadd.py @@ -26,6 +26,23 @@ def get_xmlinfo(vm_name, options): return xml_info.iothreadids.iothread +def check_iothread_id(iothread_list, search_iothread_id, test): + """ + Check if the specified iothread id exists + + :param iothread_list: list, iothread id information + :param search_iothread_id: str, the iothread id to be searched + :param test: test object + """ + found = False + for a_iothread in iothread_list: + if search_iothread_id == a_iothread['id']: + found = True + if not found: + test.fail("Can not find iothread '%s' in " + "domain xml" % search_iothread_id) + + def run(test, params, env): """ Test command: virsh iothread. @@ -115,9 +132,7 @@ def run(test, params, env): # Check domainxml iothread_info = get_xmlinfo(vm_name, options) logging.debug("iothreadinfo: %s", iothread_info) - if {'id': iothread_id} not in iothread_info: - test.fail("Failed to add iothread '%s' in " - "domain xml" % iothread_id) + check_iothread_id(iothread_info, iothread_id, test) # Check iothreadinfo by virsh command iothread_info = libvirt.get_iothreadsinfo(dom_option, options) diff --git a/libvirt/tests/src/virsh_cmd/domain/virsh_iothreaddel.py b/libvirt/tests/src/virsh_cmd/domain/virsh_iothreaddel.py index a4a6f63e6ba..90867b71eeb 100644 --- a/libvirt/tests/src/virsh_cmd/domain/virsh_iothreaddel.py +++ b/libvirt/tests/src/virsh_cmd/domain/virsh_iothreaddel.py @@ -26,6 +26,23 @@ def get_xmlinfo(vm_name, options): return xml_info.iothreadids.iothread +def check_iothread_id(iothread_list, search_iothread_id, test): + """ + Check if the specified iothread id exists + + :param iothread_list: list, iothread id information + :param search_iothread_id: str, the iothread id to be searched + :param test: test object + """ + found = False + for a_iothread in iothread_list: + if search_iothread_id == a_iothread['id']: + found = True + if found: + test.fail("Can find iothread '%s' in " + "domain xml" % search_iothread_id) + + def run(test, params, env): """ Test command: virsh iothreaddel. @@ -115,15 +132,13 @@ def run(test, params, env): # Check domainxml iothread_info = get_xmlinfo(vm_name, options) logging.debug("iothreadinfo: %s", iothread_info) - if iothread_id in iothread_info: - raise exceptions.TestFail("Failed to add iothread %s in domain xml", - iothread_id) + check_iothread_id(iothread_info, iothread_id, test) # Check iothreadinfo by virsh command iothread_info = libvirt.get_iothreadsinfo(dom_option, options) logging.debug("iothreadinfo: %s", iothread_info) if iothread_id in iothread_info: - raise exceptions.TestFail("Failed to add iothread %s", iothread_id) + raise exceptions.TestFail("Failed to delete iothread %s", iothread_id) finally: # Cleanup diff --git a/libvirt/tests/src/virsh_cmd/domain/virsh_managedsave.py b/libvirt/tests/src/virsh_cmd/domain/virsh_managedsave.py index 733303977a2..feb564fafbe 100644 --- a/libvirt/tests/src/virsh_cmd/domain/virsh_managedsave.py +++ b/libvirt/tests/src/virsh_cmd/domain/virsh_managedsave.py @@ -1,22 +1,20 @@ +import logging as log import os import re import time -import logging as log from avocado.utils import process from avocado.utils import software_manager - -from virttest import virsh -from virttest import utils_libvirtd +from virttest import libvirt_version from virttest import utils_config -from virttest import utils_misc from virttest import utils_libguestfs -from virttest import libvirt_version +from virttest import utils_libvirtd +from virttest import utils_misc +from virttest import virsh from virttest.libvirt_xml import vm_xml -from virttest.utils_test import libvirt from virttest.staging.service import Factory from virttest.staging.utils_memory import drop_caches - +from virttest.utils_test import libvirt # Using as lower capital is not the best way to do, but this is just a # workaround to avoid changing the entire file. @@ -83,7 +81,7 @@ def vm_recover_check(option, libvirtd, check_shutdown=False): " paused after started" " because of '--paused' option") else: - if params.get("paused_after_start_vm") == "yes": + if paused_after_start_vm: if not vm.is_paused(): test.fail("Guest state should be" " paused after started" @@ -314,7 +312,7 @@ def build_vm_xml(vm_name, **dargs): vm.start() except Exception as e: logging.error(str(e)) - test.cancel("Build domain xml failed") + test.error("Build domain xml failed") status_error = ("yes" == params.get("status_error", "no")) vm_ref = params.get("managedsave_vm_ref", "name") @@ -338,6 +336,7 @@ def build_vm_xml(vm_name, **dargs): remove_test = 'yes' == params.get('remove_test', 'no') case = params.get('case', '') msave_rm_error = "yes" == params.get("msave_rm_error", "no") + paused_after_start_vm = "yes" == params.get('paused_after_start_vm', "no") if option: if not virsh.has_command_help_match('managedsave', option): # Older libvirt does not have this option @@ -424,6 +423,10 @@ def build_vm_xml(vm_name, **dargs): vm_ref = params.get(vm_ref) elif vm_ref == "name": vm_ref = vm_name + # Prepare the certain state before managedsave + if paused_after_start_vm: + logging.debug("Suspend the VM!") + virsh.suspend(vm_ref) # Ignore exception with "ignore_status=True" if progress: @@ -432,7 +435,7 @@ def build_vm_xml(vm_name, **dargs): # For bypass_cache test. Run a shell command to check fd flags while # executing managedsave command - software_mgr = software_manager.SoftwareManager() + software_mgr = software_manager.manager.SoftwareManager() if not software_mgr.check_installed('lsof'): logging.info('Installing lsof package:') software_mgr.install('lsof') @@ -535,5 +538,5 @@ def build_vm_xml(vm_name, **dargs): if multi_guests: for i in range(int(multi_guests)): virsh.remove_domain("%s_%s" % (vm_name, i), - "--remove-all-storage", + "--remove-all-storage --nvram", debug=True) diff --git a/libvirt/tests/src/virsh_cmd/domain/virsh_managedsave_restore.py b/libvirt/tests/src/virsh_cmd/domain/virsh_managedsave_restore.py new file mode 100644 index 00000000000..a4938236f8d --- /dev/null +++ b/libvirt/tests/src/virsh_cmd/domain/virsh_managedsave_restore.py @@ -0,0 +1,133 @@ +import logging +import os + +from virttest import virsh +from virttest import data_dir +from virttest import utils_misc +from virttest import utils_libguestfs +from virttest.libvirt_xml import vm_xml +from virttest.utils_test import libvirt +from avocado.utils import process + +from provider.save import save_base + +LOG = logging.getLogger('avocado.' + __name__) + + +def run(test, params, env): + """ + Test vm restore after managedsave with various conditions + """ + vm_name = params.get("main_vm") + vm = env.get_vm(vm_name) + managed_save_file = "/var/lib/libvirt/qemu/save/%s.save" % vm_name + + def check_libvirtd_log(): + """ + Check the libvirtd log for expected messages + """ + result = utils_misc.wait_for( + lambda: libvirt.check_logfile(expected_log, libvirtd_log_file), timeout=20) + if not result: + test.fail("Can't get expected log %s in %s" % (expected_log, libvirtd_log_file)) + + def start_shutdown_cycle(): + """ + Do a managedsave -> start -> shutdown cycle + """ + LOG.info("Do a start shutdown cycle to clear the saved state:") + vm.start() + if os.path.exists(managed_save_file): + test.fail("The saved file exists after restore: %s", managed_save_file) + virsh.shutdown(vm_name, debug=True) + if not vm.wait_for_shutdown(): + test.error('VM failed to shutdown in 60s') + + def setup_saved_file(): + """" + Prepare the pre-conditions about saved file + + 1. Prepare an invalid saved file if needed + 2. Update the saved file to use an occupied one if needed + 3. Remove the saved file if needed + """ + if file_state == "corrupt": + LOG.info("Corrupt the saved file by 'echo >' cmd:") + process.run("echo > %s" % managed_save_file, shell=True, ignore_status=True) + elif file_state == "occupied": + LOG.info("Update the saved file to use an occupied image:") + # Edit the current vm's saved state file to use another running VM's disk path + LOG.info("Clone a VM with name as %s:", add_vm_name) + utils_libguestfs.virt_clone_cmd(vm_name, add_vm_name, + True, timeout=360) + add_vm = vm.clone(add_vm_name) + add_vm.start() + # Get the add_vm disk path, and vm disk path, then replace the + # vm disk path to be add_vm disk path + add_vm_xml = vm_xml.VMXML.new_from_inactive_dumpxml(add_vm_name) + add_disk_xml = add_vm_xml.get_devices(device_type="disk")[0] + add_disk_path = add_disk_xml.source.attrs['file'] + + disk_xml = vmxml.get_devices(device_type="disk")[0] + vm_disk_path = disk_xml.source.attrs['file'] + xmlfile = os.path.join(data_dir.get_tmp_dir(), 'managedsave.xml') + virsh.managedsave_dumpxml(vm_name, to_file=xmlfile, ignore_status=False, debug=False) + + LOG.info("Update the disk path from %s to %s:", vm_disk_path, add_disk_path) + cmd = "sed -i 's|%s|%s|' %s" % (vm_disk_path, add_disk_path, xmlfile) + process.run(cmd, shell=True) + virsh.managedsave_define(vm_name, xmlfile, debug=True) + ret = virsh.managedsave_dumpxml(vm_name, '--xpath //disk', debug=True).stdout_text + LOG.info("After update, the disk in mangedsave state file is: %s", ret) + elif file_state == "nonexist": + LOG.info("Delete the saved file:") + process.run("rm -f %s" % managed_save_file, shell=True, ignore_status=True) + + file_state = params.get("file_state") + vm_managedsaved = "yes" == params.get("vm_managedsaved") + need_vm2 = "yes" == params.get("need_vm2", "no") + expected_log = params.get("expected_log", None) + expected_cmd_err = params.get("expected_cmd_err", None) + libvirtd_log_file = os.path.join(test.debugdir, "libvirtd.log") + vm_name = params.get('main_vm') + vm = env.get_vm(vm_name) + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + bk_xml = vmxml.copy() + appendix = utils_misc.generate_random_string(4) + add_vm_name = ("%s" % vm_name[:-1]) + ("%s" % appendix) + + try: + LOG.info("TEST_STEP1: Setup before restore the vm:") + if not vm.is_alive(): + vm.start() + pre_pid_ping, pre_upsince = save_base.pre_save_setup(vm) + virsh.managedsave(vm_name, debug=True) + if not vm_managedsaved: + start_shutdown_cycle() + else: + setup_saved_file() + + LOG.info("TEST_STEP2: Restore the vm by 'virsh start':") + ret = virsh.start(vm_name, debug=True) + libvirt.check_result(ret, expected_fails=expected_cmd_err) + virsh.destroy(add_vm_name, debug=True) + # if not expect error, vm should freshly start + if not expected_cmd_err: + LOG.info("TEST_STEP3: Check the vm should be freshly start:") + post_pid_ping, post_upsince = save_base.pre_save_setup(vm) + if pre_upsince == post_upsince: + test.fail("VM is not freshly start!") + else: + LOG.info("The uptime changed: %s vs %s", pre_upsince, post_upsince) + if file_state == 'corrupt': + LOG.info("TEST_STEP4: Check libvirtd log:") + check_libvirtd_log() + finally: + virsh.destroy(vm_name, debug=True) + virsh.undefine(vm_name, "--managed-save --keep-nvram", debug=True) + if os.path.exists(managed_save_file): + process.run("rm -f %s" % managed_save_file, shell=True, ignore_status=True) + bk_xml.sync() + if need_vm2: + LOG.info("Remove the additional VM: %s", add_vm_name) + virsh.remove_domain(add_vm_name, "--remove-all-storage --nvram") diff --git a/libvirt/tests/src/virsh_cmd/domain/virsh_managedsave_special_name.py b/libvirt/tests/src/virsh_cmd/domain/virsh_managedsave_special_name.py new file mode 100644 index 00000000000..c851d00e363 --- /dev/null +++ b/libvirt/tests/src/virsh_cmd/domain/virsh_managedsave_special_name.py @@ -0,0 +1,65 @@ +import os +import logging +from virttest import virsh +from virttest import libvirt_vm +from virttest.libvirt_xml import vm_xml +from avocado.utils import process + +from provider.save import save_base + +LOG = logging.getLogger('avocado.' + __name__) + + +def run(test, params, env): + """ + Try managedsave on VMs with special name + + 1. start a vm, and do managedsave + 2. check the saved file exists + 3. start the vm, check the vm status and saved file status + """ + special_name = params.get('vmname') + special_name_display = params.get('name_display') + managed_save_file = "/var/lib/libvirt/qemu/save/%s.save" % special_name + vm_name = params.get('main_vm') + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + bk_xml = vmxml.copy() + vm = env.get_vm(vm_name) + new_vm = libvirt_vm.VM(special_name, vm.params, vm.root_dir, vm.address_cache) + try: + LOG.info("TEST_STEP1: Rename the VM to be with special name:") + LOG.info("The special name is %s with %s characters.", + special_name, len(special_name)) + if vm.is_alive: + vm.destroy() + virsh.domrename(vm_name, special_name, debug=True) + vmlist = virsh.dom_list("--name --all", + debug=True).stdout_text + if special_name not in vmlist: + test.fail("Rename the VM fail!") + + LOG.info("TEST_STEP2: Start the VM and do managedsave:") + virsh.start(special_name, debug=True) + pid_ping, upsince = save_base.pre_save_setup(new_vm) + if virsh.managedsave(special_name, debug=True).exit_status: + test.fail("VM managedsave fail!") + + LOG.info("TEST_STEP3: Ensure vm state include 'saved', and the saved file exists:") + vm_state = virsh.domstate(special_name, extra="--reason", debug=True).stdout + LOG.info("vm %s state is %s", special_name, vm_state) + if "saved" not in vm_state: + test.fail("The domain state should include 'saved'!") + if not os.path.exists(managed_save_file): + test.fail("The saved file does not exist: %s" % managed_save_file) + + LOG.info("TEST_STEP4: Start the VM to restore:") + virsh.start(special_name, debug=True) + save_base.post_save_check(new_vm, pid_ping, upsince) + if os.path.exists(managed_save_file): + test.fail("The saved file should be removed!") + finally: + virsh.destroy(special_name, debug=True) + virsh.undefine(special_name, "--nvram --managed-save", debug=True) + if os.path.exists(managed_save_file): + process.run("rm -f %s" % managed_save_file, shell=True, ignore_status=True) + bk_xml.sync() diff --git a/libvirt/tests/src/virsh_cmd/domain/virsh_managedsave_undefine.py b/libvirt/tests/src/virsh_cmd/domain/virsh_managedsave_undefine.py new file mode 100644 index 00000000000..a83e669b565 --- /dev/null +++ b/libvirt/tests/src/virsh_cmd/domain/virsh_managedsave_undefine.py @@ -0,0 +1,56 @@ +import os +import logging +from virttest import virsh +from virttest.libvirt_xml import vm_xml +from virttest.utils_test import libvirt + +VIRSH_ARGS = {'debug': True, 'ignore_status': False} +LOG = logging.getLogger('avocado.' + __name__) + + +def run(test, params, env): + """ + Test option: --managed-save + + Undefine a vm with or without --managed-save option + 1. start a vm, and do managedsave + 2. try to undefine the vm without "--managed-save" option, it should fail + 3. try to undefine the vm with "--managed-save" option, it succeeds + """ + + def vm_undefine_check(vm_name): + """ + Check if vm can be undefined with managed-save option + """ + if not os.path.exists(managed_save_file): + test.fail("Can't find managed save image") + LOG.info("Step2: Undefine the VM without --managed-save option:") + ret = virsh.undefine(vm_name, options='--nvram', ignore_status=True, debug=True) + libvirt.check_exit_status(ret, expect_error=True) + LOG.info("Step3: Undefine the VM with --managed-save option:") + ret1 = virsh.undefine(vm_name, options="--managed-save --nvram", + ignore_status=True) + LOG.debug("%s", ret1) + if ret1.exit_status: + test.fail("Guest can't be undefined with " + "managed-save option!") + + if os.path.exists(managed_save_file): + test.fail("Managed save image exists after undefining vm!") + # restore and start the vm + bk_xml.define() + vm.start() + + vm_name = params.get('main_vm') + managed_save_file = "/var/lib/libvirt/qemu/save/%s.save" % vm_name + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + bk_xml = vmxml.copy() + try: + vm = env.get_vm(vm_name) + LOG.info("Step1: start the VM and do managedsave:") + if not vm.is_alive: + vm.start() + virsh.managedsave(vm_name, **VIRSH_ARGS) + vm_undefine_check(vm_name) + finally: + bk_xml.sync() diff --git a/libvirt/tests/src/virsh_cmd/domain/virsh_memtune.py b/libvirt/tests/src/virsh_cmd/domain/virsh_memtune.py index 45057a1da7e..68e422c1423 100644 --- a/libvirt/tests/src/virsh_cmd/domain/virsh_memtune.py +++ b/libvirt/tests/src/virsh_cmd/domain/virsh_memtune.py @@ -178,7 +178,8 @@ def run(test, params, env): # Get the vm name, pid of vm and check for alive vm = env.get_vm(params["main_vm"]) - vm.verify_alive() + if not vm.is_alive(): + vm.start() pid = vm.get_pid() # Resolve the memory cgroup path for a domain diff --git a/libvirt/tests/src/virsh_cmd/domain/virsh_metadata.py b/libvirt/tests/src/virsh_cmd/domain/virsh_metadata.py index 16847ec1c3f..8accef7dafe 100644 --- a/libvirt/tests/src/virsh_cmd/domain/virsh_metadata.py +++ b/libvirt/tests/src/virsh_cmd/domain/virsh_metadata.py @@ -3,8 +3,10 @@ import aexpect +from virttest import libvirt_version from virttest import remote from virttest import virsh + from virttest.utils_test import libvirt as utlv from virttest.utils_libvirtd import Libvirtd from virttest.libvirt_xml import vm_xml @@ -137,6 +139,7 @@ def get_metadata(metadata_option=""): check_result(result, status_error) # Get metadata again for option in metadata_option.split(): - check_result(get_metadata(metadata_option=option), True) + expect_error = False if libvirt_version.version_compare(11, 3, 0) else True + check_result(get_metadata(metadata_option=option), expect_error) finally: vmxml.sync() diff --git a/libvirt/tests/src/virsh_cmd/domain/virsh_migrate.py b/libvirt/tests/src/virsh_cmd/domain/virsh_migrate.py index 02514cfaf6b..35bbef79b46 100644 --- a/libvirt/tests/src/virsh_cmd/domain/virsh_migrate.py +++ b/libvirt/tests/src/virsh_cmd/domain/virsh_migrate.py @@ -109,6 +109,7 @@ def check_migration_result(migration_res): test.cancel(migration_res.stderr) def do_migration(delay, vm, dest_uri, options, extra, **virsh_args): + migration_msg = "Migration done." logging.info("Sleeping %d seconds before migration", delay) time.sleep(delay) # Migrate the guest. @@ -119,8 +120,9 @@ def do_migration(delay, vm, dest_uri, options, extra, **virsh_args): logging.info("Migration stderr: %s", migration_res.stderr) check_migration_result(migration_res) if int(migration_res.exit_status) != 0: - logging.error("Migration failed for %s.", vm_name) - return False + migration_msg = f"Migration failed for {vm_name}, with stderr: {migration_res.stderr}" + logging.error(migration_msg) + return (False, migration_msg) if options.count("dname") or extra.count("dname"): vm.name = extra.split()[1].strip() @@ -129,14 +131,15 @@ def do_migration(delay, vm, dest_uri, options, extra, **virsh_args): logging.info("Alive guest found on destination %s.", dest_uri) else: if not options.count("offline"): - logging.error("VM not alive on destination %s", dest_uri) - return False + migration_msg = f"VM not alive on destination {dest_uri}" + logging.error(migration_msg) + return (False, migration_msg) # Throws exception if console shows panic message if not options.count("dname") and not extra.count("dname"): vm.verify_kernel_crash() - return True + return (True, migration_msg) def numa_pin(memory_mode, memnode_mode, numa_dict_list, host_numa_node): """ @@ -246,6 +249,7 @@ def enable_hugepage(vmname, no_of_HPs, hp_unit='', hp_node='', pin=False, r"[\#\$]\s*$") cmd_output = server_session.cmd_status_output(command) server_session.close() + dest_HP_free = "" if (cmd_output[0] == 0): dest_HP_free = cmd_output[1].strip('HugePages_Free:').strip() else: @@ -735,12 +739,12 @@ def check_vm_state_dest(): "single node") # To check if Hugepage supported and configure + default_hp_unit = "KiB" if enable_HP or enable_HP_pin: try: hp_obj = test_setup.HugePageConfig(params) host_hp_size = hp_obj.get_hugepage_size() # libvirt xml takes HP sizes in KiB - default_hp_unit = "KiB" hp_pin_nodes = int(params.get("HP_pin_node_count", "2")) vm_max_mem = vmxml.max_mem no_of_HPs = int(vm_max_mem // host_hp_size) + 1 @@ -826,6 +830,7 @@ def check_vm_state_dest(): remote_libvirt_file = None src_libvirt_file = None scsi_disk = None + migration_msg = "No info." try: # Change the disk of the vm to shared disk @@ -1000,6 +1005,7 @@ def check_vm_state_dest(): # Prepare for --xml. xml_option = params.get("xml_option", "no") + new_nic_mac = "" if xml_option == "yes": if not extra.count("--dname") and not extra.count("--xml"): logging.debug("Preparing new xml file for --xml option.") @@ -1128,7 +1134,7 @@ def check_vm_state_dest(): else: ret_migrate = False if not asynch_migration: - ret_migrate = do_migration(delay, vm, dest_uri, options, extra, **virsh_args) + (ret_migrate, migration_msg) = do_migration(delay, vm, dest_uri, options, extra, **virsh_args) dest_state = params.get("virsh_migrate_dest_state", "running") if ret_migrate and dest_state == "running": @@ -1170,8 +1176,8 @@ def check_vm_state_dest(): .remove_key_for_modular_daemon(remove_dict, remote_dargs) if not asynch_migration: - ret_migrate = do_migration(delay, vm, src_uri, options, - extra) + (ret_migrate, migration_msg) = do_migration(delay, vm, src_uri, options, + extra) elif extra.count("--timeout-suspend"): func = check_migration_timeout_suspend try: @@ -1250,7 +1256,7 @@ def check_vm_state_dest(): # Check unsafe result and may do migration again in right mode if ret_migrate is False and unsafe_test: options = params.get("virsh_migrate_options") - ret_migrate = do_migration(delay, vm, dest_uri, options, extra) + (ret_migrate, migration_msg) = do_migration(delay, vm, dest_uri, options, extra) elif ret_migrate and unsafe_test: check_unsafe_result = False if vm_ref != vm_name: @@ -1322,10 +1328,10 @@ def check_vm_state_dest(): # Check test result. if status_error == 'yes': if ret_migrate: - test.fail("Migration finished with unexpected status.") + test.fail(f"Migration finished with unexpected status {migration_msg}.") else: if not ret_migrate: - test.fail("Migration finished with unexpected status.") + test.fail(f"Migration finished with unexpected status {migration_msg}.") if not check_dest_persistent: test.fail("VM is not persistent on destination.") if not check_src_undefine: diff --git a/libvirt/tests/src/virsh_cmd/domain/virsh_migrate_option_mix.py b/libvirt/tests/src/virsh_cmd/domain/virsh_migrate_option_mix.py index f0857f7f360..2faab30e70f 100644 --- a/libvirt/tests/src/virsh_cmd/domain/virsh_migrate_option_mix.py +++ b/libvirt/tests/src/virsh_cmd/domain/virsh_migrate_option_mix.py @@ -7,7 +7,6 @@ from virttest import utils_selinux from virttest import virsh -from virttest import utils_package from virttest import migration from virttest.utils_conn import TLSConnection from virttest.utils_test import libvirt @@ -227,26 +226,8 @@ def cleanup_vm(vm, vm_name='', uri=''): # Prepare for postcopy migration: install and run stress in VM if postcopy and src_vm_status == "running": logging.debug("Install and run stress in vm for postcopy migration") - pkg_name = 'stress' - - # Get a vm session - logging.debug("Get a vm session") - vm_session = vm.wait_for_login() - if not vm_session: - test.error("Can't get a vm session successfully") - - # Install package stress if it is not installed in vm - logging.debug("Check if stress tool is installed for postcopy migration") - pkg_mgr = utils_package.package_manager(vm_session, pkg_name) - if not pkg_mgr.is_installed(pkg_name): - logging.debug("Stress tool will be installed") - if not pkg_mgr.install(): - test.error("Package '%s' installation fails" % pkg_name) - - # Run stress in vm - logging.debug("Run stress in vm") - stress_args = params.get("stress_args") - vm_session.cmd('stress %s' % stress_args) + params.update({"stress_package": "stress"}) + obj_migration.run_stress_in_vm(vm, params) # Prepare for --xml . if xml_option: diff --git a/libvirt/tests/src/virsh_cmd/domain/virsh_numatune.py b/libvirt/tests/src/virsh_cmd/domain/virsh_numatune.py index dda489868cd..b808d1ed1da 100644 --- a/libvirt/tests/src/virsh_cmd/domain/virsh_numatune.py +++ b/libvirt/tests/src/virsh_cmd/domain/virsh_numatune.py @@ -197,8 +197,7 @@ def dynamic_node_replacement(params, numa_info, test_obj): numa_nodeset_format = params.get('numa_nodeset') dynamic_nodeset = params.get('dynamic_nodeset', 'no') == 'yes' if dynamic_nodeset and 'numa_nodeset' in params: - params['numa_nodeset'] = libvirt_numa.parse_numa_nodeset_to_str(numa_nodeset_format, - node_list) + params['numa_nodeset'] = libvirt_numa.convert_all_nodes_to_string(node_list) logging.debug('The parameter "numa_nodeset" from config file is going to be replaced by: {} ' 'available on this system'.format(params['numa_nodeset'])) diff --git a/libvirt/tests/src/virsh_cmd/domain/virsh_reboot.py b/libvirt/tests/src/virsh_cmd/domain/virsh_reboot.py index a9c580b776d..3a4748893b9 100644 --- a/libvirt/tests/src/virsh_cmd/domain/virsh_reboot.py +++ b/libvirt/tests/src/virsh_cmd/domain/virsh_reboot.py @@ -50,7 +50,7 @@ def get_boot_time(): logging.error("Get boot_time error:%s" % e) return boot_time - boot_time = utils_misc.wait_for(get_boot_time, 60) + boot_time = utils_misc.wait_for(get_boot_time, 120) session.close() return boot_time diff --git a/libvirt/tests/src/virsh_cmd/domain/virsh_restore.py b/libvirt/tests/src/virsh_cmd/domain/virsh_restore.py index c41a4c1ab8a..8bcb224079c 100644 --- a/libvirt/tests/src/virsh_cmd/domain/virsh_restore.py +++ b/libvirt/tests/src/virsh_cmd/domain/virsh_restore.py @@ -65,6 +65,7 @@ def check_file_own(file_path, exp_uid, exp_gid): check_log = params.get("check_log") check_str_not_in_log = params.get("check_str_not_in_log") qemu_conf_dict = eval(params.get("qemu_conf_dict", "{}")) + os_update_dict = eval(params.get("os_update_dict", "{}")) vm_ref_uid = None vm_ref_gid = None @@ -88,12 +89,7 @@ def check_file_own(file_path, exp_uid, exp_gid): os.chmod(vmxml.xml, stat.S_IRWXU | stat.S_IRGRP | stat.S_IROTH) if not setup_nfs: extra_param = "--xml %s" % vmxml.xml - dict_os_attrs = {} - if "hd" in vmxml.os.boots: - dict_os_attrs.update({"boots": ["cdrom"]}) - vmxml.set_os_attrs(**dict_os_attrs) - else: - test.cancel("Please add 'hd' in boots for --xml testing") + vmxml.set_os_attrs(**os_update_dict) logging.info("vmxml os is %s after update" % vmxml.os.xmltreefile) else: @@ -196,9 +192,11 @@ def check_file_own(file_path, exp_uid, exp_gid): if extra_param.count("xml"): if not setup_nfs: aft_vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) - boots_list = aft_vmxml.os.boots - if "hd" in boots_list or "cdrom" not in boots_list: - test.fail("Update xml with restore failed") + for attr in os_update_dict: + got = getattr(aft_vmxml.os, attr, "") + expected = os_update_dict[attr] + if got != expected: + test.fail("Update xml with restore failed") else: if vm_ref_uid and vm_ref_gid: check_file_own(vm_ref, vm_ref_uid, vm_ref_gid) diff --git a/libvirt/tests/src/virsh_cmd/domain/virsh_save.py b/libvirt/tests/src/virsh_cmd/domain/virsh_save.py index d8d50cc5521..071a865a652 100644 --- a/libvirt/tests/src/virsh_cmd/domain/virsh_save.py +++ b/libvirt/tests/src/virsh_cmd/domain/virsh_save.py @@ -131,7 +131,7 @@ def create_alter_xml(vm_name): else: if status: test.fail("virsh run failed with a " - "correct command") + "correct command: %s" % err_msg) if progress and not err_msg.count("Save:"): test.fail("No progress information outputted!") if "--xml" in options and 'test.img' not in xml_after_save: diff --git a/libvirt/tests/src/virsh_cmd/domain/virsh_save_image_define.py b/libvirt/tests/src/virsh_cmd/domain/virsh_save_image_define.py index 3148cdbe842..d6aa6d36e59 100644 --- a/libvirt/tests/src/virsh_cmd/domain/virsh_save_image_define.py +++ b/libvirt/tests/src/virsh_cmd/domain/virsh_save_image_define.py @@ -52,14 +52,18 @@ def redefine_new_xml(): debug=True) libvirt.check_exit_status(cmd_result) - def vm_state_check(): + def vm_state_check(xml_after): + """ + Checks the VM state + + :param xml_after: expected xml substring + """ cmd_result = virsh.dumpxml(vm_name, debug=True) libvirt.check_exit_status(cmd_result) # The xml should contain the match_string xml = cmd_result.stdout.strip() - match_string = "" - if not re.search(match_string, xml): + if not re.search(xml_after, xml): raise exceptions.TestFail("After domain restore, " "the xml is not expected") @@ -74,6 +78,9 @@ def vm_state_check(): restore_state = params.get("restore_state", "running") vm_save = params.get("vm_save", "vm.save") + xml_before = params.get("xml_before") + xml_after = params.get("xml_after") + try: # Get a tmp_dir. tmp_dir = data_dir.get_tmp_dir() @@ -87,8 +94,7 @@ def vm_state_check(): xml = get_image_xml() - # Replace to - newxml = xml.replace("", "") + newxml = xml.replace(xml_before, xml_after) logging.debug("After string replacement, the new xml is %s", newxml) # Write new xml into a tempfile @@ -108,7 +114,7 @@ def vm_state_check(): libvirt.check_exit_status(cmd_result) os.remove(vm_save) - vm_state_check() + vm_state_check(xml_after) finally: # cleanup diff --git a/libvirt/tests/src/virsh_cmd/domain/virsh_save_image_edit.py b/libvirt/tests/src/virsh_cmd/domain/virsh_save_image_edit.py index becdb2911bc..2c835fda187 100644 --- a/libvirt/tests/src/virsh_cmd/domain/virsh_save_image_edit.py +++ b/libvirt/tests/src/virsh_cmd/domain/virsh_save_image_edit.py @@ -25,8 +25,9 @@ def run(test, params, env): 5) Check the new xml of the VM and its state """ - def edit_image_xml(): - edit_cmd = r":%s //" + def edit_image_xml(xml_before, xml_after): + edit_cmd = r":%s /" + xml_before.replace("/", "\/") + edit_cmd += "/" + xml_after.replace("/", "\/") if restore_state == "running": option = "--running" @@ -44,7 +45,7 @@ def edit_image_xml(): session.sendline("virsh save-image-edit %s %s " % (vm_save, option)) - logging.info("Replace '' to ''") + logging.info(f"Replace {xml_before} to {xml_after}") session.sendline(edit_cmd) session.send('\x1b') session.send('ZZ') @@ -64,8 +65,7 @@ def vm_state_check(): # The xml should contain the match_string xml = cmd_result.stdout.strip() - match_string = "" - if not re.search(match_string, xml): + if not re.search(xml_after, xml): test.fail("After domain restore the xml is not expected") domstate = virsh.domstate(vm_name, debug=True).stdout.strip() @@ -83,6 +83,9 @@ def vm_state_check(): vm_backup = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + xml_before = params.get("xml_before") + xml_after = params.get("xml_after") + try: # Get a tmp_dir. tmp_dir = data_dir.get_tmp_dir() @@ -95,7 +98,7 @@ def vm_state_check(): test.fail("Failed to save running domain %s" % vm_name) # Edit the xml in the saved state file - edit_image_xml() + edit_image_xml(xml_before, xml_after) # Restore domain cmd_result = virsh.restore(vm_save, debug=True) diff --git a/libvirt/tests/src/virsh_cmd/domain/virsh_set_user_password.py b/libvirt/tests/src/virsh_cmd/domain/virsh_set_user_password.py index 13d4737c443..96921ec4944 100644 --- a/libvirt/tests/src/virsh_cmd/domain/virsh_set_user_password.py +++ b/libvirt/tests/src/virsh_cmd/domain/virsh_set_user_password.py @@ -2,7 +2,6 @@ from avocado.utils import process -from virttest import utils_net from virttest import remote from virttest import virsh from virttest.utils_test import libvirt @@ -60,8 +59,7 @@ def run(test, params, env): else: # Get guest ip address session = vm.wait_for_login(timeout=30, username="root", password=ori_passwd) - vm_mac = vm.get_virsh_mac_address() - vm_ip = utils_net.get_guest_ip_addr(session, vm_mac) + vm_ip = vm.wait_for_get_address(nic_index=0, timeout=120) # Add user if add_user: @@ -74,49 +72,33 @@ def run(test, params, env): # Set the user password in vm if encrypted: - openssl_version = process.run("openssl version", - ignore_status=False) - if "OpenSSL 3.0." in openssl_version.stdout_text: - cmd = "openssl passwd %s" % new_passwd - else: - cmd = "openssl passwd -crypt %s" % new_passwd + cmd = "openssl passwd %s" % new_passwd ret = process.run(cmd, shell=True) libvirt.check_exit_status(ret) en_passwd = str(ret.stdout_text.strip()) - passwd = en_passwd + passwd = en_passwd.replace('$', r'\$') ret = virsh.set_user_password(vm_name, set_user_name, passwd, encrypted=encrypted, option=option, debug=True) libvirt.check_exit_status(ret) # Login with new password + logging.debug("Trying to log in with new password") try: session = remote.wait_for_login("ssh", vm_ip, "22", set_user_name, new_passwd, r"[\#\$]\s*$", timeout=30) session.close() except remote.LoginAuthenticationError as e: logging.debug(e) + test.fail("Failed to login with new password") - # Login with old password - try: - session = remote.wait_for_login("ssh", vm_ip, "22", set_user_name, ori_passwd, - r"[\#\$]\s*$", timeout=10) - session.close() - except remote.LoginAuthenticationError: - logging.debug("Login with old password failed as expected.") - - # Change the password back in VM - ret = virsh.set_user_password(vm_name, set_user_name, ori_passwd, False, - option=option, debug=True) - libvirt.check_exit_status(ret) - - # Login with the original password - try: - session = remote.wait_for_login("ssh", vm_ip, "22", set_user_name, ori_passwd, - r"[\#\$]\s*$", timeout=30) - session.close() - except remote.LoginAuthenticationError as e: - logging.debug(e) + finally: + # Recover VM + if vm.is_alive(): + # always restore root password in case previously case execution is broken + if status_error != "yes": + virsh.set_user_password(vm_name, set_user_name, ori_passwd, False, + option=option, debug=True) if start_ga: # Stop guest agent in vm @@ -131,8 +113,5 @@ def run(test, params, env): test.error("Deleting user '%s' got failed: '%s'" % (set_user_name, output)) session.close() - finally: - vmxml_bak.sync() - # Recover VM - if vm.is_alive(): vm.destroy(gracefully=False) + vmxml_bak.sync() diff --git a/libvirt/tests/src/virsh_cmd/domain/virsh_shutdown.py b/libvirt/tests/src/virsh_cmd/domain/virsh_shutdown.py index ed22ad5fe96..2af22c12f38 100644 --- a/libvirt/tests/src/virsh_cmd/domain/virsh_shutdown.py +++ b/libvirt/tests/src/virsh_cmd/domain/virsh_shutdown.py @@ -111,7 +111,7 @@ def run(test, params, env): session.cmd_output('LANG=C') command = ("virsh -c %s shutdown %s %s" % (remote_uri, vm_name, mode)) - status = session.cmd_status(command, internal_timeout=5) + status = session.cmd_status(command, internal_timeout=10) session.close() except process.CmdError: status = 1 diff --git a/libvirt/tests/src/virsh_cmd/domain/virsh_sosreport.py b/libvirt/tests/src/virsh_cmd/domain/virsh_sosreport.py new file mode 100644 index 00000000000..7bf2e297d97 --- /dev/null +++ b/libvirt/tests/src/virsh_cmd/domain/virsh_sosreport.py @@ -0,0 +1,138 @@ +import logging +import os +import shutil +import subprocess + +from pathlib import Path + + +def run(test, params, env): + + generate_sos_report = params.get("generate_sos_report", "no") == "yes" + access_pool_stats = params.get("access_pool_stats", "no") == "yes" + + # Configuration + LOG_PATTERNS = [ + r"nfsd.*NULL pointer dereference", + r"kernel: BUG:.*nfsd", + r"kernel: WARNING:.*nfsd", + r"pool_stats.*crash", + r"kernel: general protection fault.*nfsd" + ] + proc_file = "/proc/fs/nfsd/pool_stats" + log_sources = ["/var/log/kern.log", "/var/log/syslog", + "journalctl -k --since='1 hour ago'"] + + def check_user_status(): + + # check if user has permissions to run the command + logging.debug("Check for the user privileges") + if os.geteuid() != 0: + test.fail("'sosreport' must be run with root privileges") + + def scan_logs(): + + issues = [] + for source in log_sources: + try: + if source.startswith("journalctl"): + logs = subprocess.check_output(source.split(), universal_newlines=True) + else: + with open(source, 'r') as f: + logs = f.read() + + for pattern in LOG_PATTERNS: + if re.search(pattern, logs, re.IGNORECASE): + issues.append(f"Found in {source}: {pattern}") + + except Exception as e: + continue + return issues + + if generate_sos_report: + # check if the command available + logging.debug("Check if 'sosreport' is installed") + if not shutil.which('sosreport'): + test.fail("sosreport command not found. \ + Is the sos package installed?") + + check_user_status() + + report_path = None + + try: + # Run command in non-interactive mode + logging.debug("Starting sosreport collection...") + result = subprocess.run( + ['sosreport', '--batch'], + capture_output=True, + universal_newlines=True, check=True) + + # Parse output for getting the report path + for line in result.stdout.split('\n'): + if 'tar.xz' in line: + report_path = line.split()[-1] + break + + logging.debug("* * * REPORT GENERATED * * *") + + except Exception as err: + test.fail(err) + + # check for any trace messages after report generation + dmesg = subprocess.run(['dmesg'], + capture_output=True, + universal_newlines=True, check=True) + + log_issues = scan_logs() + if log_issues: + logging.debug("Found potential crash indicators in logs") + for issue in log_issues: + logging.debug(" - %s" % issue) + test.fail("potential crash indicators found in logs") + else: + logging.debug("Your sos report file has been generated" + "and saved in : %s" % report_path) + + if access_pool_stats: + + check_user_status() + + # Check for the file existence + try: + lsmod = subprocess.check_output(["lsmod"], universal_newlines=True) + if "nfsd" not in lsmod: + test.fail("nfsd module not loaded") + + proc_mount = Path(proc_file) + if not proc_mount.exists(): + test.fail("%s file not present" % proc_file) + + logging.debug("NFSD appears healthy") + + except Exception as e: + logging.debug(str(e)) + + # check for crash indicators before accessing the file + log_issues = scan_logs() + if log_issues: + logging.debug("Found potential crash indicators in logs") + for issue in log_issues: + logging.debug(" - %s" % issue) + + # Attempt to safely read the target file + try: + with open(proc_file, 'r') as f: + f.read(500) + logging.debug("File read successfully") + except Exception as e: + test.fail("File access failed: %s" % str(e)) + + # check for crash indicators after accessing the file + log_issues = scan_logs() + if log_issues: + logging.debug("Found potential crash indicators in logs") + for issue in log_issues: + logging.debug(" - %s" % issue) + + test.fail("potential crash indicators found in logs") diff --git a/libvirt/tests/src/virsh_cmd/domain/virsh_start.py b/libvirt/tests/src/virsh_cmd/domain/virsh_start.py index 5881d525663..dc582bcf0af 100644 --- a/libvirt/tests/src/virsh_cmd/domain/virsh_start.py +++ b/libvirt/tests/src/virsh_cmd/domain/virsh_start.py @@ -1,3 +1,4 @@ +import os import logging as log from avocado.utils import process @@ -9,6 +10,7 @@ from virttest import utils_libvirtd from virttest import ssh_key from virttest import libvirt_version +from virttest.utils_test import libvirt # Using as lower capital is not the best way to do, but this is just a @@ -30,6 +32,38 @@ def check_audit_log(test, audit_log_search_string, start_date, start_time): "in'{cmd_result.stdout_text}'") +def check_message_log(test, params): + """ + Check message in /var/log/messages file + + :param test: Test object for utility functions + :param params: one dictionary wrapping parameters + """ + str_to_grep = params.get("libvirtd_error_message") + message_log_file = params.get("message_log_file") + if not libvirt.check_logfile(str_to_grep, message_log_file, str_in_log=False): + test.fail('Get unexpected error message:%s in log file:%s' % (str_to_grep, message_log_file)) + + +def check_auvirt_log(test, params): + """ + Check message in output of virtualization audit + + :param test: Test object for utility functions + :param params: one dictionary wrapping parameters + """ + vm_name = params.get("main_vm", "avocado-vt-vm1") + str_to_grep = params.get("auvirt_error_msg") % vm_name + auvirt_log_file = params.get("tmp_auvirt_event_log") + if os.path.exists(auvirt_log_file): + cmd = f"truncate -s 0 {auvirt_log_file}" + process.run(cmd, ignore_status=True, shell=True, verbose=True) + generate_virt_log_cmd = "auvirt --start recent --all-events|tee %s" % auvirt_log_file + process.run(generate_virt_log_cmd, ignore_status=False, shell=True, verbose=True) + if not libvirt.check_logfile(str_to_grep, auvirt_log_file, str_in_log=False): + test.fail('Get unexpected audit error message:%s in log file:%s' % (str_to_grep, auvirt_log_file)) + + def run(test, params, env): """ Test command: virsh start. @@ -140,6 +174,8 @@ def run(test, params, env): if audit_log_search_string: if not service_mgr.status("auditd"): service_mgr.start("auditd") + truncate_2m_cmd = "truncate -s 0 /var/log/messages" + process.run(truncate_2m_cmd, ignore_status=True, shell=True, verbose=True) cmd_result = virsh.start(vm_ref, options=opt) if cmd_result.exit_status: if status_error == "no": @@ -174,7 +210,9 @@ def run(test, params, env): "but it is restored from a" " managedsave.") elif audit_log_search_string: + check_message_log(test, params) check_audit_log(test, audit_log_search_string, start_date, start_time) + check_auvirt_log(test, params) else: if status_error == "no" and not vm.is_alive() and pre_operation != "remote": test.fail("VM was started but it is not alive.") diff --git a/libvirt/tests/src/virsh_cmd/host/virsh_capabilities.py b/libvirt/tests/src/virsh_cmd/host/virsh_capabilities.py index 4486c85601d..cc959291420 100644 --- a/libvirt/tests/src/virsh_cmd/host/virsh_capabilities.py +++ b/libvirt/tests/src/virsh_cmd/host/virsh_capabilities.py @@ -4,119 +4,201 @@ from avocado.utils import path from avocado.utils import process +from avocado.utils import cpu from virttest import libvirt_vm from virttest import virsh from virttest.libvirt_xml import capability_xml - # Using as lower capital is not the best way to do, but this is just a # workaround to avoid changing the entire file. logging = log.getLogger('avocado.' + __name__) -def run(test, params, env): +def check_host_arch(cap_xml, test): """ - Test the command virsh capabilities + Check host arch information in virsh capabilities output - (1) Call virsh capabilities - (2) Call virsh capabilities with an unexpected option - (3) Call virsh capabilities with libvirtd service stop + :param cap_xml: CapabilityXML instance + :param test: test object + """ + xml_arch = cap_xml.arch + logging.debug("Host arch (capabilities_xml): %s", xml_arch) + exp_arch = platform.machine() + if xml_arch != exp_arch: + test.fail("The host arch in capabilities_xml is " + "expected to be %s, but get %s" % + (exp_arch, xml_arch)) + + +def check_host_cpu_count(cap_xml, test): + """ + Check host cpu number in virsh capabilities output + + :param cap_xml: CapabilityXML instance + :param test: test object + """ + xml_cpu_count = cap_xml.cpu_count + logging.debug("Host cpus count (capabilities_xml): %s", xml_cpu_count) + exp_cpu_count = cpu.online_count() + if xml_cpu_count != exp_cpu_count: + test.fail("Host cpus count is expected to be %s, " + "but get %s" % + (exp_cpu_count, xml_cpu_count)) + + +def check_host_cpu_topology(cap_xml, test): + """ + Check host cpu topology information in virsh capabilities output + + :param cap_xml: CapabilityXML instance + :param test: test object + """ + def _compare_value(cmd, value_in_capxml, key_in_cpu): + """ + Compare a pair of cpu key and value in capabilities to sysfs + + :param cmd: str, command to execute + :param value_in_capxml: str, key value in + :param key_in_cpu: str, key name in + """ + sys_value = process.run(cmd, shell=True).stdout_text.strip() + if sys_value != value_in_capxml: + test.fail("Expect '%s' to be '%s', " + "but found '%s'" % (key_in_cpu, + sys_value, + value_in_capxml)) + + cell_list = cap_xml.cells_topology.cell + current_arch = platform.machine() + is_x8664 = True if current_arch == "x86_64" else False + is_aarch64 = True if current_arch == "aarch64" else False + is_s390x = True if current_arch == "s390x" else False + prefix_cmd = "cat /sys/devices/system/cpu/cpu%s/topology/%s" + file_name_key_mapping = {"physical_package_id": "socket_id", + "cluster_id": "cluster_id", + "core_id": "core_id", + "thread_siblings_list": "siblings"} + if is_x8664: + file_name_key_mapping.update({"die_id": "die_id"}) + if is_aarch64 or is_x8664: + file_name_key_mapping.update({"cluster_id": "cluster_id"}) + if is_s390x: + del file_name_key_mapping["cluster_id"] + for a_cell in cell_list: + cpu_list = a_cell.cpu + for a_cpu in cpu_list: + for file_name, key_in_cap in file_name_key_mapping.items(): + cmd = prefix_cmd % (a_cpu['id'], file_name) + _compare_value(cmd, a_cpu[key_in_cap], key_in_cap) + logging.debug("Verify cpu%s with sysfs - PASS", a_cpu['id']) + + +def check_arch_guest_support(cap_xml, test): + """ + Check arch guest support information in virsh capabilities output + + :param cap_xml: CapabilityXML instance + :param test: test object """ - def compare_capabilities_xml(source): - cap_xml = capability_xml.CapabilityXML() - cap_xml.xml = source - - # Check that host has a non-empty UUID tag. - xml_uuid = cap_xml.uuid - logging.debug("Host UUID (capabilities_xml): %s", xml_uuid) - if xml_uuid == "": - test.fail("The host uuid in capabilities_xml is none!") - - # Check the host arch. - xml_arch = cap_xml.arch - logging.debug("Host arch (capabilities_xml): %s", xml_arch) - exp_arch = process.run("arch", shell=True).stdout_text.strip() - if xml_arch != exp_arch: - test.fail("The host arch in capabilities_xml is " - "expected to be %s, but get %s" % - (exp_arch, xml_arch)) - - # Check the host cpu count. - xml_cpu_count = cap_xml.cpu_count - logging.debug("Host cpus count (capabilities_xml): %s", xml_cpu_count) - search_str = 'processor' - if platform.machine() == 's390x': - search_str = 'cpu number' - cmd = "grep '%s' /proc/cpuinfo | wc -l" % search_str - exp_cpu_count = int(process.run(cmd, shell=True).stdout_text.strip()) - if xml_cpu_count != exp_cpu_count: - test.fail("Host cpus count is expected to be %s, " - "but get %s" % - (exp_cpu_count, xml_cpu_count)) - - # Check the arch of guest supported. - guest_capa = cap_xml.get_guest_capabilities() - logging.debug(guest_capa) - - # libvirt track wordsize in hardcode struct virArchData - wordsize = {} - wordsize['64'] = ['alpha', 'aarch64', 'ia64', 'mips64', 'mips64el', - 'parisc64', 'ppc64', 'ppc64le', 's390x', 'sh4eb', - 'sparc64', 'x86_64'] - wordsize['32'] = ['armv6l', 'armv7l', 'armv7b', 'cris', 'i686', 'lm32', - 'm68k', 'microblaze', 'microblazeel', 'mips', - 'mipsel', 'openrisc', 'parisc', 'ppc', 'ppcle', - 'ppcemb', 's390', 'sh4', 'sparc', 'unicore32', - 'xtensa', 'xtensaeb'] - uri_type = process.run( - "virsh uri", shell=True).stdout_text.split(':')[0] - domain_type = "domain_" + uri_type - for arch_dict in list(itervalues(guest_capa)): - for arch, val_dict in list(iteritems(arch_dict)): - # Check wordsize - if arch not in wordsize[val_dict['wordsize']]: - test.fail("'%s' wordsize '%s' in " - "capabilities_xml not expected" % - (arch, val_dict['wordsize'])) - # Check the type of hypervisor - if domain_type not in list(val_dict.keys()): - if (arch == "ppc64" or arch == "ppc64le"): - tcg_check = process.run("qemu-system-ppc64 --accel help", - shell=True).stdout_text.split('\n') - if "tcg" not in tcg_check: - logging.info("expected to fail as tcg is disabled") - else: - test.fail("domain type '%s' is not matched" - " under arch '%s' in " - "capabilities_xml" % - (uri_type, arch)) + guest_capa = cap_xml.get_guest_capabilities() + logging.debug(guest_capa) + + # libvirt track wordsize in hardcode struct virArchData + wordsize = {} + wordsize['64'] = ['alpha', 'aarch64', 'ia64', 'mips64', 'mips64el', + 'parisc64', 'ppc64', 'ppc64le', 's390x', 'sh4eb', + 'sparc64', 'x86_64'] + wordsize['32'] = ['armv6l', 'armv7l', 'armv7b', 'cris', 'i686', 'lm32', + 'm68k', 'microblaze', 'microblazeel', 'mips', + 'mipsel', 'openrisc', 'parisc', 'ppc', 'ppcle', + 'ppcemb', 's390', 'sh4', 'sparc', 'unicore32', + 'xtensa', 'xtensaeb'] + uri_type = virsh.command('uri').stdout_text.split(':')[0] + domain_type = "domain_" + uri_type + for arch_dict in list(itervalues(guest_capa)): + for arch, val_dict in list(iteritems(arch_dict)): + # Check wordsize + if arch not in wordsize[val_dict['wordsize']]: + test.fail("'%s' wordsize '%s' in " + "capabilities_xml not expected" % + (arch, val_dict['wordsize'])) + # Check the type of hypervisor + if domain_type not in list(val_dict.keys()): + if (arch == "ppc64" or arch == "ppc64le"): + tcg_check = process.run("qemu-system-ppc64 --accel help", + shell=True).stdout_text.split('\n') + if "tcg" not in tcg_check: + logging.info("expected to fail as tcg is disabled") else: test.fail("domain type '%s' is not matched" " under arch '%s' in " "capabilities_xml" % (uri_type, arch)) + else: + test.fail("domain type '%s' is not matched" + " under arch '%s' in " + "capabilities_xml" % + (uri_type, arch)) + + +def check_power_management_suuport(cap_xml, test): + """ + Check power management support in virsh capabilities output - # check power management support. - try: - pm_cmd = path.find_command('pm-is-supported') - pm_cap_map = {'suspend': 'suspend_mem', - 'hibernate': 'suspend_disk', - 'suspend-hybrid': 'suspend_hybrid'} - exp_pms = [] - for opt in pm_cap_map: - cmd = '%s --%s' % (pm_cmd, opt) - res = process.run(cmd, ignore_status=True, shell=True) - if res.exit_status == 0: - exp_pms.append(pm_cap_map[opt]) - pms = cap_xml.power_management_list - if set(exp_pms) != set(pms): - test.fail("Expected supported PMs are %s, got %s " - "instead." % (exp_pms, pms)) - except path.CmdNotFoundError: - logging.debug('Power management checking is skipped, since command' - ' pm-is-supported is not found.') + :param cap_xml: CapabilityXML instance + :param test: test object + """ + try: + pm_cmd = path.find_command('pm-is-supported') + pm_cap_map = {'suspend': 'suspend_mem', + 'hibernate': 'suspend_disk', + 'suspend-hybrid': 'suspend_hybrid'} + exp_pms = [] + for opt in pm_cap_map: + cmd = '%s --%s' % (pm_cmd, opt) + res = process.run(cmd, ignore_status=True, shell=True) + if res.exit_status == 0: + exp_pms.append(pm_cap_map[opt]) + pms = cap_xml.power_management_list + if set(exp_pms) != set(pms): + test.fail("Expected supported PMs are %s, got %s " + "instead." % (exp_pms, pms)) + except path.CmdNotFoundError: + logging.debug('Power management checking is skipped, since command' + ' pm-is-supported is not found.') + + +def compare_capabilities_xml(source, test): + """ + Check virsh capabilities output + + :param source: CapabilityXML instance + :param test: test object + """ + cap_xml = capability_xml.CapabilityXML() + cap_xml.xml = source + # Check that host has a non-empty UUID tag. + xml_uuid = cap_xml.uuid + logging.debug("Host UUID (capabilities_xml): %s", xml_uuid) + if xml_uuid == "": + test.fail("The host uuid in capabilities_xml is none!") + + check_host_arch(cap_xml, test) + check_host_cpu_count(cap_xml, test) + check_host_cpu_topology(cap_xml, test) + check_arch_guest_support(cap_xml, test) + check_power_management_suuport(cap_xml, test) + + +def run(test, params, env): + """ + Test the command virsh capabilities + + (1) Call virsh capabilities + (2) Call virsh capabilities with an unexpected option + """ connect_uri = libvirt_vm.normalize_connect_uri(params.get("connect_uri", "default")) # Run test case @@ -136,7 +218,7 @@ def compare_capabilities_xml(source): test.fail("Command virsh capabilities %s succeeded (incorrect \ command)" % option) elif status_error == "no": - compare_capabilities_xml(output) + compare_capabilities_xml(output, test) if status != 0: test.fail("Command 'virsh capabilities %s' failed " "(correct command)" % option) diff --git a/libvirt/tests/src/virsh_cmd/host/virsh_cpu_models.py b/libvirt/tests/src/virsh_cmd/host/virsh_cpu_models.py index f76cea0c86c..d89244433bc 100644 --- a/libvirt/tests/src/virsh_cmd/host/virsh_cpu_models.py +++ b/libvirt/tests/src/virsh_cmd/host/virsh_cpu_models.py @@ -1,6 +1,8 @@ import logging as log from six import itervalues +from avocado.utils import process + from virttest import ssh_key from virttest import virsh from virttest import libvirt_vm @@ -13,6 +15,31 @@ logging = log.getLogger('avocado.' + __name__) +def compare_cpu_model_with_qemu(test, params, virsh_cpu_model_result, qemu_cmd): + """ + Compare the libvirt cpu model same with the model in qemu-kvm. + + :params: test: test object + :params: params, cfg parameter dict. + :params: virsh_cpu_model_result:virsh cpu-model result + :params: qemu_cmd: qemu cmd to get cpu model name. + """ + arch_option = params.get("arch_option") + if arch_option == "arch_x86": + skip_list = eval(params.get("skip_list", [])) + qemu_models = process.run(qemu_cmd, ignore_status=False, shell=True).stdout_text.strip().split("\n") + virsh_cpu_model_result = virsh_cpu_model_result.stdout_text.strip().split("\n") + + for qemu_model in qemu_models: + if qemu_model not in {*virsh_cpu_model_result, *skip_list}: + test.fail("Expected the model of qemu-kvm:%s in virsh cpu-model result" % qemu_model) + test.log.debug("All the cpu models of qemu-kvm are contained in virsh cpu-models.") + else: + msg = params.get("msg", "") + if msg not in virsh_cpu_model_result.stdout_text: + test.fail("Expected '%s' in virsh cpu-models result" % msg) + + def run(test, params, env): """ Test command virsh cpu-models @@ -23,6 +50,7 @@ def run(test, params, env): remote_ref = params.get("remote_ref", "") connect_uri = libvirt_vm.normalize_connect_uri(params.get("connect_uri", "default")) + qemu_cmd = params.get("check_qemu_cpu_supported_cmd", "") if remote_ref == "remote": remote_ip = params.get("remote_ip", "REMOTE.EXAMPLE.COM") @@ -54,3 +82,4 @@ def run(test, params, env): result = virsh.cpu_models(arch, options=option, uri=connect_uri, ignore_status=True, debug=True) utlv.check_exit_status(result, expect_error=status_error) + compare_cpu_model_with_qemu(test, params, result, qemu_cmd) diff --git a/libvirt/tests/src/virsh_cmd/host/virsh_freepages.py b/libvirt/tests/src/virsh_cmd/host/virsh_freepages.py index 5ca259087bc..15106debc50 100644 --- a/libvirt/tests/src/virsh_cmd/host/virsh_freepages.py +++ b/libvirt/tests/src/virsh_cmd/host/virsh_freepages.py @@ -1,10 +1,11 @@ import logging as log import time +from avocado.utils import memory as avocado_mem + from virttest import virsh from virttest import test_setup from virttest import utils_misc -from virttest.libvirt_xml import vm_xml from virttest.utils_test import libvirt as utlv @@ -78,14 +79,19 @@ def check_freepages(output, expect_result_list): return False not in check_result -def modify_expect(cell, expect, pagesize='4KiB'): +def modify_expect(cell, expect): """ - For 4KiB freepages checking, if the gap between freepages command return - with system current freememory is less than 4*1024Kib, check would pass. + For default page size freepages checking, if the gap between freepages command return + with system current freememory is less than 'default page size' * 1024Kib, check would pass. + + :params cell: free pages dict of single node + :params expect: expected free page dict """ - if pagesize in expect.keys(): - if abs(int(float(expect[pagesize])) - int(float(cell[pagesize]))) < 1024: - expect[pagesize] = cell[pagesize] + default_pagesize = int(avocado_mem.get_page_size() / 1024) + pagesize_key = f'{default_pagesize}KiB' + if pagesize_key in expect.keys(): + if abs(int(float(expect[pagesize_key])) - int(float(cell[pagesize_key]))) < 1024: + expect[pagesize_key] = cell[pagesize_key] def run(test, params, env): @@ -99,20 +105,19 @@ def get_freepages_number_of_node(node, pagesize): :params node: node No :params pagesize: page size, for example: '4', '2048', '1048576' - For pagesize is '4' which is not hugepage, get free memory from + For pagesize is default page size which is not hugepage, get free memory from `grep MemFree /sys/devices/system/node/node${node}/meminfo` For pagesize '2048' or '1048576', get free page number from /sys/devices/system/node/nodei${node}/hugepages/ hugepages-${pagesize}/free_hugepages :return: integer number of free pagesize """ - if pagesize == '4': + if pagesize == default_pagesize: node_meminfo = host_numa_node.read_from_node_meminfo(node, 'MemFree') - return int(node_meminfo) / 4 - else: - return hp_cl.get_node_num_huge_pages(node, pagesize, type='free') + return int(node_meminfo) / int(default_pagesize) + return hp_cl.get_node_num_huge_pages(node, pagesize, type='free') - def check_hugepages_allocated_status(is_type_check, pagesize, quantity): + def check_hugepages_allocated_status(pagesize, quantity): """ Allocate some specific hugepages and check whether the number of this specific hugepages allocated by kernel totally is equal to the sum that @@ -120,14 +125,11 @@ def check_hugepages_allocated_status(is_type_check, pagesize, quantity): for each node is equal to the number allocated by kernel for each node. If yes, return True, else return False. - :params is_type_check: Flag to determine do this check or not :params pagesize: pagesize type needed to check :params quantity: the number will be allocated :return: True if current system support this pagesize and allocate page successfully, otherwise return False """ - if not is_type_check or pagesize not in supported_hp_size: - return False hp_cl.set_kernel_hugepages(pagesize, quantity) # kernel need some time to prepare hugepages due to maybe there # are some memory fragmentation. @@ -163,10 +165,19 @@ def check_hugepages_allocated_status(is_type_check, pagesize, quantity): "equal to kernel allocated totally." % pagesize) return True + def cleanup(): + """ + Clean up all supported huge page size allocation + """ + for hp_size in hp_cl.get_multi_supported_hugepage_size(): + hp_cl.set_kernel_hugepages(hp_size, 0) + option = params.get("freepages_option", "") status_error = "yes" == params.get("status_error", "no") cellno = params.get("freepages_cellno") pagesize = params.get("freepages_pagesize") + pagesize_kb = params.get("pagesize_kb") + hugepage_allocation_dict = eval(params.get("hugepage_allocation_dict", "{}")) host_numa_node = utils_misc.NumaInfo() node_list = host_numa_node.get_online_nodes_withmem() @@ -175,6 +186,8 @@ def check_hugepages_allocated_status(is_type_check, pagesize, quantity): hp_cl = test_setup.HugePageConfig(params) supported_hp_size = hp_cl.get_multi_supported_hugepage_size() + default_pagesize = str(int(avocado_mem.get_page_size() / 1024)) + cellno_list = [] if cellno == "EACH": cellno_list = node_list @@ -183,35 +196,23 @@ def check_hugepages_allocated_status(is_type_check, pagesize, quantity): else: cellno_list.append(cellno) - # Add 4K pagesize - supported_hp_size.insert(0, '4') - pagesize_list = [] + # Add default pagesize + supported_hp_size.insert(0, str(int(avocado_mem.get_page_size() / 1024))) + pagesize_list, pagesize_kb_list = [], [] if pagesize == "EACH": - pagesize_list = supported_hp_size + pagesize_list = pagesize_kb_list = supported_hp_size else: pagesize_list.append(pagesize) + pagesize_kb_list.append(pagesize_kb) if not status_error: - # Get if CPU support 2M-hugepages - check_2M = vm_xml.VMCPUXML.check_feature_name('pse') - # Get if CPU support 1G-hugepages - check_1G = vm_xml.VMCPUXML.check_feature_name('pdpe1gb') - if not check_2M and not check_1G: - test.cancel("pse and pdpe1gb flags are not supported by CPU.") - - num_1G = str(1024*1024) - num_2M = str(2048) - - # Let kernel allocate 64 of 2M hugepages at runtime - quantity_2M = 64 - # Let kernel allocate 2 of 1G hugepages at runtime - quantity_1G = 2 - check_2M = check_hugepages_allocated_status(check_2M, num_2M, quantity_2M) - check_1G = check_hugepages_allocated_status(check_1G, num_1G, quantity_1G) - - if not check_2M and not check_1G: - test.cancel("Not enough free memory to support huge pages " - "in current system.") + for page_size in pagesize_kb_list: + if page_size is None or page_size == default_pagesize: + continue + if page_size not in supported_hp_size: + test.cancel("Required hugepage size %sKiB is not supported on this host." % page_size) + if not check_hugepages_allocated_status(page_size, hugepage_allocation_dict[page_size]): + test.cancel("Not enough %sKiB hugepage size allocated in current system." % page_size) # Run test for cell in cellno_list: @@ -221,11 +222,8 @@ def check_hugepages_allocated_status(is_type_check, pagesize, quantity): options=option, debug=True) # Unify pagesize unit to KiB - if page is not None: - if page.upper() in ['2M', '2048K', '2048KIB']: - page = num_2M - elif page.upper() in ['1G', '1048576K', '1048576KIB']: - page = num_1G + if page is not None and pagesize_kb is not None: + page = pagesize_kb # the node without memory will fail and it is expected if cell is not None and page is None and not status_error: status_error = True @@ -265,3 +263,6 @@ def check_hugepages_allocated_status(is_type_check, pagesize, quantity): else: test.fail("Huge page freepages check failed, " "expect result is %s" % expect_result_list) + + # clean up the huge page allocation + cleanup() diff --git a/libvirt/tests/src/virsh_cmd/host/virsh_hostname.py b/libvirt/tests/src/virsh_cmd/host/virsh_hostname.py index 74ba887aed2..e667b537b18 100644 --- a/libvirt/tests/src/virsh_cmd/host/virsh_hostname.py +++ b/libvirt/tests/src/virsh_cmd/host/virsh_hostname.py @@ -30,7 +30,7 @@ def run(test, params, env): remote_uri = params.get("remote_uri", None) if remote_uri and remote_ip.count("EXAMPLE"): - test.cancel("Pls configure rempte_ip first") + test.cancel("Pls configure remote_ip first") session = None if remote_uri: diff --git a/libvirt/tests/src/virsh_cmd/host/virsh_hypervisor_cpu_models.py b/libvirt/tests/src/virsh_cmd/host/virsh_hypervisor_cpu_models.py new file mode 100644 index 00000000000..03b75e49941 --- /dev/null +++ b/libvirt/tests/src/virsh_cmd/host/virsh_hypervisor_cpu_models.py @@ -0,0 +1,45 @@ +import logging as log + +from virttest import libvirt_version +from virttest import virsh +from virttest.utils_test import libvirt as utlv +from virttest.libvirt_xml.domcapability_xml import DomCapabilityXML + + +logging = log.getLogger("avocado." + __name__) + + +def compare_cpu_model_with_domcapabilities(test, params, result): + """ + Compare the available CPUs with those returned by domcapabilities. + + :param test: the test instance + :param params: the test parameters + :param result: the output from hypervisor-cpu-models + """ + xml = DomCapabilityXML() + hc_models = [x for x in result.stdout_text.split("\n") if x != ""] + if "--all" in params.get("options"): + xpath = "/cpu/mode/model" + else: + xpath = "/cpu/mode/model[@usable='yes']" + dc_models = [str(x.text) for x in xml.xmltreefile.findall(xpath)] + difference = set(dc_models) ^ set(hc_models) + if difference and difference != set(""): + test.fail(f"Model list should be identical. Difference: {difference}") + test.log.debug("All models were found in hypervisor-cpu-models") + + +def run(test, params, env): + """ + Test command virsh hypervisor-cpu-models + """ + options = params.get("options", "") + status_error = "yes" == params.get("status_error", "no") + + libvirt_version.is_libvirt_feature_supported(params) + + result = virsh.hypervisor_cpu_models(options, ignore_status=True, debug=True) + utlv.check_exit_status(result, expect_error=status_error) + if not status_error: + compare_cpu_model_with_domcapabilities(test, params, result) diff --git a/libvirt/tests/src/virsh_cmd/host/virsh_nodecpustats.py b/libvirt/tests/src/virsh_cmd/host/virsh_nodecpustats.py index 4efec85cc14..a035b471336 100755 --- a/libvirt/tests/src/virsh_cmd/host/virsh_nodecpustats.py +++ b/libvirt/tests/src/virsh_cmd/host/virsh_nodecpustats.py @@ -242,7 +242,7 @@ def test_disable_enable_cpu(test, host_cpus_list, params): libvirt.check_result(output, expected_fails=[err_msg]) logging.debug("Online host cpu %s" % host_cpus_list[-1]) - if cpuutil.online(host_cpus_list[-1]): + if not cpuutil.online(host_cpus_list[-1]): test.error("Failed to online host cpu %s" % host_cpus_list[-1]) subtest_cpu_percentage_option(test, host_cpus_list[-1], with_cpu_option=False) diff --git a/libvirt/tests/src/virsh_cmd/host/virsh_nodeinfo.py b/libvirt/tests/src/virsh_cmd/host/virsh_nodeinfo.py index eea3b346885..56a8421a586 100644 --- a/libvirt/tests/src/virsh_cmd/host/virsh_nodeinfo.py +++ b/libvirt/tests/src/virsh_cmd/host/virsh_nodeinfo.py @@ -106,11 +106,12 @@ def output_check(nodeinfo_output): # that it's within 20 percent of each value to give us enough of # a "fudge" factor to declare "close enough". Don't return a failure # just print a debug message and move on. - diffval = abs(int(cpu_frequency_nodeinfo) - int(cpu_frequency_os)) - if (float(diffval) / float(cpu_frequency_nodeinfo) > 0.20 or - float(diffval) / float(cpu_frequency_os) > 0.20): - logging.debug("Virsh nodeinfo output didn't match CPU " - "frequency within 20 percent") + if 'yes' == params.get('check_frequency', 'no'): + diffval = abs(int(cpu_frequency_nodeinfo) - int(cpu_frequency_os)) + if (float(diffval) / float(cpu_frequency_nodeinfo) > 0.20 or + float(diffval) / float(cpu_frequency_os) > 0.20): + logging.debug("Virsh nodeinfo output didn't match CPU " + "frequency within 20 percent") # Get CPU topology from virsh capabilities xml cpu_topology = capability_xml.CapabilityXML()['cpu_topology'] diff --git a/libvirt/tests/src/virsh_cmd/host/virsh_sysinfo.py b/libvirt/tests/src/virsh_cmd/host/virsh_sysinfo.py index 4f66dd1951f..1c621e77020 100644 --- a/libvirt/tests/src/virsh_cmd/host/virsh_sysinfo.py +++ b/libvirt/tests/src/virsh_cmd/host/virsh_sysinfo.py @@ -60,7 +60,7 @@ def run(test, params, env): dmidecode_version = get_processor_version() if dmidecode_version: # Get processor version from result - sysinfo_xml = libvirt_xml.SysinfoXML() + sysinfo_xml = libvirt_xml.VMSysinfoXML() sysinfo_xml['xml'] = output sysinfo_xml.xmltreefile.write() diff --git a/libvirt/tests/src/virsh_cmd/monitor/virsh_domstate.py b/libvirt/tests/src/virsh_cmd/monitor/virsh_domstate.py index f0b67ee5f00..e5d5a82e3f7 100644 --- a/libvirt/tests/src/virsh_cmd/monitor/virsh_domstate.py +++ b/libvirt/tests/src/virsh_cmd/monitor/virsh_domstate.py @@ -2,7 +2,6 @@ import os import shutil import logging as log -import platform import time import signal @@ -159,15 +158,13 @@ def run(test, params, env): vmxml.sync() if vm_action == "crash": + libvirt_version.is_libvirt_feature_supported(params) if vm.is_alive(): vm.destroy(gracefully=False) vmxml.on_crash = vm_oncrash_action if not vmxml.xmltreefile.find('devices').findall('panic'): # Add device to domain panic_dev = Panic() - if "ppc" not in platform.machine(): - panic_dev.addr_type = "isa" - panic_dev.addr_iobase = "0x505" vmxml.add_device(panic_dev) vmxml.sync() # Config auto_dump_path in qemu.conf @@ -204,7 +201,7 @@ def run(test, params, env): if kill_action == "stop_libvirtd": libvirtd.stop() time.sleep(1) - utils_misc.kill_process_by_pattern(vm_name) + process.run('pkill -9 qemu-kvm', ignore_status=True, shell=True) time.sleep(1) libvirtd.restart() elif kill_action == "reboot_vm": diff --git a/libvirt/tests/src/virsh_cmd/monitor/virsh_domstats.py b/libvirt/tests/src/virsh_cmd/monitor/virsh_domstats.py index ca6ded49bf5..7b00d904c78 100644 --- a/libvirt/tests/src/virsh_cmd/monitor/virsh_domstats.py +++ b/libvirt/tests/src/virsh_cmd/monitor/virsh_domstats.py @@ -6,13 +6,14 @@ from multiprocessing.pool import ThreadPool +from virttest import utils_disk from virttest import virsh from virttest.utils_test import libvirt from virttest.libvirt_xml import vm_xml from virttest.libvirt_xml.devices.panic import Panic from virttest import libvirt_version - +from avocado.utils import process # Using as lower capital is not the best way to do, but this is just a # workaround to avoid changing the entire file. @@ -86,7 +87,7 @@ def prepare_vm_state(vm, vm_state): logging.error("Unknown state for this test") -def check_output(output, vm, vm_state, options): +def check_output(output, vm, vm_state, options, params): """ Check virsh domstats output according to vm state and command options; For now, we only check given state domain can be find by list option. @@ -95,6 +96,7 @@ def check_output(output, vm, vm_state, options): :param vm: Libvirt VM instance :param vm_state: Domain state :param options: Virsh command options + :param params: Dictionary with the test parameters """ check_pass = [] list_option = "" @@ -105,6 +107,7 @@ def check_output(output, vm, vm_state, options): block_option_pass = False cpu_option = "" cpu_option_pass = False + vcpu_wait_sum_pass = False balloon_option = "" balloon_option_pass = False nowait_option = "" @@ -188,6 +191,12 @@ def check_output(output, vm, vm_state, options): if 'vcpu' in output: cpu_option_pass = True check_pass.append(cpu_option_pass) + if params.get("vcpu_wait_sum"): + wait_sum = re.findall(r"vcpu.\d+.wait=(\d+)", output) + for sum in wait_sum: + if sum != "0": + vcpu_wait_sum_pass = True + check_pass.append(vcpu_wait_sum_pass) if balloon_option == '--balloon': if 'balloon' in output: balloon_option_pass = True @@ -295,6 +304,8 @@ def run(test, params, env): iothread_add_ids = eval(params.get("iothread_add_ids", '[]')) iothread_del_ids = eval(params.get("iothread_del_ids", '[]')) status_error = (params.get("status_error", "no") == "yes") + params.update( + {"vcpu_wait_sum": vm_state == "running" and domstats_option == "--vcpu"}) if "--nowait" in domstats_option and not libvirt_version.version_compare(4, 5, 0): test.cancel("--nowait option is supported until libvirt 4.5.0 version...") @@ -328,6 +339,11 @@ def run(test, params, env): test.cancel("No 'panic' device in the guest, maybe " "your libvirt version doesn't support it.") prepare_vm_state(vm, vm_state) + if params.get("vcpu_wait_sum"): + session = vm.wait_for_login() + utils_disk.dd_data_to_vm_disk(session, "/tmp/file1") + session.close() + if enforce_command: domstats_option += " --enforce" if raw_print: @@ -339,6 +355,8 @@ def run(test, params, env): if "--iothread" in domstats_option: add_iothread(vm_list, iothread_add_ids) # Run virsh command + process.run("echo 1 > /proc/sys/kernel/sched_schedstats", shell=True) + logging.debug("enable sched_schedstats success") result = virsh.domstats(vm_list, domstats_option, ignore_status=True, debug=True) status = result.exit_status @@ -355,8 +373,9 @@ def run(test, params, env): test.fail("Run failed with right command") else: for vm in vms: - if not check_output(output, vm, vm_state, domstats_option): - test.fail("Check command output failed") + if not check_output(output, vm, vm_state, domstats_option, params): + test.fail("Check command output failed " + "due to %s option" % domstats_option) if "--iothread" in domstats_option: test_iothread(vm_list, iothread_add_ids, iothread_del_ids, output, test) diff --git a/libvirt/tests/src/virsh_cmd/network/virsh_net_dhcp_leases.py b/libvirt/tests/src/virsh_cmd/network/virsh_net_dhcp_leases.py index 108551377fd..5c57ebe47ef 100644 --- a/libvirt/tests/src/virsh_cmd/network/virsh_net_dhcp_leases.py +++ b/libvirt/tests/src/virsh_cmd/network/virsh_net_dhcp_leases.py @@ -1,19 +1,19 @@ +from datetime import datetime, timedelta import re import logging as log import signal +from avocado.utils import process + +from virttest import libvirt_version from virttest import utils_net from virttest import utils_misc from virttest import virsh -from virttest.libvirt_xml import vm_xml +from virttest.libvirt_xml import LibvirtXMLError from virttest.libvirt_xml import network_xml +from virttest.libvirt_xml import vm_xml from virttest.utils_test import libvirt as utlv -from avocado.utils import process -from datetime import datetime, timedelta -from virttest.libvirt_xml import LibvirtXMLError - -from virttest import libvirt_version - +from provider.virtual_network import network_base # Using as lower capital is not the best way to do, but this is just a # workaround to avoid changing the entire file. @@ -154,7 +154,7 @@ def f(): if ip_addr is None: iface_name = utils_net.get_linux_ifname(session, mac_addr) if try_dhclint: - session.cmd("dhclient %s" % iface_name) + session.cmd(f"dhcpcd {iface_name} || dhclient {iface_name}") ip_addr = utils_misc.wait_for(f, 10) else: # No IP for the interface, just print the interface name @@ -189,7 +189,8 @@ def check_net_lease(net_leases, expected_find=True): else: logging.debug("Not find '%s' in domain XML", net_mac) continue - iface_ip = get_ip_by_mac(net_mac) + session = vm.wait_for_login(login_nic_index, timeout=120, serial=True) + iface_ip = network_base.get_vm_ip(session, net_mac) if iface_ip and iface_ip != net_ip: test.fail("Address '%s' is not expected" % iface_ip) #check if lease time is correct diff --git a/libvirt/tests/src/virsh_cmd/network/virsh_net_update.py b/libvirt/tests/src/virsh_cmd/network/virsh_net_update.py index 6f2ab4ea62a..18e3d27c08d 100644 --- a/libvirt/tests/src/virsh_cmd/network/virsh_net_update.py +++ b/libvirt/tests/src/virsh_cmd/network/virsh_net_update.py @@ -13,6 +13,7 @@ from virttest.libvirt_xml import xcepts from virttest.libvirt_xml import vm_xml from avocado.utils import process +from provider.virtual_network import network_base # Using as lower capital is not the best way to do, but this is just a @@ -832,9 +833,7 @@ def section_update(ori_pre, new_pre): "then pkill dhclient; sleep 3; fi) " \ "&& dhclient -%s -lf /dev/stdout" % ip_version[-1] leases = session.cmd_output(dhclient_cmd) - iface_ip = utils_net.get_guest_ip_addr(session, mac, - ip_version=ip_version, - timeout=10) + iface_ip = network_base.get_vm_ip(session, mac, ip_ver=ip_version) if net_section == "ip-dhcp-range": if new_start_ip <= iface_ip <= new_end_ip: logging.info("getting ip %s is in range [%s ~ %s]", diff --git a/libvirt/tests/src/virsh_cmd/nodedev/crypto_nodedev_create_destroy.py b/libvirt/tests/src/virsh_cmd/nodedev/crypto_nodedev_create_destroy.py index a08cd1c6e2f..13a8707dd0e 100644 --- a/libvirt/tests/src/virsh_cmd/nodedev/crypto_nodedev_create_destroy.py +++ b/libvirt/tests/src/virsh_cmd/nodedev/crypto_nodedev_create_destroy.py @@ -4,7 +4,6 @@ from uuid import uuid1 -from avocado.utils import process from virttest import libvirt_version from virttest import virsh from virttest import utils_misc @@ -119,7 +118,7 @@ def check_device_attributes_are_dumped(test, dev_name, adapter, domain): :param domain: domain number in base 16 """ - process.run("udevadm settle") + time.sleep(10) nodedevice_xml = nodedev_xml.NodedevXML.new_from_dumpxml(dev_name) mdev_cap_xml = nodedevice_xml.get_cap() logging.debug("MdevXML: %s", mdev_cap_xml) diff --git a/libvirt/tests/src/virsh_cmd/nodedev/virsh_nodedev_dumpxml_chain.py b/libvirt/tests/src/virsh_cmd/nodedev/virsh_nodedev_dumpxml_chain.py index aa2716bd38d..9fd2d3a3ea3 100644 --- a/libvirt/tests/src/virsh_cmd/nodedev/virsh_nodedev_dumpxml_chain.py +++ b/libvirt/tests/src/virsh_cmd/nodedev/virsh_nodedev_dumpxml_chain.py @@ -3,6 +3,9 @@ from virttest import virsh from virttest.libvirt_xml.base import LibvirtXMLBase +from virttest.utils_zchannels import SubchannelPaths as paths + +from provider.vfio import ccw # Using as lower capital is not the best way to do, but this is just a @@ -16,28 +19,37 @@ def run(test, params, env): going up per parent. """ + device_ids = params.get("device_ids", "").split(",") + device = None chain_start_device_pattern = params.get("chain_start_device_pattern") checks = eval(params.get("checks")) - result = virsh.nodedev_list(ignore_status=False) - selected_device = get_device(result.stdout_text.strip().splitlines(), - chain_start_device_pattern) - if not selected_device: - test.error("No suitable device found for test." - "Pattern: %s. Available devices: %s." % - (chain_start_device_pattern, result.stdout)) - - xml = get_nodedev_dumpxml(selected_device) - validate_nodedev_xml(test, xml) - for check in checks: - for xpath, pattern in check.items(): - value = xml.xmltreefile.findtext(xpath) - value = value if value else "" - if not re.search(pattern, value): - test.fail("Unexpected value on xpath '%s':" - " '%s' does not match '%s'" % - (xpath, value, pattern)) - xml = get_nodedev_dumpxml(xml.xmltreefile.findtext("parent")) + try: + device = ccw.select_first_available_device(device_ids) + if device[paths.HEADER["Use"]] != "yes": + ccw.set_device_online(device[paths.HEADER["Device"]]) + result = virsh.nodedev_list(ignore_status=False) + selected_device = get_device(result.stdout_text.strip().splitlines(), + chain_start_device_pattern) + if not selected_device: + test.error("No suitable device found for test." + "Pattern: %s. Available devices: %s." % + (chain_start_device_pattern, result.stdout)) + + xml = get_nodedev_dumpxml(selected_device) validate_nodedev_xml(test, xml) + for check in checks: + for xpath, pattern in check.items(): + value = xml.xmltreefile.findtext(xpath) + value = value if value else "" + if not re.search(pattern, value): + test.fail("Unexpected value on xpath '%s':" + " '%s' does not match '%s'" % + (xpath, value, pattern)) + xml = get_nodedev_dumpxml(xml.xmltreefile.findtext("parent")) + validate_nodedev_xml(test, xml) + finally: + if device and device[paths.HEADER["Use"]] == "yes": + ccw.set_device_offline(device[paths.HEADER["Device"]]) def validate_nodedev_xml(test, xml): diff --git a/libvirt/tests/src/virsh_cmd/nodedev/virsh_nodedev_list.py b/libvirt/tests/src/virsh_cmd/nodedev/virsh_nodedev_list.py index 5dc19a22bf8..34807b8a13e 100644 --- a/libvirt/tests/src/virsh_cmd/nodedev/virsh_nodedev_list.py +++ b/libvirt/tests/src/virsh_cmd/nodedev/virsh_nodedev_list.py @@ -30,6 +30,26 @@ def get_avail_caps(all_caps): return avail_caps +def get_scm_devices(): + """ + Get all Storage Class Memory Increments devices, only for s390. + + :return: A list contains all available scm devices in string. + """ + scm_devices = [] + try: + utils_path.find_command('lsscm') + scm_output = process.run('lsscm', ignore_status=True, shell=True).stdout_text + scm_list = scm_output.split('\n')[2:-1] + for scm in scm_list: + scm_info_list = [info for info in scm.split(' ') if info != ''] + scm_devices.append('block_' + scm_info_list[2]) + except utils_path.CmdNotFoundError: + logging.warning('Cmd lsscm not found!') + logging.warning('You can try to install it by `yum install s390utils*`') + return scm_devices + + def get_storage_devices(): """ Retrieve storage devices list from sysfs. @@ -125,6 +145,9 @@ def get_ccw_io_devices(): timeout=5, ignore_status=True, shell=True).stdout_text is_online = "1" == online_value.strip() + # After libvirt version 10.5.0, virsh nodedev list will list all of ccw devices regardless of its state + if libvirt_version.version_compare(10, 5, 0): + is_online = True if is_online: dev_name = re.sub(r'\W', '_', 'ccw_' + device) devices.append(dev_name) @@ -248,6 +271,7 @@ def _check_result(cap, ref_list, result, mode): return True mode = params.get("comparison_mode", "exact") + remove_scm_device = 'yes' == params.get("remove_scm_device", "no") all_caps = ['system', 'pci', 'usb_device', 'usb', 'net', 'scsi_host', 'scsi_target', 'scsi', 'storage', 'fc_host', 'vports', 'scsi_generic', 'ccw', 'css'] @@ -293,6 +317,11 @@ def _check_result(cap, ref_list, result, mode): break elif result.exit_status == 0 and expect_succeed == 'no': break + if cap == 'storage' and remove_scm_device: + scm_devices = get_scm_devices() + if scm_devices: + devices[cap] = [device for device in devices[cap] + if device not in scm_devices] if not _check_result(cap, devices[cap], result.stdout.strip(), mode): check_failed = True break diff --git a/libvirt/tests/src/virsh_cmd/snapshot/virsh_snapshot_create_as.py b/libvirt/tests/src/virsh_cmd/snapshot/virsh_snapshot_create_as.py index fa629d49187..fe698bce977 100644 --- a/libvirt/tests/src/virsh_cmd/snapshot/virsh_snapshot_create_as.py +++ b/libvirt/tests/src/virsh_cmd/snapshot/virsh_snapshot_create_as.py @@ -73,7 +73,7 @@ def check_snap_in_image(vm_name, snap_name, backing_file=False): search_str = os.path.join(os.path.dirname(snap_file_path), os.path.basename(snap_file_path).replace(snap_name, file_suffix)) - search_str = "backing file:\s*%s" % search_str + search_str = "backing file:\\s*%s" % search_str if re.search(search_str, img_info): logging.info("Find snapshot or backing file info in image with '%s'", search_str) @@ -241,45 +241,52 @@ def check_snapslist(test, vm_name, options, option_dict, output, # For no metadata snapshot do not check name and # snapshot if no_metadata < 0: - dname = disks[num].get('name') - logging.debug("dname is %s", dname) - if dname == disk_dict['name']: - logging.info("get disk%d name same as set in " - "diskspec", num) + dnames = [] + for each in range(len(disks)): + dnames.append(disks[each].get('name')) + logging.debug("All disk names: %s", dnames) + if disk_dict['name'] in dnames: + logging.info("Found disk %s in diskspec", + disk_dict['name']) else: - test.fail("Get wrong disk%d name %s" - % (num, dname)) + test.fail("%s disk not present" + % disk_dict['name']) if option_disk.find('snapshot=') >= 0: - dsnap = disks[num].get('snapshot') - logging.debug("dsnap is %s", dsnap) - if dsnap == disk_dict['snapshot']: - logging.info("get disk%d snapshot type same" - " as set in diskspec", num) + dsnaps = [] + for each in range(len(disks)): + dsnaps.append(disks[each].get('snapshot')) + logging.debug("All snapshots are %s", dsnaps) + if disk_dict['snapshot'] in dsnaps: + logging.info("Found snapshot %s in diskspec", + disk_dict['snapshot']) else: - test.fail("Get wrong disk%d " - "snapshot type %s" % - (num, dsnap)) + test.fail("%s snapshot not present" + % disk_dict['snapshot']) if option_disk.find('driver=') >= 0: - dtype = disks[num].find('driver').get('type') - if dtype == disk_dict['driver']: - logging.info("get disk%d driver type same as " - "set in diskspec", num) + dtypes = [] + for each in range(len(disks)): + dtypes.append(disks[each].find('driver').get('type')) + logging.debug("All drivers are %s", dtypes) + if disk_dict['driver'] in dtypes: + logging.info("Found driver %s in diskspec", + disk_dict['driver']) else: - test.fail("Get wrong disk%d driver " - "type %s" % (num, dtype)) + test.fail("%s driver not present" + % disk_dict['driver']) if option_disk.find('file=') >= 0: - sfile = disks[num].find('source').get('file') - if sfile == disk_dict['file']: - logging.info("get disk%d source file same as " - "set in diskspec", num) - if os.path.exists(sfile): - os.unlink(sfile) + sfiles = [] + for each in range(len(disks)): + sfiles.append(disks[each].find('source').get('file')) + logging.debug("All sources are %s", sfiles) + if disk_dict['file'] in sfiles: + logging.info("Found source %s in diskspec", + disk_dict['file']) else: - test.fail("Get wrong disk%d source " - "file %s" % (num, sfile)) + test.fail("%s source not present" + % disk_dict['file']) # For memspec check if the xml is same as setting # Also check if the mem file exists @@ -594,7 +601,14 @@ def run(test, params, env): # check status_error if status_error == "yes": if status == 0: - test.fail("Run successfully with wrong command!") + # snapshots can be created for the guests created + # with 'autodestroy' option on libvirt v5.8.0 and above! + if libvirt_version.version_compare(5, 8, 0) and \ + create_autodestroy: + logging.info("Run passed as expected in " + "libvirt version >= 5.8.0") + else: + test.fail("Run successfully with wrong command!") else: # Check memspec file should be removed if failed if (options.find("memspec") >= 0 and diff --git a/libvirt/tests/src/virsh_cmd/snapshot/virsh_snapshot_disk.py b/libvirt/tests/src/virsh_cmd/snapshot/virsh_snapshot_disk.py index 3f7a26e4149..bc0cf61e566 100644 --- a/libvirt/tests/src/virsh_cmd/snapshot/virsh_snapshot_disk.py +++ b/libvirt/tests/src/virsh_cmd/snapshot/virsh_snapshot_disk.py @@ -288,6 +288,7 @@ def run(test, params, env): if vm_state == "shut off": vm.destroy(gracefully=False) + logging.debug("VM state: %s", vm.state()) snapshot_result = virsh.snapshot_create( vm_name, options, debug=True) out_err = snapshot_result.stderr.strip() @@ -320,6 +321,7 @@ def run(test, params, env): if match_cluster_size not in img_info: test.fail("%s snapshot image doesn't have the same cluster size with backing file" % disk_path) else: + logging.debug("VM state: %s", vm.state()) snapshot_result = virsh.snapshot_create(vm_name, options, debug=True) if snapshot_result.exit_status: @@ -338,6 +340,7 @@ def run(test, params, env): # update an element new_snap.creation_time = snapshot_name snapshot_xml_path = new_snap.xml + logging.debug("VM state: %s", vm.state()) options += "--redefine %s --current" % snapshot_xml_path snapshot_result = virsh.snapshot_create(vm_name, options, debug=True) @@ -422,7 +425,7 @@ def run(test, params, env): session.close() # Test delete snapshot without "--metadata", delete external disk - # snapshot will fail for now. + # External snapshot deletion support added in libvirt_version >= 9.0.0 # Only do this when snapshot create succeed which filtered in cfg file. if snapshot_del_test: if snapshot_name: @@ -439,7 +442,7 @@ def run(test, params, env): test.fail("Snapshot xml file %s missing" % snap_xml_path) else: - if status_error: + if (not libvirt_version.version_compare(9, 0, 0)) and status_error: err_msg = "Snapshot delete succeed but expect fail." test.fail(err_msg) else: diff --git a/libvirt/tests/src/virsh_cmd/virsh_qemu_cmdline_core.py b/libvirt/tests/src/virsh_cmd/virsh_qemu_cmdline_core.py new file mode 100644 index 00000000000..ac9f5572e8b --- /dev/null +++ b/libvirt/tests/src/virsh_cmd/virsh_qemu_cmdline_core.py @@ -0,0 +1,31 @@ +import subprocess + + +def run(test, params, env): + + qemu_binary = params.get("qemu_binary") + errors = ["tcg_region_init", "assertion failed", "Aborted", + "core dumped", "Invalid CPU topology"] + + def check_qemu_cmdline(cpus=9999): + + print("checking with %d CPUs" % cpus) + + command = "%s -accel tcg -smp 10,maxcpus=%d" % (qemu_binary, cpus) + global output + output = subprocess.getoutput(command) + + for err in errors: + if err in output: + return True + return False + + cpus = ["9000", "123", "97865", "56789", "123456789"] + + for cpu in cpus: + failed = check_qemu_cmdline(int(cpu)) + if failed: + break + + if failed: + test.fail(output) diff --git a/libvirt/tests/src/virsh_cmd/volume/virsh_vol_download_upload.py b/libvirt/tests/src/virsh_cmd/volume/virsh_vol_download_upload.py index 344c769721d..4c46cd58a22 100644 --- a/libvirt/tests/src/virsh_cmd/volume/virsh_vol_download_upload.py +++ b/libvirt/tests/src/virsh_cmd/volume/virsh_vol_download_upload.py @@ -18,6 +18,7 @@ from virttest.libvirt_xml import vm_xml from virttest.libvirt_xml.devices.disk import Disk +from virttest.utils_libvirt import libvirt_disk from virttest.utils_test import libvirt from virttest.utils_test import libvirt as utlv @@ -117,22 +118,22 @@ def create_disk(disk_type, disk_path, disk_format, disk_device_type, return custom_disk -def write_disk(test, guest_vm, target_name, size=200): +def write_disk(test, guest_vm, size=200): """ Write data into disk in VM discard value. :param test: test itself. :param guest_vm: Guest VM. - :param target_name: Device target name. :param size: Data size in 1M unit. """ logging.info("Write data into disk in VM...") try: session = guest_vm.wait_for_login() + disk_name, _ = libvirt_disk.get_non_root_disk_name(session) cmd = ("fdisk -l /dev/{0} && mkfs.ext4 -F /dev/{0} && " "mkdir -p test && mount /dev/{0} test && " "dd if=/dev/urandom of=test/file bs=1M count={1} && sync" - .format(target_name, size)) + .format(disk_name, size)) status, output = session.cmd_status_output(cmd) if status != 0: session.close() @@ -376,7 +377,7 @@ def get_pre_post_digest(): # Write 100M data into disk. data_size = 100 - write_disk(test, vm, target, data_size) + write_disk(test, vm, data_size) data_size_in_bytes = data_size * 1024 * 1024 # Refresh directory pool. diff --git a/libvirt/tests/src/virsh_cmd/volume/vol_concurrent.py b/libvirt/tests/src/virsh_cmd/volume/vol_concurrent.py index 3b965c6fcda..5d0497d36b4 100644 --- a/libvirt/tests/src/virsh_cmd/volume/vol_concurrent.py +++ b/libvirt/tests/src/virsh_cmd/volume/vol_concurrent.py @@ -2,10 +2,7 @@ import os import threading import re -try: - import queue as Queue -except ImportError: - import Queue +import queue from avocado.core import exceptions @@ -15,7 +12,7 @@ from virttest.utils_test import libvirt as utlv -q = Queue.Queue() +q = queue.Queue() # Using as lower capital is not the best way to do, but this is just a diff --git a/libvirt/tests/src/virt_cmd/virt_top.py b/libvirt/tests/src/virt_cmd/virt_top.py index 9c692f37649..e2d03421635 100644 --- a/libvirt/tests/src/virt_cmd/virt_top.py +++ b/libvirt/tests/src/virt_cmd/virt_top.py @@ -21,7 +21,7 @@ def run(test, params, env): machine. """ # Install virt-top package if missing. - software_mgr = software_manager.SoftwareManager() + software_mgr = software_manager.manager.SoftwareManager() if not software_mgr.check_installed('virt-top'): logging.info('Installing virt-top package:') software_mgr.install('virt-top') diff --git a/libvirt/tests/src/virt_cmd/virt_xml_validate.py b/libvirt/tests/src/virt_cmd/virt_xml_validate.py index f05e14eaee1..bce16b62e4f 100644 --- a/libvirt/tests/src/virt_cmd/virt_xml_validate.py +++ b/libvirt/tests/src/virt_cmd/virt_xml_validate.py @@ -8,6 +8,7 @@ from virttest import virsh from virttest import data_dir +from virttest import libvirt_version from virttest.utils_libvirt import libvirt_secret from virttest.utils_test import libvirt @@ -34,6 +35,8 @@ def check_info(s1, s2, errorstr="Values differ"): cmd_result = virsh.snapshot_dumpxml(vm_name, snapshot_name, to_file=file) libvirt.check_exit_status(cmd_result) + cmd_result = virsh.snapshot_delete(vm_name, snapshot_name, to_file=file) + libvirt.check_exit_status(cmd_result) def network_validate(test, net_name, file=None, **virsh_dargs): @@ -183,10 +186,21 @@ def interface_validate(test, file=None, **virsh_dargs): test.error(str(e)) +def domcap_validate(file=None, **virsh_dargs): + """ + Prepare schema domcapabilities. + :param file: domcapabilities output file + :param virsh_dargs: virsh debug args. + """ + cmd_result = virsh.domcapabilities(options="> %s" % file, **virsh_dargs) + libvirt.check_exit_status(cmd_result) + + def run(test, params, env): """ Test for virt-xml-validate """ + libvirt_version.is_libvirt_feature_supported(params) # Get the full path of virt-xml-validate command. try: VIRT_XML_VALIDATE = astring.to_text(process.system_output("which virt-xml-validate", shell=True)) @@ -203,7 +217,7 @@ def run(test, params, env): valid_schemas = ['domain', 'domainsnapshot', 'network', 'storagepool', 'storagevol', 'nodedev', 'capability', - 'nwfilter', 'secret', 'interface'] + 'nwfilter', 'secret', 'interface', 'domcapabilities'] if schema not in valid_schemas: test.fail("invalid %s specified" % schema) @@ -230,6 +244,9 @@ def run(test, params, env): secret_validate(test, secret_volume, file=output_path, **virsh_dargs) elif schema == "interface": interface_validate(test, file=output_path, **virsh_dargs) + elif schema == "domcapabilities": + domcap_validate(file=output_path, **virsh_dargs) + schema = "" else: # domain virsh.dumpxml(vm_name, to_file=output_path) diff --git a/libvirt/tests/src/virtio/virtio_page_per_vq.py b/libvirt/tests/src/virtio/virtio_page_per_vq.py index 45fa5ae8ab5..de4e9920345 100644 --- a/libvirt/tests/src/virtio/virtio_page_per_vq.py +++ b/libvirt/tests/src/virtio/virtio_page_per_vq.py @@ -1,9 +1,12 @@ import os import platform +from avocado.utils import process + from virttest import libvirt_version from virttest import utils_net from virttest import virsh +from virttest.utils_test import libvirt from virttest.libvirt_xml import vm_xml from virttest.libvirt_xml.devices.controller import Controller # pylint: disable=W0611 from virttest.libvirt_xml.devices.disk import Disk # pylint: disable=W0611 @@ -13,6 +16,25 @@ from virttest.libvirt_xml.devices.memballoon import Memballoon # pylint: disable=W0611 from virttest.libvirt_xml.devices.rng import Rng # pylint: disable=W0611 from virttest.libvirt_xml.devices.video import Video # pylint: disable=W0611 +from virttest.utils_test import libvirt + + +def get_input_event_file(test): + """ + Get the input event file on the host + + :return: str, the last file path if exists, otherwise skip the test + """ + ret = process.run("ls /dev/input/event*", + shell=True, + verbose=True, + ignore_status=True) + if ret.exit_status != 0: + if ret.stderr_text.count("No such file or directory"): + test.cancel(ret.stderr_text) + else: + test.fail(ret.stderr_text) + return ret.stdout_text.splitlines()[-1] def run(test, params, env): @@ -29,7 +51,8 @@ def prepare_test(vmxml): :params vmxml: the vm xml """ - vmxml.remove_all_device_by_type(device_type) + if not ((device_type == "disk" and hotplug) or device_type == "input"): + vmxml.remove_all_device_by_type(device_type) # For now, arm can not create USB controller automatically. if device_type == "controller" and platform.machine() == 'aarch64': usb_controller = Controller("controller") @@ -44,12 +67,21 @@ def prepare_test(vmxml): vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) # Prepare device xml by using device function, for example, Disk(). device_obj = device_type.capitalize() + disk_image_path = None + if device_type == "disk" and hotplug: + disk_image_path = os.path.join(os.path.dirname(disk_image), "base.qcow2") + libvirt.create_local_disk( + "file", path=disk_image_path, + size="1G", disk_format="qcow2") + device_dict['source']['attrs']['file'] = disk_image_path if device_type == "input": device_xml = eval(device_obj)(input_type) + if input_type == "passthrough": + device_dict['source_evdev'] = get_input_event_file(test) else: device_xml = eval(device_obj)() device_xml.setup_attrs(**device_dict) - return device_xml, vmxml + return device_xml, vmxml, disk_image_path def run_test(device_xml, vmxml): """ @@ -67,44 +99,58 @@ def run_test(device_xml, vmxml): test.log.info("TEST_STEP1: hotplug %s device", device_type) start_guest() virsh.attach_device(vm_name, device_xml.xml, ignore_status=False, debug=True) - vm.wait_for_login() + vm.cleanup_serial_console() + vm.create_serial_console() + vm_session = vm.wait_for_serial_login() test.log.info("TEST_STEP2: check the attribute in %s xml", device_type) check_attribute() if hotplug: virsh.detach_device(vm_name, device_xml.xml, ignore_status=False, debug=True) test.log.info("TEST_STEP3: check the network by ping") - utils_net.ping(dest=ping_outside, count='3', timeout=10, session=vm.session, force_ipv4=True) + utils_net.ping(dest=ping_outside, count='3', timeout=10, session=vm_session, force_ipv4=True) + vm_session.close() - def teardown_test(): + def teardown_test(disk_image_path): """ Clean up the test environment. """ bkxml.sync() - if hotplug and os.path.exists(disk_image): - os.remove(disk_image) + if disk_image_path and os.path.exists(disk_image_path): + os.remove(disk_image_path) def check_attribute(): """ Check the page_per_vq attribute after starting the guest """ af_vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) - test.log.info("The current dumpxml is %s", virsh.dumpxml(af_vmxml)) + test.log.info("The current dumpxml is %s", af_vmxml) # Keyboard and mouse input will be default in guest. So identify input device. - if device_type == "input" and hotplug: - dev_xml = af_vmxml.get_devices(device_type)[2] + if device_type == "input": + input_element = [x for x in af_vmxml.get_devices(device_type) + if x['input_type'] == input_type + and 'driver' in x.fetch_attrs()] + if not input_element: + test.fail("The expected input device was not found.") + dev_xml = input_element[0] # Guest has many controllers, so also need to identify it. elif device_type == "controller": dev_xml = af_vmxml.get_devices(device_type) + elif device_type == "disk" and hotplug: + dev_xml = af_vmxml.get_devices(device_type)[1] else: dev_xml = af_vmxml.get_devices(device_type)[0] # Select the virtio-scsi/virtio-serial controller from all controllers if device_type == "controller": for controller in dev_xml: if controller.type == controller_type: - cur_dict = controller.fetch_attrs()["driver"] + controller_attrs = controller.fetch_attrs() + test.log.debug("controller attrs: %s", controller_attrs) + cur_dict = controller_attrs["driver"] else: - cur_dict = dev_xml.fetch_attrs()["driver"] + dev_attrs = dev_xml.fetch_attrs() + test.log.debug("dev attrs: %s", dev_attrs) + cur_dict = dev_attrs["driver"] pre_dict = driver_dict["driver"] for key, value in pre_dict.items(): if cur_dict.get(key) != value: @@ -112,7 +158,7 @@ def check_attribute(): "got '%s'" % (pre_dict, cur_dict)) else: test.log.debug("Driver XML compare successfully. The '%s' matches" - " the '%s'", (pre_dict, cur_dict)) + " the '%s'", pre_dict, cur_dict) def start_guest(): """ @@ -120,7 +166,7 @@ def start_guest(): """ test.log.info("Start the guest") if not vm.is_alive(): - virsh.start(vm_name, ignore_status=False, debug=True) + vm.start() vm_name = params.get("main_vm") device_type = params.get("device_type") @@ -136,9 +182,10 @@ def start_guest(): vm = env.get_vm(vm_name) vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) bkxml = vmxml.copy() + disk_image_path = None try: - device_xml, vmxml = prepare_test(vmxml) + device_xml, vmxml, disk_image_path = prepare_test(vmxml) run_test(device_xml, vmxml) finally: - teardown_test() + teardown_test(disk_image_path) diff --git a/libvirt/tests/src/virtio_transitional/virtio_transitional_mem_balloon.py b/libvirt/tests/src/virtio_transitional/virtio_transitional_mem_balloon.py index 3946c86e187..1a4c28b836f 100644 --- a/libvirt/tests/src/virtio_transitional/virtio_transitional_mem_balloon.py +++ b/libvirt/tests/src/virtio_transitional/virtio_transitional_mem_balloon.py @@ -45,6 +45,7 @@ def run(test, params, env): os_variant = params.get("os_variant", "") params["disk_model"] = virtio_model set_crypto_policy = params.get("set_crypto_policy") + vm_memory = int(params.get("vm_memory")) if not libvirt_version.version_compare(5, 0, 0): test.cancel("This libvirt version doesn't support " @@ -68,6 +69,8 @@ def run(test, params, env): libvirt.modify_vm_iface(vm_name, "update_iface", iface_params) # Remove nvram setting for rhel6 guest virtio_transitional_base.remove_rhel6_nvram(vm_name) + vmxml.memory = vm_memory + vmxml.sync() libvirt.set_vm_disk(vm, params) # The local variable "vmxml" will not be updated since set_vm_disk # sync with another dumped xml inside the function @@ -92,7 +95,7 @@ def run(test, params, env): if is_windows_guest: return # Check if memory balloon device exists on guest - status = session.cmd_status_output('lspci |grep balloon')[0] + status = session.cmd_status_output(params.get("detect_cmd"))[0] if status != 0: test.fail("Didn't detect memory balloon device on guest.") # Save and restore guest diff --git a/libvirt/tests/src/virtio_transitional/virtio_transitional_nic.py b/libvirt/tests/src/virtio_transitional/virtio_transitional_nic.py index 892b9d932ef..275be100218 100644 --- a/libvirt/tests/src/virtio_transitional/virtio_transitional_nic.py +++ b/libvirt/tests/src/virtio_transitional/virtio_transitional_nic.py @@ -209,7 +209,7 @@ def create_iface_xml(mac): if cold_plug == "yes": reboot() # Reboot guest if it is cold plug test detect_new_nic(mac) - if plug_method == 'interface' and cold_plug == 'no': + if plug_method == 'interface' and cold_plug == 'no' and check_pci_bridge: check_plug_to_pci_bridge(vm_name, mac) session = vm.wait_for_login(serial=True) # Add nic to VM object for further check @@ -278,6 +278,8 @@ def ping_test(restart_network=False): params['disk_model'] = params['virtio_model'] guest_os_type = params['os_type'] set_crypto_policy = params.get("set_crypto_policy") + bridge_controller_needed = params.get("bridge_controller_needed", "yes") == "yes" + check_pci_bridge = params.get("check_pci_bridge", "yes") == "yes" target_path = None @@ -301,15 +303,16 @@ def ping_test(restart_network=False): libvirt.set_vm_disk(vm, params) # Add pcie-to-pci-bridge when there is no one - pci_controllers = vmxml.get_controllers('pci') - for controller in pci_controllers: - if controller.get('model') == 'pcie-to-pci-bridge': - break - else: - contr_dict = {'controller_type': 'pci', - 'controller_model': 'pcie-to-pci-bridge'} - cntl_add = libvirt.create_controller_xml(contr_dict) - libvirt.add_controller(vm_name, cntl_add) + if bridge_controller_needed: + pci_controllers = vmxml.get_controllers('pci') + for controller in pci_controllers: + if controller.get('model') == 'pcie-to-pci-bridge': + break + else: + contr_dict = {'controller_type': 'pci', + 'controller_model': 'pcie-to-pci-bridge'} + cntl_add = libvirt.create_controller_xml(contr_dict) + libvirt.add_controller(vm_name, cntl_add) try: # Update interface model as defined iface_params = {'model': params['virtio_model']} libvirt.modify_vm_iface(vm_name, "update_iface", iface_params) diff --git a/libvirt/tests/src/virtio_transitional/virtio_transitional_rng.py b/libvirt/tests/src/virtio_transitional/virtio_transitional_rng.py index 8b69b832020..8283862449e 100644 --- a/libvirt/tests/src/virtio_transitional/virtio_transitional_rng.py +++ b/libvirt/tests/src/virtio_transitional/virtio_transitional_rng.py @@ -17,7 +17,7 @@ # Using as lower capital is not the best way to do, but this is just a # workaround to avoid changing the entire file. -logging = log.getLogger('avocado.' + __name__) +logging = log.getLogger("avocado." + __name__) def run(test, params, env): @@ -37,10 +37,9 @@ def get_free_pci_slot(): """ used_slot = [] for dev in pci_devices: - address = dev.find('address') - if (address is not None and - address.get('bus') == pci_bridge_index): - used_slot.append(address.get('slot')) + address = dev.find("address") + if address is not None and address.get("bus") == pci_bridge_index: + used_slot.append(address.get("slot")) for slot_index in range(1, 30): slot = "%0#4x" % slot_index if slot not in used_slot: @@ -58,16 +57,16 @@ def get_free_root_port(): used_slot = set() # Record the bus indexes for all pci controllers for controller in pci_controllers: - if controller.get('model') == 'pcie-root-port': - root_ports.add(controller.get('index')) + if controller.get("model") == "pcie-root-port": + root_ports.add(controller.get("index")) else: - other_ports.add(controller.get('index')) + other_ports.add(controller.get("index")) # Record the addresses being allocated for all pci devices - pci_devices = list(vmxml.xmltreefile.find('devices')) + pci_devices = list(vmxml.xmltreefile.find("devices")) for dev in pci_devices: - address = dev.find('address') + address = dev.find("address") if address is not None: - used_slot.add(address.get('bus')) + used_slot.add(address.get("bus")) # Find the bus address unused for bus_index in root_ports: bus = "%0#4x" % int(bus_index) @@ -76,15 +75,17 @@ def get_free_root_port(): # Add a new pcie-root-port if no free one for index in range(1, 30): if index not in (root_ports | other_ports): - contr_dict = {'controller_type': 'pci', - 'controller_index': index, - 'controller_model': 'pcie-root-port'} + contr_dict = { + "controller_type": "pci", + "controller_index": index, + "controller_model": "pcie-root-port", + } cntl_add = libvirt.create_controller_xml(contr_dict) libvirt.add_controller(vm_name, cntl_add) return "%0#4x" % int(index) return None - def check_plug_to(bus_type='pcie-to-pci-bridge'): + def check_plug_to(bus_type="pcie-to-pci-bridge"): """ Check if the nic is plugged onto pcie-to-pci-bridge @@ -92,12 +93,12 @@ def check_plug_to(bus_type='pcie-to-pci-bridge'): :return True if plugged onto 'bus_type', otherwise False """ vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) - rng = vmxml.xmltreefile.find('devices').find('rng') - bus = int(eval(rng.find('address').get('bus'))) - controllers = vmxml.get_controllers('pci') + rng = vmxml.xmltreefile.find("devices").find("rng") + bus = int(eval(rng.find("address").get("bus"))) + controllers = vmxml.get_controllers("pci") for controller in controllers: - if controller.get('index') == bus: - if controller.get('model') == bus_type: + if controller.get("index") == bus: + if controller.get("model") == bus_type: return True break return False @@ -106,31 +107,33 @@ def check_rng_inside_guest(): """ check rng device inside guest """ - check_cmd = params['check_cmd'] + check_cmd = params["check_cmd"] lspci_output = session.cmd_output(check_cmd) - session.cmd_output('pkill -9 hexdump') - if 'No such file or directory' in lspci_output and device_exists: - test.fail('Can not detect device by %s.' % check_cmd) + session.cmd_output("pkill -9 hexdump") + if "No such file or directory" in lspci_output and device_exists: + test.fail("Can not detect device by %s." % check_cmd) vm_name = params.get("main_vm", "avocado-vt-vm1") vm = env.get_vm(params["main_vm"]) vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) backup_xml = vmxml.copy() guest_src_url = params.get("guest_src_url") - virtio_model = params['virtio_model'] - boot_with_rng = (params.get('boot_with_rng', 'yes') == 'yes') - hotplug = (params.get('hotplug', 'no') == 'yes') - device_exists = (params.get('device_exists', 'yes') == 'yes') - plug_to = params.get('plug_to', '') + virtio_model = params["virtio_model"] + boot_with_rng = params.get("boot_with_rng", "yes") == "yes" + hotplug = params.get("hotplug", "no") == "yes" + device_exists = params.get("device_exists", "yes") == "yes" + plug_to = params.get("plug_to", "") set_crypto_policy = params.get("set_crypto_policy") + bridge_controller_needed = "yes" == params.get("bridge_controller_needed", "yes") if not libvirt_version.version_compare(5, 0, 0): - test.cancel("This libvirt version doesn't support " - "virtio-transitional model.") + test.cancel( + "This libvirt version doesn't support " "virtio-transitional model." + ) # Download and update image if required if guest_src_url: - image_name = params['image_path'] + image_name = params["image_path"] target_path = utils_misc.get_path(data_dir.get_data_dir(), image_name) if not os.path.exists(target_path): download.get_file(guest_src_url, target_path) @@ -139,25 +142,28 @@ def check_rng_inside_guest(): utils_conn.update_crypto_policy(set_crypto_policy) try: - # Add 'pcie-to-pci-bridge' if there is no one - pci_controllers = vmxml.get_controllers('pci') - for controller in pci_controllers: - if controller.get('model') == 'pcie-to-pci-bridge': - pci_bridge = controller - break - else: - contr_dict = {'controller_type': 'pci', - 'controller_model': 'pcie-to-pci-bridge'} - pci_bridge = libvirt.create_controller_xml(contr_dict) - libvirt.add_controller(vm_name, pci_bridge) - pci_bridge = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name)\ - .get_controllers('pci', 'pcie-to-pci-bridge')[0] - pci_bridge_index = '%0#4x' % int(pci_bridge.get("index")) + if bridge_controller_needed: + # Add 'pcie-to-pci-bridge' if there is no one + pci_controllers = vmxml.get_controllers("pci") + for controller in pci_controllers: + if controller.get("model") == "pcie-to-pci-bridge": + pci_bridge = controller + break + else: + contr_dict = { + "controller_type": "pci", + "controller_model": "pcie-to-pci-bridge", + } + pci_bridge = libvirt.create_controller_xml(contr_dict) + libvirt.add_controller(vm_name, pci_bridge) + pci_bridge = vm_xml.VMXML.new_from_inactive_dumpxml( + vm_name + ).get_controllers("pci", "pcie-to-pci-bridge")[0] + pci_bridge_index = "%0#4x" % int(pci_bridge.get("index")) # Update nic/nvram and vm disks - if (params["os_variant"] == 'rhel6' or - 'rhel6' in params.get("shortname")): - iface_params = {'model': 'virtio-transitional'} + if params["os_variant"] == "rhel6" or "rhel6" in params.get("shortname"): + iface_params = {"model": "virtio-transitional"} libvirt.modify_vm_iface(vm_name, "update_iface", iface_params) virtio_transitional_base.remove_rhel6_nvram(vm_name) libvirt.set_vm_disk(vm, params) @@ -166,7 +172,7 @@ def check_rng_inside_guest(): vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) # Remove existed rng devices if there are - rng_devs = vmxml.get_devices('rng') + rng_devs = vmxml.get_devices("rng") for rng in rng_devs: vmxml.del_device(rng) vmxml.xmltreefile.write() @@ -174,15 +180,15 @@ def check_rng_inside_guest(): # General new rng xml per configurations rng_xml = libvirt.create_rng_xml({"rng_model": virtio_model}) - if params.get('specify_addr', 'no') == 'yes': - pci_devices = list(vmxml.xmltreefile.find('devices')) + if params.get("specify_addr", "no") == "yes": + pci_devices = list(vmxml.xmltreefile.find("devices")) addr = rng_xml.new_rng_address() - if plug_to == 'pcie-root-port': + if plug_to == "pcie-root-port": bus = get_free_root_port() - addr.set_attrs({'bus': bus}) + addr.set_attrs({"bus": bus}) else: slot = get_free_pci_slot() - addr.set_attrs({'bus': pci_bridge_index, 'slot': slot}) + addr.set_attrs({"bus": pci_bridge_index, "slot": slot}) rng_xml.address = addr if boot_with_rng: # Add to vm if required libvirt.add_vm_device(vmxml, rng_xml) @@ -199,7 +205,7 @@ def check_rng_inside_guest(): check_rng_inside_guest() if hotplug: # Unplug rng if hotplugged previously vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) - rng = vmxml.get_devices('rng')[0] + rng = vmxml.get_devices("rng")[0] file_arg = rng.xml with open(file_arg) as rng_file: logging.debug("Detach rng by XML: %s", rng_file.read()) @@ -208,14 +214,15 @@ def check_rng_inside_guest(): if not hotplug: session.close() save_path = os.path.join( - data_dir.get_tmp_dir(), '%s.save' % params['os_variant']) + data_dir.get_tmp_dir(), "%s.save" % params["os_variant"] + ) ret = virsh.save(vm_name, save_path) libvirt.check_exit_status(ret) ret = virsh.restore(save_path) libvirt.check_exit_status(ret) session = vm.wait_for_login() check_rng_inside_guest() - process.run('rm -f %s' % save_path, ignore_status=True) + process.run("rm -f %s" % save_path, ignore_status=True) finally: vm.destroy() backup_xml.sync() diff --git a/libvirt/tests/src/virtiofs/virtiofs.py b/libvirt/tests/src/virtiofs/virtiofs.py new file mode 100644 index 00000000000..78a7b3e3859 --- /dev/null +++ b/libvirt/tests/src/virtiofs/virtiofs.py @@ -0,0 +1,733 @@ +import logging as log +import os +import shutil +import time +import threading + +from glob import glob + +from avocado.utils import process +from avocado.utils import path as utils_path + +from virttest import virsh +from virttest import utils_test +from virttest import utils_misc +from virttest import libvirt_version +from virttest import utils_libvirtd +from virttest import utils_package +from virttest.libvirt_xml import vm_xml +from virttest.staging import utils_memory +from virttest.utils_config import LibvirtQemuConfig +from virttest.utils_test import libvirt_device_utils +from virttest.utils_test import libvirt +from virttest.utils_libvirt import libvirt_pcicontr +from virttest.utils_libvirt import libvirt_vmxml + + +# Using as lower capital is not the best way to do, but this is just a +# workaround to avoid changing the entire file. +logging = log.getLogger('avocado.' + __name__) + + +def run(test, params, env): + """ + Test virtiofs filesystem device: + + 1.Start guest with 1/2 virtiofs filesystem devices. + 2.Start 2 guest with the same virtiofs filesystem device. + 3.Coldplug/Coldunplug virtiofs filesystem device + 4.Share data between guests and host. + 5.Lifecycle for guest with virtiofs filesystem device. + """ + + def generate_expected_process_options(): + """ + Generate expected virtiofsd process option + """ + expected_results = [] + if cache_mode != "auto": + if cache_mode == "none": + expected_results.append("cache(\s|=)(none|never)") + else: + expected_results.append("cache(\s|=)%s" % cache_mode) + if xattr == "on": + expected_results.append("(\s--|,)xattr") + elif xattr == "off" and not libvirt_version.version_compare(10, 5, 0): + expected_results.append(",no_xattr") + if thread_pool_size: + # Even through there is a equal mark between --thread-pool-size and + # its value for libvirt format. But there is no equal mark in + # virtiofsd man pages. Add another kind of pattern here to avoid + # possible change in the future again. + expected_results.append("--thread-pool-size(\s|=)%s" % thread_pool_size) + if openfiles: + expected_results.append(" --rlimit-nofile(\s|=)%s" % open_files_max) + if sandbox_mode and sandbox_mode == "namespace": + expected_results.append(" --sandbox(\s|=)%s" % sandbox_mode) + logging.debug(f"Expected qemu cmdline pattern {expected_results}") + return expected_results + + def shared_data(vm_names, fs_devs): + """ + Shared data between guests and host: + 1.Mount dir in guest; + 2.Write a file in guest; + 3.Check the md5sum value are the same in guests and host; + + :param vm_names: list of the VM names in the test + :param fs_devs: list of device XML instances + """ + try: + _shared_data(vm_names, fs_devs) + except ShellTimeoutError as e: + logging.error(f"Issue using virtiofs {e}") + logging.error("Collect more information and retry") + for cmd in [ + "ps aux|grep virtiofsd", + "ps aux|grep qemu-kvm", + "ls /var/tmp|grep mount", + "cat /var/log/libvirt/qemu/*virtiofsd.log" + ]: + logging.error(utils_misc.cmd_status_output(cmd)[1]) + logging.error("Retry now") + _shared_data(vm_names, fs_devs) + logging.error("Seems retrying succeeded") + raise e + + def _shared_data(vm_names, fs_devs): + """ + Helper function for `shared_data` so we can retry and collect more + information about the system state. + + :param vm_names: list of the VM names in the test + :param fs_devs: list of device XML instances + """ + md5s = [] + for vm in vms: + guest_index = vms.index(vm) + session = vm.wait_for_login() + fs_indexes = _fs_dev_indexes(guest_index) + for fs_index in fs_indexes: + fs_dev = fs_devs[fs_index] + logging.debug(fs_dev) + mount_dir = '/var/tmp/' + fs_dev.target['dir'] + session.cmd('rm -rf %s' % mount_dir, ignore_all_errors=False) + session.cmd('mkdir -p %s' % mount_dir) + logging.debug("mount virtiofs dir in guest") + cmd = "mount -t virtiofs %s %s" % (fs_dev.target['dir'], mount_dir) + status, output = session.cmd_status_output(cmd, timeout=300) + if status != 0: + session.close() + test.fail("mount virtiofs dir failed: %s" % output) + filename_guest = mount_dir + '/' + vms[0].name + if vm == vms[0]: + cmd = "dd if=/dev/urandom of=%s bs=1M count=512 oflag=direct" % filename_guest + status, output = session.cmd_status_output(cmd, timeout=300) + if status != 0: + session.close() + test.fail("Write data failed: %s" % output) + session.cmd_status_output(f"sync -d {mount_dir}") + md5_value = session.cmd_status_output("md5sum %s" % filename_guest, + timeout=300)[1].strip().split()[0] + md5s.append(md5_value) + logging.debug(md5_value) + md5_value = process.run("md5sum %s" % filename_guest).stdout_text.strip().split()[0] + logging.debug(md5_value) + md5s.append(md5_value) + session.close() + if len(set(md5s)) != fs_num: + test.fail("The md5sum value are not the same in guests and host") + + def launch_externally_virtiofs(source_dir, source_socket): + """ + Launch externally virtiofs + + :param source_dir: the dir shared on host + :param source_socket: the socket file listened on + """ + cmd = "%s --socket-path=%s -o source=%s &" % (path, source_socket, source_dir) + try: + process.run(cmd, ignore_status=False, shell=True, ignore_bg_processes=True) + # Make sure the socket is created + utils_misc.wait_for(lambda: os.path.isdir(source_socket), timeout=3) + process.run("chown qemu:qemu %s" % source_socket, ignore_status=False) + process.run('chcon -t svirt_image_t %s' % source_socket, ignore_status=False, shell=True) + except Exception as err: + cmd = "pkill virtiofsd" + process.run(cmd, shell=True) + test.fail("{}".format(err)) + + def prepare_stress_script(script_path, script_content): + """ + Refer to xfstest generic/531. Create stress test script to create a lot of unlinked files. + + :param source_path: The path of script + :param content: The content of stress script + """ + logging.debug("stress script path: %s content: %s" % (script_path, script_content)) + script_lines = script_content.split(';') + try: + with open(script_path, 'w') as fd: + fd.write('\n'.join(script_lines)) + os.chmod(script_path, 0o777) + except Exception as e: + test.error("Prepare the guest stress script failed %s" % e) + + def run_stress_script(session, script_path): + """ + Run stress script in the guest + + :param session: guest session + :param script_path: The path of script in the guest + """ + # Set ULIMIT_NOFILE to increase the number of unlinked files + session.cmd("ulimit -n 500000 && /usr/bin/python3 %s" % script_path, timeout=120) + + def umount_fs(guest_index): + """ + Unmount the filesystem in guest + + :param guest_index: the guest's index in vms + """ + fs_indexes = _fs_dev_indexes(guest_index) + vm = vms[guest_index] + if vm.is_alive(): + session = vm.wait_for_login() + if lifecycle_scenario == "reboot": + session.cmd("sed -i '$d' /etc/fstab", ignore_all_errors=True) + for index in fs_indexes: + mount_dir = '/var/tmp/' + fs_devs[index].target['dir'] + session.cmd('umount -f %s' % mount_dir, ignore_all_errors=True) + session.cmd('rm -rf %s' % mount_dir, ignore_all_errors=True) + session.close() + + def check_detached_xml(vm): + """ + Check whether there is xml about the filesystem device + in the vm xml + + :param vm: the vm to be checked + """ + vmxml = vm_xml.VMXML.new_from_dumpxml(vm.name) + filesystems = vmxml.devices.by_device_tag('filesystem') + if filesystems: + test.fail("There should be no filesystem devices in guest " + "xml after hotunplug") + + def check_filesystem_in_guest(vm, fs_dev): + """ + Check whether there is virtiofs in vm + + :param vm: the vm to be checked + :param fs_dev: the virtiofs device to be checked + """ + session = vm.wait_for_login() + mount_dir = '/var/tmp/' + fs_dev.target['dir'] + cmd = "mkdir %s; mount -t virtiofs %s %s" % (mount_dir, fs_dev.target['dir'], mount_dir) + status, output = session.cmd_status_output(cmd, timeout=300) + session.cmd('rm -rf %s' % mount_dir, ignore_all_errors=True) + if not status: + test.fail("Mount virtiofs should failed after hotunplug device. %s" % output) + session.close() + + def check_filesystem_hotplug_with_mem_setup(): + """ + Check libvirt can not identify shared memory after restarting + virtqemud. + Bug 2078693 + """ + vm_attrs = eval(params.get('vm_attrs', '{}')) + fs_dict = eval(params.get('fs_dict', '{}')) + source_dir = params.get('source_dir') + dev_type = params.get('dev_type') + vm_name = vm_names[-1] + + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml( + vm_name) + vmxml.setup_attrs(**vm_attrs) + virsh.define(vmxml.xml, debug=True, ignore_status=False) + + libvirtd = utils_libvirtd.Libvirtd() + libvirtd.restart() + + vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) + vmxml.remove_all_device_by_type(dev_type) + vmxml.sync() + vm = env.get_vm(vm_name) + vm.start() + vm.wait_for_login(timeout=120) + os.mkdir(source_dir) + + fs = libvirt_vmxml.create_vm_device_by_type(dev_type, fs_dict) + virsh.attach_device(vm_name, fs.xml, + debug=True, ignore_status=False) + + start_vm = params.get("start_vm", "no") + vm_names = params.get("vms", "avocado-vt-vm1").split() + guest_num = len(vm_names) + cache_mode = params.get("cache_mode", "none") + sandbox_mode = params.get("sandbox_mode", "none") + xattr = params.get("xattr", "on") + path = params.get("virtiofsd_path", "/usr/libexec/virtiofsd") + thread_pool_size = params.get("thread_pool_size") + openfiles = params.get("openfiles", "no") == "yes" + queue_size = params.get("queue_size", "512") + driver_type = params.get("driver_type", "virtiofs") + fs_num = int(params.get("fs_num", "1")) + vcpus_per_cell = int(params.get("vcpus_per_cell", 2)) + dir_prefix = params.get("dir_prefix", "mount_tag") + error_msg_start = params.get("error_msg_start", "") + error_msg_save = params.get("error_msg_save", "") + status_error = params.get("status_error", "no") == "yes" + socket_file_checking = params.get("socket_file_checking", "no") == "yes" + coldplug = params.get("coldplug", "no") == "yes" + hotplug_unplug = params.get("hotplug_unplug", "no") == "yes" + detach_device_alias = params.get("detach_device_alias", "no") == "yes" + extra_hugepages = params.get_numeric("extra_hugepages") + lifecycle_scenario = params.get("lifecycle_scenario", "") + with_hugepages = params.get("with_hugepages", "yes") == "yes" + with_numa = params.get("with_numa", "yes") == "yes" + with_memfd = params.get("with_memfd", "no") == "yes" + source_socket = params.get("source_socket", "/var/tmp/vm001.socket") + launch_mode = params.get("launch_mode", "auto") + bug_url = params.get("bug_url", "") + script_content = params.get("stress_script", "") + stdio_handler = params.get("stdio_handler", "") + setup_mem = params.get("setup_mem", False) + omit_dir_at_first = "yes" == params.get("omit_dir_at_first", "no") + check_debug_log = "yes" == params.get("check_debug_log", "no") + + qemu_config = None + fs_devs = [] + vms = [] + vmxml_backups = [] + expected_fails_msg = [] + backup_huge_pages_num = utils_memory.get_num_huge_pages() + host_hp_size = utils_memory.get_huge_page_size() + huge_pages_num = 0 + + if hotplug_unplug and not utils_path.find_command("lsof", default=False): + test.error("Lsof command is required to run test, but not installed") + + if not libvirt_version.version_compare(7, 0, 0) and not with_numa: + test.cancel("Not supported without NUMA before 7.0.0") + + if not libvirt_version.version_compare(7, 6, 0) and lifecycle_scenario == "destroy_start": + test.cancel("Bug %s is not fixed on current build" % bug_url) + + if not libvirt_version.version_compare(10, 0, 0) and lifecycle_scenario == "managed_save": + test.cancel("Bug %s is not fixed on current build" % bug_url) + + try: + if setup_mem: + libvirt_version.is_libvirt_feature_supported(params) + check_filesystem_hotplug_with_mem_setup() + return + + if openfiles: + with open('/proc/sys/fs/nr_open', 'r') as file: + open_files_max = file.read().strip() + else: + open_files_max = None + + def _get_fs_dev_and_source_dir(fs_index, socket_index): + """ + Returns the device XML for both internally or externally launched + virtiofsd. + + :param fs_index: the index of the filesystem + :param socket_index: the index of the socket for externally launched + virtiofsd; this parameter is ignored for internally + launched virtiofsd and must be different for each + VM accessing the filesystem + :return tuple: (fs_dev, source_dir) - the device xml but also the source + directory which is not part of the XML so the test can + launch the instance for it + """ + driver = {'type': driver_type} + if queue_size != "": + driver['queue'] = queue_size + source_dir = os.path.join('/var/tmp/', str(dir_prefix) + str(fs_index)) + logging.debug(f"This filesystem has source dir: {source_dir}") + if not os.path.isdir(source_dir): + if not (omit_dir_at_first and fs_index == 0): + os.mkdir(source_dir) + target_dir = dir_prefix + str(fs_index) + target = {'dir': target_dir} + if launch_mode == "auto": + binary_keys = ['path', 'cache_mode', 'xattr', + 'thread_pool_size', "open_files_max", "sandbox_mode"] + binary_values = [path, cache_mode, xattr, + thread_pool_size, open_files_max, sandbox_mode] + binary_dict = dict(zip(binary_keys, binary_values)) + source = {'dir': source_dir} + accessmode = "passthrough" + fsdev_keys = ['accessmode', 'driver', 'source', 'target', 'binary'] + fsdev_values = [accessmode, driver, source, target, binary_dict] + else: + source_socket = f"/var/tmp/vm_test{socket_index}.socket" + source = {'socket': source_socket} + fsdev_keys = ['driver', 'source', 'target'] + fsdev_values = [driver, source, target] + fsdev_dict = dict(zip(fsdev_keys, fsdev_values)) + logging.debug(fsdev_dict) + fs_dev = libvirt_device_utils.create_fs_xml(fsdev_dict, launch_mode) + logging.debug(fs_dev) + return fs_dev, source_dir + + def create_fs_devs(): + """ + Creates all fs devs necessary for the test setup and adds them + to the list fs_devs. + """ + with_sockets = launch_mode == "externally" + + def __indexes(): + """ + Helper function that creates input parameters for + _get_fs_dev_and_source_dir. They are different for internally + and externally launched virtiofsd, e.g. for 2 times 2: + (fs_index, socket_index) + internally: the same xml can be used for all guests: + (0, None), (1, None) + externally: there must be 1 socket for each instance and guest: + (0, 0), (0, 1), (1, 2), (1, 3) + """ + socket_number = -1 + for i in range(fs_num): + if not with_sockets: + yield (i, None) + else: + for j in range(guest_num): + socket_number += 1 + yield (i, socket_number) + + for index in __indexes(): + fs_dev, source_dir = _get_fs_dev_and_source_dir(index[0], index[1]) + if with_sockets: + launch_externally_virtiofs(source_dir, fs_dev.source['socket']) + fs_devs.append(fs_dev) + + def _fs_dev_indexes(guest_index): + """ + Returns the list of indexes of all filesystem devices in fs_devs + that correspond to guest_index, e.g. for 2 times 2: + (fs_dev_index, guest_index) + internally launched: no socket necessary, reuse file + fs_dev with index 0, 1 can both be attached to guest 0, 1 + externally launched: can't reuse file + fs_dev with index 0, 2 (with sockets 0, 2) are attached to guest 0 + fs_dev with index 1, 3 (with sockets 1, 3) are attached to guest 1 + + :param guest_index: the index of the VM in vms list + """ + if launch_mode == "externally": + return range(guest_index, fs_num*guest_num, guest_num) + else: + return range(fs_num) + + def update_vm_with_fs_devs(guest_index, vmxml, attach): + """ + Either updates the VM XML or attaches the device XML + + :param guest_index: the index of the guest in vms + :param vmxml: VMXML instance for guest_index + :param attach: if True uses `virsh attach` else it redefines the VM + """ + fs_indexes = _fs_dev_indexes(guest_index) + if attach: + for fs_index in fs_indexes: + ret = virsh.attach_device(vms[guest_index].name, fs_devs[fs_index].xml, + flagstr='--current', debug=True) + utils_test.libvirt.check_exit_status(ret, expect_error=False) + else: + for fs_index in fs_indexes: + vmxml.add_device(fs_devs[fs_index]) + vmxml.sync() + logging.debug(f"VMXML after adding device: {vmxml}") + + def detach_fs_dev(guest_index): + """ + The function uses the virsh detach command to detach + all file systems from the guest determined by its index. + + :param guest_index: the index of the VM as given by the vms list + """ + vm = vms[guest_index] + fs_indexes = _fs_dev_indexes(guest_index) + for fs_index in fs_indexes: + fs_dev = fs_devs[fs_index] + if detach_device_alias and launch_mode == "auto": + utils_package.package_install("lsof") + alias = fs_dev.alias['name'] + cmd = 'lsof /var/log/libvirt/qemu/%s-%s-virtiofsd.log' % (vm.name, alias) + output = process.run(cmd).stdout_text.splitlines() + for item in output[1:]: + if stdio_handler == "file": + if item.split()[0] != "virtiofsd": + test.fail("When setting stdio_handler as file, the command" + " to write log should be virtiofsd!") + elif stdio_handler == "logd": + if item.split()[0] != "virtlogd": + test.fail(" When setting stdio_handler as logd, the command" + "to write log should be virtlogd!") + ret = virsh.detach_device_alias(vm.name, alias, ignore_status=True, + debug=True, wait_for_event=True, + event_timeout=10) + else: + ret = virsh.detach_device(vm.name, fs_dev.xml, ignore_status=True, + debug=True, wait_for_event=True) + libvirt.check_exit_status(ret, status_error) + check_filesystem_in_guest(vm, fs_dev) + + def set_up_and_start_vm(guest_index): + """ + Updates the domain xml according to test scenario + and starts it + + :param guest_index: the index of the guest to be handled + :return end_of_test: True if test should terminate after VM + can be started + """ + vm = env.get_vm(vm_names[guest_index]) + logging.debug("prepare vm %s", vm.name) + vms.append(vm) + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm.name) + vmxml_backups.append(vmxml.copy()) + if vmxml.max_mem < 1024000: + vmxml.max_mem = 1024000 + if with_hugepages: + nonlocal huge_pages_num + huge_pages_num += vmxml.max_mem // host_hp_size + extra_hugepages + utils_memory.set_num_huge_pages(huge_pages_num) + vmxml.remove_all_device_by_type('filesystem') + vmxml.sync() + numa_no = None + if with_numa: + numa_no = vmxml.vcpu // vcpus_per_cell if vmxml.vcpu != 1 else 1 + vm_xml.VMXML.set_vm_vcpus(vmxml.vm_name, vmxml.vcpu, numa_number=numa_no) + vm_xml.VMXML.set_memoryBacking_tag(vmxml.vm_name, access_mode="shared", + hpgs=with_hugepages, memfd=with_memfd) + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm.name) + logging.debug(f"VMXML before adding device: {vmxml}") + if coldplug: + update_vm_with_fs_devs(guest_index, vmxml, attach=True) + else: + if not hotplug_unplug: + update_vm_with_fs_devs(guest_index, vmxml, attach=False) + libvirt_pcicontr.reset_pci_num(vm.name) + result = virsh.start(vm.name, debug=True) + if omit_dir_at_first: + expect_error = True + libvirt.check_exit_status(result, expect_error) + source_dir = os.path.join('/var/tmp/', str(dir_prefix) + str(0)) + os.mkdir(source_dir) + result = virsh.start(vm.name, debug=True) + libvirt.check_exit_status(result, not expect_error) + return True + if hotplug_unplug: + update_vm_with_fs_devs(guest_index, vmxml, attach=True) + if status_error: + return True + + if status_error and not lifecycle_scenario == "managedsave": + expected_error = error_msg_start + utils_test.libvirt.check_exit_status(result, expected_error) + return True + else: + utils_test.libvirt.check_exit_status(result, expect_error=False) + if launch_mode == "auto": + expected_results = generate_expected_process_options() + cmd = 'ps aux | grep /usr/libexec/virtiofsd' + utils_test.libvirt.check_cmd_output(cmd, content=expected_results) + + def check_qemu_cmdline(): + """ + Checks the qemu command line output + At this point only queue size is checked. + """ + if ( + queue_size + and int(queue_size) > 0 + and not hotplug_unplug + ): + cmd = 'ps aux | grep qemu-kvm' + content = [f"queue-size.{{1,3}}{queue_size}"] + utils_test.libvirt.check_cmd_output( + cmd, + content=content + ) + + def check_file_exists(vm, filepath): + """ + Confirm that the given file path exists. + It should have been created earlier in the `shared_data` + function + + :param vm: VM instance + :param filepath: the filepath created in the shared directory + :raise TestFail: file not found + """ + session = vm.wait_for_login() + status, output = session.cmd_status_output(f"ls {filepath}") + if status: + test.fail(f"{filepath} not found in the mount: {output}") + + def update_qemu_config(): + """ + Updates Libvirt's QEMU configuration if needed + """ + if not any([stdio_handler, check_debug_log]): + return + nonlocal qemu_config + qemu_config = LibvirtQemuConfig() + if stdio_handler: + qemu_config.stdio_handler = stdio_handler + if check_debug_log: + qemu_config.virtiofsd_debug = 1 + utils_libvirtd.Libvirtd().restart() + + update_qemu_config() + create_fs_devs() + + for index in range(guest_num): + end_test = set_up_and_start_vm(index) + if end_test: + return + check_qemu_cmdline() + + shared_data(vm_names, fs_devs) + + if check_debug_log: + alias = fs_devs[0].alias['name'] + file_name = '/var/log/libvirt/qemu/%s-%s-virtiofsd.log' % (vm_names[0], alias) + try: + with open(file_name, 'r') as f: + output = f.read() + if "DEBUG" not in output: + shutil.copy(file_name, test.debugdir) + test.fail("Failed to find string in virtiofsd log.") + except FileNotFoundError: + test.fail("virtiofsd log not found") + + if lifecycle_scenario == "suspend_resume": + virsh.suspend(vm_names[0], debug=True, ignore_status=False) + time.sleep(30) + virsh.resume(vm_names[0], debug=True, ignore_statue=False) + elif lifecycle_scenario == "managedsave": + virsh.managedsave(vm_names[0], ignore_status=True, debug=True) + save_file = "/var/lib/libvirt/qemu/save/%s.save" % vm_names[0] + if not os.path.exists(save_file): + test.fail("guest is not manangedsaved") + virsh.start(vm_names[0], ignore_status=True, debug=True) + if os.path.exists(save_file): + test.fail("guest is not restored from the managedsave file") + elif lifecycle_scenario in [ + "destroy_start", + "shutdown_start", + "reboot" + ]: + if fs_num > 1 or guest_num > 1: + test.error("some lifecycle tests are implemented for only" + " 1 guest and filesystem") + session = vms[0].wait_for_login(timeout=120) + session.cmd_status_output( + "echo 'mount_tag0 /var/tmp/mount_tag0 " + "virtiofs defaults 0 0' >> /etc/fstab" + ) + if lifecycle_scenario == "destroy_start": + # Prepare the guest test script + _, source_dir = _get_fs_dev_and_source_dir(0, 0) + script_path = os.path.join(source_dir, "test.py") + script_content %= (source_dir, source_dir) + prepare_stress_script(script_path, script_content) + # Run guest stress script + stress_script_thread = threading.Thread(target=run_stress_script, + args=(session, script_path)) + stress_script_thread.setDaemon(True) + stress_script_thread.start() + # Creates a lot of unlink files + time.sleep(60) + virsh.destroy(vm_names[0], debug=True, ignore_status=False) + ret = virsh.start(vm_names[0], debug=True) + libvirt.check_exit_status(ret) + elif lifecycle_scenario == "shutdown_start": + virsh.shutdown( + vm_names[0], + debug=True, + ignore_status=False + ) + utils_misc.wait_for(vms[0].is_dead, timeout=60) + ret = virsh.start(vm_names[0], debug=True) + libvirt.check_exit_status(ret) + elif lifecycle_scenario == "reboot": + ret = virsh.reboot(vm_names[0], debug=True, ignore_status=False) + libvirt.check_exit_status(ret) + else: + test.fail("Test case not implemented.") + if lifecycle_scenario: + check_file_exists(vms[0], "/var/tmp/mount_tag0/" + vm_names[0]) + elif lifecycle_scenario == "edit_start": + vmxml_virtio_backup = vm_xml.VMXML.new_from_inactive_dumpxml(vm_names[0]) + if vm.is_alive(): + virsh.destroy(vm_names[0]) + cmd = "virt-xml %s --edit --qemu-commandline '\-foo'" % vm_names[0] + cmd_result = process.run(cmd, ignore_status=True, shell=True) + logging.debug(virsh.dumpxml(vm_names[0])) + if cmd_result.exit_status: + test.error("virt-xml edit guest failed: %s" % cmd_result) + result = virsh.start(vm_names[0], ignore_status=True, debug=True) + if error_msg_start: + expected_fails_msg.append(error_msg_start) + utils_test.libvirt.check_result(result, expected_fails=expected_fails_msg) + if not libvirt_version.version_compare(6, 10, 0): + # Because of bug #1897105, it was fixed in libvirt-6.10.0, + # before this version, need to recover the env manually. + cmd = "pkill virtiofsd" + process.run(cmd, shell=True) + if not vm.is_alive(): + # Restoring vm and check if vm can start successfully + vmxml_virtio_backup.sync() + virsh.start(vm_names[0], ignore_status=False, shell=True) + elif socket_file_checking: + result = virsh.domid(vm_names[0]) + domid = result.stdout.strip() + domain_dir = "var/lib/libvirt/qemu/domain-" + domid + '-' + vm_names[0] + if result.exit_status: + test.fail("Get domid failed.") + for fs_dev in fs_devs: + alias = fs_dev.alias['name'] + expected_pid = domain_dir + alias + '-fs.pid' + expected_sock = alias + '-fs.sock' + status1 = process.run('ls -l %s' % expected_pid, shell=True).exit_status + status2 = process.run('ls -l %s' % expected_sock, shell=True).exit_status + if not (status1 and status2): + test.fail("The socket and pid file is not as expected") + elif hotplug_unplug: + for guest_index in range(guest_num): + umount_fs(guest_index) + vm = vms[guest_index] + detach_fs_dev(guest_index) + check_detached_xml(vms[guest_index]) + finally: + for vm in vms: + index = vms.index(vm) + if vm.is_alive(): + umount_fs(index) + vm.destroy(gracefully=False) + virsh.managedsave_remove(vm.name, debug=True, ignore_status=True) + vmxml_backups[index].sync() + utils_memory.set_num_huge_pages(backup_huge_pages_num) + if qemu_config: + qemu_config.restore() + utils_libvirtd.Libvirtd().restart() + for path_pattern in [ + "/var/log/libvirt/qemu/*-virtiofsd.log'", + "/var/tmp/vm_test*socket*", + ]: + for file in glob(path_pattern): + os.remove(file) + for folder in glob("/var/tmp/%s*" % str(dir_prefix)): + shutil.rmtree(folder) + if launch_mode == "externally": + process.run('restorecon %s' % path, ignore_status=False, shell=True) diff --git a/libvirt/tests/src/virtiofs/virtiofs_unprivileged.py b/libvirt/tests/src/virtiofs/virtiofs_unprivileged.py new file mode 100644 index 00000000000..d79e135f452 --- /dev/null +++ b/libvirt/tests/src/virtiofs/virtiofs_unprivileged.py @@ -0,0 +1,401 @@ +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Copyright Red Hat +# +# SPDX-License-Identifier: GPL-2.0 +# +# Author: smitterl@redhat.com +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +import logging +import os +import shutil +import stat + +from aexpect import ShellSession + +from avocado.core.exceptions import TestError +from avocado.utils import process + +from virttest import libvirt_version +from virttest import remote +from virttest import utils_ids +from virttest import virsh +from virttest.staging import utils_memory +from virttest.libvirt_xml.vm_xml import VMXML +from virttest.utils_config import LibvirtQemuConfig +from virttest.utils_libvirt.libvirt_filesystem import check_idmap_xml_filesystem_device +from virttest.utils_libvirt.libvirt_unprivileged import get_unprivileged_vm +from virttest.utils_libvirt.libvirt_vmxml import create_vm_device_by_type + +LOG = logging.getLogger("avocado." + __name__) +allow_all = stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO + +unpr_virsh = "" +vmxmls = {} +backupxmls = [] +vms = [] +test_user = "" +test_passwd = "" +_params = {} +backup_huge_pages_num = 0 +user_config_path = "" +hugepages_user_path = "/var/user_hugepages" +with_hugepages = False +qemu_config = None + + +def get_unprivileged_vms(): + """ + Store the unprivileged user's VMs and the virsh + object for interaction as unprivileged user. + + Assumes that the non-root user exists on the system + and that they have VMs of given names. + """ + + global vmxmls, backupxmls, vms + + vm_names = _params.get("unpr_vms").split(",") + unpr_vm_args = { + "username": _params.get("username"), + "password": _params.get("password"), + } + + vms = [ + get_unprivileged_vm(vm_name, test_user, test_passwd, **unpr_vm_args) + for vm_name in vm_names + ] + + for vm_name in vm_names: + vmxmls[vm_name] = VMXML.new_from_inactive_dumpxml( + vm_name, + virsh_instance=unpr_virsh, + ) + + backupxmls = [vmxmls[name].copy() for name in vmxmls] + + +def _initialize_unpr_virsh(): + """ + Initializes the global instance of the virsh commands object. + """ + + global unpr_virsh + unpr_uri = f"qemu+ssh://{test_user}@localhost/session" + unpr_virsh = virsh.Virsh(uri=unpr_uri, safe=True) + + host_session = ShellSession("su") + remote.VMManager.set_ssh_auth(host_session, "localhost", test_user, test_passwd) + host_session.close() + + +def _refresh_vmxmls(): + """ + Refreshes the global list of VMXML instances under test + so they are up-to-date after changes. + """ + global vmxmls + for name in vmxmls: + vmxmls[name] = VMXML.new_from_dumpxml(name, virsh_instance=unpr_virsh) + LOG.debug("Current XML: %s", vmxmls[name]) + + +def configure_hugepages_for_unprivileged_user(mem): + """ + Allocates hugepages and creates a mount for the unprivileged + test user. + + Assume that all VMs have the same max_mem value so if + the QEMU configuration has already been altered it assumes + hugepages have already been set up and will return. + + It kills the user's process at the end to force reload + with the new configuration. + + :param mem: The memory size that needs to be allocated + in the same unit as the VMXML + """ + global backup_huge_pages_num, qemu_config + if qemu_config: + return + if not os.path.exists(user_config_path): + shutil.copyfile(LibvirtQemuConfig.conf_path, user_config_path) + os.chmod(user_config_path, allow_all) + extra_hugepages = _params.get_numeric("extra_hugepages") + host_hp_size = utils_memory.get_huge_page_size() + backup_huge_pages_num = utils_memory.get_num_huge_pages() + huge_pages_num = 0 + huge_pages_num += mem // host_hp_size + extra_hugepages + utils_memory.set_num_huge_pages(huge_pages_num) + process.run(f"mkdir {hugepages_user_path}", ignore_status=False) + process.run( + f"mount -t hugetlbfs hugetlbfs {hugepages_user_path}", ignore_status=False + ) + process.run(f"chmod a+wrx {hugepages_user_path}", ignore_status=False) + qemu_config = LibvirtQemuConfig(user_config_path) + qemu_config.hugetlbfs_mount = [hugepages_user_path] + process.run(f"killall --user {test_user} virtqemud", shell=True) + + +def clean_up_hugepages_for_unprivileged_user(): + """ + Cleans up the set up for hugepages + """ + qemu_config.restore() + process.run(f"killall --user {test_user} virtqemud", shell=True) + utils_memory.set_num_huge_pages(backup_huge_pages_num) + process.run(f"umount {hugepages_user_path}") + process.run(f"rm -rf {hugepages_user_path}") + + +def add_memory_backing(): + """ + Adds and removes all present filesystem devices + It also sets up hugepages for the unprivileged user assuming + that all VMs would require the same number of memory + """ + + global backup_huge_pages_num, with_hugepages + memorybacking = _params.get("memorybacking") + with_hugepages = "with_hugepages" == memorybacking + with_memfd = "with_memfd" == memorybacking + with_numa = "yes" == _params.get("with_numa") + vcpus_per_cell = _params.get("vcpus_per_cell") + + for name in vmxmls.copy(): + vmxml = vmxmls[name] + if vmxml.max_mem < 1024000: + vmxml.max_mem = 1024000 + if with_hugepages: + configure_hugepages_for_unprivileged_user(len(vms) * vmxml.max_mem) + numa_no = None + if with_numa: + numa_no = vmxml.vcpu // vcpus_per_cell if vmxml.vcpu != 1 else 1 + + vmxml.remove_all_device_by_type("filesystem") + + VMXML.set_vm_vcpus( + vmxml.vm_name, + vmxml.vcpu, + numa_number=numa_no, + virsh_instance=None, + vmxml=vmxml, + ) + VMXML.set_memoryBacking_tag( + vmxml.vm_name, + access_mode="shared", + hpgs=with_hugepages, + memfd=with_memfd, + virsh_instance=None, + vmxml=vmxml, + ) + + _initialize_unpr_virsh() + vmxml.sync(virsh_instance=unpr_virsh) + vmxmls[vmxml.vm_name] = vmxml + + +def cold_or_hot_plug_filesystem(): + """ + Cold or hot plugs the filesystem and + starts the VMs. + + It handles the VM state and makes sure + they are running for further testing. + """ + + for vm in vms: + if "hotplug" == _params.get("plugmode") and not vm.is_alive(): + vm.start() + vm.wait_for_serial_login().close() + if "coldplug" == _params.get("plugmode") and vm.is_alive(): + vm.destroy() + + for fs_dict in fs_dicts: + source_dir = fs_dict["source"]["dir"] + if not os.path.exists(source_dir): + os.mkdir(source_dir) + os.chmod(source_dir, allow_all) + + fs = create_vm_device_by_type("filesystem", fs_dict) + os.chmod(fs.xml, allow_all) + unpr_virsh.attach_device( + vm.name, fs.xml, flagstr="--current", debug=True, ignore_status=False + ) + + if not vm.is_alive(): + vm.start() + _refresh_vmxmls() + + +def check_virtiofs_idmap(): + """ + Checks if the unprivileged VM is running with the correct + user related ids. + """ + + user_info = utils_ids.get_user_ids(test_user) + for name in vmxmls: + for fs in vmxmls[name].get_devices("filesystem"): + check_idmap_xml_filesystem_device(user_info, fs) + + +def mount_fs(session): + """ + Mounts the folder inside of the guest + + :param session: Guest console session + """ + + for fs_dict in fs_dicts: + mount_tag = fs_dict["target"]["dir"] + mount_dir = f"/mnt/{mount_tag}" + session.cmd_output_safe(f"mkdir {mount_dir}") + session.cmd_output_safe(f"mount -t virtiofs {mount_tag} {mount_dir}") + + +def create_file(session): + """ + Creates a file in the guest's mounted filesystem(s) + + :param session: guest console session + """ + + for fs_dict in fs_dicts: + mount_tag = fs_dict["target"]["dir"] + mount_dir = f"/mnt/{mount_tag}" + session.cmd_output_safe( + f"dd if=/dev/zero of={mount_dir}/testfile bs=1M count=10" + ) + session.cmd_output_safe("sync") + + +def check_md5sum(sessions): + """ + Returns the md5sum of the created file + + :param sessions: a list of two console sessions + to take md5sum from and compare + them; the second session might + be a host session (if there is only + 1 vm in the test scenario) + """ + + sums = {0: [], 1: []} + for fs_dict in fs_dicts: + for i in range(len(sessions)): + mount_tag = fs_dict["target"]["dir"] + mount_dir = f"/mnt/{mount_tag}" + source_dir = fs_dict["source"]["dir"] + cmd = f"md5sum {mount_dir}/testfile" + if i == 1 and len(vms) == 1: + cmd = f"md5sum {source_dir}/testfile" + o = sessions[i].cmd_output_safe(cmd) + sums[i].append(o.split()[0]) + + if sums[0] != sums[1]: + raise TestError("The md5sums don't match: %s" % sums) + + +def check_filesystem(after="attach"): + """ + Prepares the filesystems in the guest(s) and runs some checks + + This assumes that the filesystem is shared either between guest + and host or between two guests. + + :param after: if "attach" expect commands to succeed + if "detach" expect commands to fail + """ + + session1 = vms[0].wait_for_serial_login() + if len(vms) == 2: + session2 = vms[1].wait_for_serial_login() + else: + session2 = ShellSession("su") + + try: + mount_fs(session1) + create_file(session1) + if len(vms) == 2: + mount_fs(session2) + check_md5sum([session1, session2]) + + except TestError as e: + if after == "detach": + pass + else: + raise e + + finally: + session1.close() + session2.close() + + +def cold_or_hot_unplug_filesystem(): + """ + Cold or hot unplugs the filesystem and + starts the VMs. + + It handles the VM state and makes sure they are + running for further checks. + """ + + for vm in vms: + if "coldplug" == _params.get("plugmode") and vm.is_alive(): + vm.destroy() + + for fs_dict in fs_dicts: + fs = create_vm_device_by_type("filesystem", fs_dict) + os.chmod(fs.xml, allow_all) + unpr_virsh.detach_device( + vm.name, fs.xml, flagstr="--current", debug=True, ignore_status=False + ) + + if not vm.is_alive(): + vm.start() + + +def initialize(params): + """ + Initializes parameters that are needed globally for all test + variants. + + :param params: the test parameters + """ + + global _params, fs_dicts, test_user, user_config_path, test_passwd + libvirt_version.is_libvirt_feature_supported(params) + _params = params + fs_dicts = eval(_params.get("fs_dicts")) + test_user = _params.get("test_user", "") + test_passwd = _params.get("test_passwd", "") + user_config_path = f"/home/{test_user}/.config/libvirt/qemu.conf" + _initialize_unpr_virsh() + + +def run(test, params, env): + """ + Test running VMs with a filesystem device as unprivileged users. + """ + + global backupxmls, unpr_virsh, fs_dicts, with_hugepages + initialize(params) + try: + get_unprivileged_vms() + add_memory_backing() + cold_or_hot_plug_filesystem() + check_virtiofs_idmap() + check_filesystem(after="attach") + cold_or_hot_unplug_filesystem() + check_filesystem(after="detach") + finally: + for xml in backupxmls: + xml.sync(virsh_instance=unpr_virsh) + for fs_dict in fs_dicts: + source_dir = fs_dict["source"]["dir"] + if os.path.exists(source_dir): + shutil.rmtree(source_dir) + if with_hugepages: + clean_up_hugepages_for_unprivileged_user() diff --git a/libvirt/tests/src/virtual_device/filesystem_device.py b/libvirt/tests/src/virtual_device/filesystem_device.py deleted file mode 100644 index 4d9327345cb..00000000000 --- a/libvirt/tests/src/virtual_device/filesystem_device.py +++ /dev/null @@ -1,479 +0,0 @@ -import os -import logging as log -import time -import threading - -from avocado.utils import process -from avocado.utils import path as utils_path - -from virttest import virsh -from virttest import utils_test -from virttest import utils_misc -from virttest import libvirt_version -from virttest import utils_libvirtd -from virttest import utils_package -from virttest.libvirt_xml import vm_xml -from virttest.staging import utils_memory -from virttest.utils_config import LibvirtQemuConfig -from virttest.utils_test import libvirt_device_utils -from virttest.utils_test import libvirt -from virttest.utils_libvirt import libvirt_pcicontr -from virttest.utils_libvirt import libvirt_vmxml - - -# Using as lower capital is not the best way to do, but this is just a -# workaround to avoid changing the entire file. -logging = log.getLogger('avocado.' + __name__) - - -def run(test, params, env): - """ - Test virtiofs filesystem device: - - 1.Start guest with 1/2 virtiofs filesystem devices. - 2.Start 2 guest with the same virtiofs filesystem device. - 3.Coldplug/Coldunplug virtiofs filesystem device - 4.Share data between guests and host. - 5.Lifecycle for guest with virtiofs filesystem device. - """ - - def generate_expected_process_option(expected_results): - """ - Generate expected virtiofsd process option - """ - if cache_mode != "auto": - expected_results = "cache=%s" % cache_mode - if xattr == "on": - expected_results += ",xattr" - elif xattr == "off": - expected_results += ",no_xattr" - if flock == "on": - expected_results += ",flock" - else: - expected_results += ",no_flock" - if lock_posix == "on": - expected_results += ",posix_lock" - else: - expected_results += ",no_posix_lock" - if thread_pool_size: - expected_results += " --thread-pool-size=%s" % thread_pool_size - logging.debug(expected_results) - return expected_results - - def shared_data(vm_names, fs_devs): - """ - Shared data between guests and host: - 1.Mount dir in guest; - 2.Write a file in guest; - 3.Check the md5sum value are the same in guests and host; - """ - md5s = [] - for vm in vms: - session = vm.wait_for_login() - for fs_dev in fs_devs: - logging.debug(fs_dev) - mount_dir = '/var/tmp/' + fs_dev.target['dir'] - session.cmd('rm -rf %s' % mount_dir, ignore_all_errors=False) - session.cmd('mkdir -p %s' % mount_dir) - logging.debug("mount virtiofs dir in guest") - cmd = "mount -t virtiofs %s %s" % (fs_dev.target['dir'], mount_dir) - status, output = session.cmd_status_output(cmd, timeout=300) - if status != 0: - session.close() - test.fail("mount virtiofs dir failed: %s" % output) - if vm == vms[0]: - filename_guest = mount_dir + '/' + vm.name - cmd = "dd if=/dev/urandom of=%s bs=1M count=512 oflag=direct" % filename_guest - status, output = session.cmd_status_output(cmd, timeout=300) - if status != 0: - session.close() - test.fail("Write data failed: %s" % output) - md5_value = session.cmd_status_output("md5sum %s" % filename_guest, - timeout=300)[1].strip().split()[0] - md5s.append(md5_value) - logging.debug(md5_value) - md5_value = process.run("md5sum %s" % filename_guest).stdout_text.strip().split()[0] - logging.debug(md5_value) - md5s.append(md5_value) - session.close() - if len(set(md5s)) != len(fs_devs): - test.fail("The md5sum value are not the same in guests and host") - - def launch_externally_virtiofs(source_dir, source_socket): - """ - Launch externally virtiofs - - :param source_dir: the dir shared on host - :param source_socket: the socket file listened on - """ - process.run('chcon -t virtd_exec_t %s' % path, ignore_status=False, shell=True) - cmd = "systemd-run %s --socket-path=%s -o source=%s" % (path, source_socket, source_dir) - try: - process.run(cmd, ignore_status=False, shell=True) - # Make sure the socket is created - utils_misc.wait_for(lambda: os.path.isdir(source_socket), timeout=3) - process.run("chown qemu:qemu %s" % source_socket, ignore_status=False) - process.run('chcon -t svirt_image_t %s' % source_socket, ignore_status=False, shell=True) - except Exception as err: - cmd = "pkill virtiofsd" - process.run(cmd, shell=True) - test.fail("{}".format(err)) - - def prepare_stress_script(script_path, script_content): - """ - Refer to xfstest generic/531. Create stress test script to create a lot of unlinked files. - - :param source_path: The path of script - :param content: The content of stress script - """ - logging.debug("stress script path: %s content: %s" % (script_path, script_content)) - script_lines = script_content.split(';') - try: - with open(script_path, 'w') as fd: - fd.write('\n'.join(script_lines)) - os.chmod(script_path, 0o777) - except Exception as e: - test.error("Prepare the guest stress script failed %s" % e) - - def run_stress_script(session, script_path): - """ - Run stress script in the guest - - :param session: guest session - :param script_path: The path of script in the guest - """ - # Set ULIMIT_NOFILE to increase the number of unlinked files - session.cmd("ulimit -n 500000 && /usr/bin/python3 %s" % script_path, timeout=120) - - def umount_fs(vm): - """ - Unmount the filesystem in guest - - :param vm: filesystem in this vm that should be unmounted - """ - if vm.is_alive(): - session = vm.wait_for_login() - for fs_dev in fs_devs: - mount_dir = '/var/tmp/' + fs_dev.target['dir'] - session.cmd('umount -f %s' % mount_dir, ignore_all_errors=True) - session.cmd('rm -rf %s' % mount_dir, ignore_all_errors=True) - session.close() - - def check_detached_xml(vm): - """ - Check whether there is xml about the filesystem device - in the vm xml - - :param vm: the vm to be checked - """ - vmxml = vm_xml.VMXML.new_from_dumpxml(vm.name) - filesystems = vmxml.devices.by_device_tag('filesystem') - if filesystems: - test.fail("There should be no filesystem devices in guest " - "xml after hotunplug") - - def check_filesystem_in_guest(vm, fs_dev): - """ - Check whether there is virtiofs in vm - - :param vm: the vm to be checked - :param fs_dev: the virtiofs device to be checked - """ - session = vm.wait_for_login() - mount_dir = '/var/tmp/' + fs_dev.target['dir'] - cmd = "mkdir %s; mount -t virtiofs %s %s" % (mount_dir, fs_dev.target['dir'], mount_dir) - status, output = session.cmd_status_output(cmd, timeout=300) - session.cmd('rm -rf %s' % mount_dir, ignore_all_errors=True) - if not status: - test.fail("Mount virtiofs should failed after hotunplug device. %s" % output) - session.close() - - def check_filesystem_hotplug_with_mem_setup(): - """ - Check libvirt can not identify shared memory after restarting - virtqemud. - Bug 2078693 - """ - vm_attrs = eval(params.get('vm_attrs', '{}')) - fs_dict = eval(params.get('fs_dict', '{}')) - source_dir = params.get('source_dir') - dev_type = params.get('dev_type') - - vmxml = vm_xml.VMXML.new_from_inactive_dumpxml( - vm_names[int(guest_num) - 1]) - vmxml.setup_attrs(**vm_attrs) - virsh.define(vmxml.xml, debug=True, ignore_status=False) - - libvirtd = utils_libvirtd.Libvirtd() - libvirtd.restart() - - vmxml = vm_xml.VMXML.new_from_dumpxml(vm_names[int(guest_num) - 1]) - vmxml.remove_all_device_by_type(dev_type) - vmxml.sync() - vm = env.get_vm(vm_names[int(guest_num) - 1]) - vm.start() - vm.wait_for_login(timeout=120) - os.mkdir(source_dir) - - fs = libvirt_vmxml.create_vm_device_by_type(dev_type, fs_dict) - virsh.attach_device(vm_names[int(guest_num) - 1], fs.xml, - debug=True, ignore_status=False) - - start_vm = params.get("start_vm", "no") - vm_names = params.get("vms", "avocado-vt-vm1").split() - cache_mode = params.get("cache_mode", "none") - xattr = params.get("xattr", "on") - lock_posix = params.get("lock_posix", "on") - flock = params.get("flock", "on") - xattr = params.get("xattr", "on") - path = params.get("virtiofsd_path", "/usr/libexec/virtiofsd") - thread_pool_size = params.get("thread_pool_size") - queue_size = int(params.get("queue_size", "512")) - driver_type = params.get("driver_type", "virtiofs") - guest_num = int(params.get("guest_num", "1")) - fs_num = int(params.get("fs_num", "1")) - vcpus_per_cell = int(params.get("vcpus_per_cell", 2)) - dir_prefix = params.get("dir_prefix", "mount_tag") - error_msg_start = params.get("error_msg_start", "") - error_msg_save = params.get("error_msg_save", "") - status_error = params.get("status_error", "no") == "yes" - socket_file_checking = params.get("socket_file_checking", "no") == "yes" - suspend_resume = params.get("suspend_resume", "no") == "yes" - managedsave = params.get("managedsave", "no") == "yes" - coldplug = params.get("coldplug", "no") == "yes" - hotplug_unplug = params.get("hotplug_unplug", "no") == "yes" - detach_device_alias = params.get("detach_device_alias", "no") == "yes" - extra_hugepages = params.get_numeric("extra_hugepages") - edit_start = params.get("edit_start", "no") == "yes" - with_hugepages = params.get("with_hugepages", "yes") == "yes" - with_numa = params.get("with_numa", "yes") == "yes" - with_memfd = params.get("with_memfd", "no") == "yes" - source_socket = params.get("source_socket", "/var/tmp/vm001.socket") - launched_mode = params.get("launched_mode", "auto") - destroy_start = params.get("destroy_start", "no") == "yes" - bug_url = params.get("bug_url", "") - script_content = params.get("stress_script", "") - stdio_handler_file = "file" == params.get("stdio_handler") - setup_mem = params.get("setup_mem", False) - - fs_devs = [] - vms = [] - vmxml_backups = [] - expected_fails_msg = [] - expected_results = "" - host_hp_size = utils_memory.get_huge_page_size() - backup_huge_pages_num = utils_memory.get_num_huge_pages() - huge_pages_num = 0 - - if hotplug_unplug and not utils_path.find_command("lsof", default=False): - test.cancel("Lsof command is required to run test, but not installed") - - if len(vm_names) != guest_num: - test.cancel("This test needs exactly %d vms." % guest_num) - - if not libvirt_version.version_compare(7, 0, 0) and not with_numa: - test.cancel("Not supported without NUMA before 7.0.0") - - if not libvirt_version.version_compare(7, 6, 0) and destroy_start: - test.cancel("Bug %s is not fixed on current build" % bug_url) - - try: - if setup_mem: - libvirt_version.is_libvirt_feature_supported(params) - check_filesystem_hotplug_with_mem_setup() - return - # Define filesystem device xml - for index in range(fs_num): - driver = {'type': driver_type, 'queue': queue_size} - source_dir = os.path.join('/var/tmp/', str(dir_prefix) + str(index)) - logging.debug(source_dir) - not os.path.isdir(source_dir) and os.mkdir(source_dir) - target_dir = dir_prefix + str(index) - source = {'socket': source_socket} - target = {'dir': target_dir} - if launched_mode == "auto": - binary_keys = ['path', 'cache_mode', 'xattr', 'lock_posix', - 'flock', 'thread_pool_size'] - binary_values = [path, cache_mode, xattr, lock_posix, - flock, thread_pool_size] - binary_dict = dict(zip(binary_keys, binary_values)) - source = {'dir': source_dir} - accessmode = "passthrough" - fsdev_keys = ['accessmode', 'driver', 'source', 'target', 'binary'] - fsdev_values = [accessmode, driver, source, target, binary_dict] - else: - fsdev_keys = ['driver', 'source', 'target'] - fsdev_values = [driver, source, target] - fsdev_dict = dict(zip(fsdev_keys, fsdev_values)) - logging.debug(fsdev_dict) - fs_dev = libvirt_device_utils.create_fs_xml(fsdev_dict, launched_mode) - logging.debug(fs_dev) - fs_devs.append(fs_dev) - - #Start guest with virtiofs filesystem device - for index in range(guest_num): - logging.debug("prepare vm %s", vm_names[index]) - vm = env.get_vm(vm_names[index]) - vms.append(vm) - vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_names[index]) - vmxml_backup = vmxml.copy() - vmxml_backups.append(vmxml_backup) - if vmxml.max_mem < 1024000: - vmxml.max_mem = 1024000 - if with_hugepages: - huge_pages_num += vmxml.max_mem // host_hp_size + extra_hugepages - utils_memory.set_num_huge_pages(huge_pages_num) - vmxml.remove_all_device_by_type('filesystem') - vmxml.sync() - numa_no = None - if with_numa: - numa_no = vmxml.vcpu // vcpus_per_cell if vmxml.vcpu != 1 else 1 - vm_xml.VMXML.set_vm_vcpus(vmxml.vm_name, vmxml.vcpu, numa_number=numa_no) - vm_xml.VMXML.set_memoryBacking_tag(vmxml.vm_name, access_mode="shared", - hpgs=with_hugepages, memfd=with_memfd) - vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_names[index]) - logging.debug(vmxml) - if launched_mode == "externally": - launch_externally_virtiofs(source_dir, source_socket) - if coldplug: - ret = virsh.attach_device(vm_names[index], fs_devs[0].xml, - flagstr='--config', debug=True) - utils_test.libvirt.check_exit_status(ret, expect_error=False) - else: - if not hotplug_unplug: - for fs in fs_devs: - vmxml.add_device(fs) - vmxml.sync() - logging.debug(vmxml) - libvirt_pcicontr.reset_pci_num(vm_names[index]) - result = virsh.start(vm_names[index], debug=True) - if hotplug_unplug: - if stdio_handler_file: - qemu_config = LibvirtQemuConfig() - qemu_config.stdio_handler = "file" - utils_libvirtd.Libvirtd().restart() - for fs_dev in fs_devs: - ret = virsh.attach_device(vm_names[index], fs_dev.xml, - ignore_status=True, debug=True) - libvirt.check_exit_status(ret, status_error) - - if status_error: - return - if status_error and not managedsave: - expected_error = error_msg_start - utils_test.libvirt.check_exit_status(result, expected_error) - return - else: - utils_test.libvirt.check_exit_status(result, expect_error=False) - expected_results = generate_expected_process_option(expected_results) - if launched_mode == "auto": - cmd = 'ps aux | grep /usr/libexec/virtiofsd' - utils_test.libvirt.check_cmd_output(cmd, content=expected_results) - - if managedsave: - expected_error = error_msg_save - result = virsh.managedsave(vm_names[0], ignore_status=True, debug=True) - utils_test.libvirt.check_exit_status(result, expected_error) - else: - shared_data(vm_names, fs_devs) - if suspend_resume: - virsh.suspend(vm_names[0], debug=True, ignore_status=False) - time.sleep(30) - virsh.resume(vm_names[0], debug=True, ignore_statue=False) - elif destroy_start: - session = vm.wait_for_login(timeout=120) - # Prepare the guest test script - script_path = os.path.join(fs_devs[0].source["dir"], "test.py") - script_content %= (fs_devs[0].source["dir"], fs_devs[0].source["dir"]) - prepare_stress_script(script_path, script_content) - # Run guest stress script - stress_script_thread = threading.Thread(target=run_stress_script, - args=(session, script_path)) - stress_script_thread.setDaemon(True) - stress_script_thread.start() - # Create a lot of unlink files - time.sleep(60) - virsh.destroy(vm_names[0], debug=True, ignore_status=False) - ret = virsh.start(vm_names[0], debug=True) - libvirt.check_exit_status(ret) - elif edit_start: - vmxml_virtio_backup = vm_xml.VMXML.new_from_inactive_dumpxml(vm_names[0]) - if vm.is_alive(): - virsh.destroy(vm_names[0]) - cmd = "virt-xml %s --edit --qemu-commandline '\-foo'" % vm_names[0] - cmd_result = process.run(cmd, ignore_status=True, shell=True) - logging.debug(virsh.dumpxml(vm_names[0])) - if cmd_result.exit_status: - test.error("virt-xml edit guest failed: %s" % cmd_result) - result = virsh.start(vm_names[0], ignore_status=True, debug=True) - if error_msg_start: - expected_fails_msg.append(error_msg_start) - utils_test.libvirt.check_result(result, expected_fails=expected_fails_msg) - if not libvirt_version.version_compare(6, 10, 0): - # Because of bug #1897105, it was fixed in libvirt-6.10.0, - # before this version, need to recover the env manually. - cmd = "pkill virtiofsd" - process.run(cmd, shell=True) - if not vm.is_alive(): - # Restoring vm and check if vm can start successfully - vmxml_virtio_backup.sync() - virsh.start(vm_names[0], ignore_status=False, shell=True) - elif socket_file_checking: - result = virsh.domid(vm_names[0]) - domid = result.stdout.strip() - domain_dir = "var/lib/libvirt/qemu/domain-" + domid + '-' + vm_names[0] - if result.exit_status: - test.fail("Get domid failed.") - for fs_dev in fs_devs: - alias = fs_dev.alias['name'] - expected_pid = domain_dir + alias + '-fs.pid' - expected_sock = alias + '-fs.sock' - status1 = process.run('ls -l %s' % expected_pid, shell=True).exit_status - status2 = process.run('ls -l %s' % expected_sock, shell=True).exit_status - if not (status1 and status2): - test.fail("The socket and pid file is not as expected") - elif hotplug_unplug: - for vm in vms: - umount_fs(vm) - for fs_dev in fs_devs: - if detach_device_alias: - utils_package.package_install("lsof") - alias = fs_dev.alias['name'] - cmd = 'lsof /var/log/libvirt/qemu/%s-%s-virtiofsd.log' % (vm.name, alias) - output = process.run(cmd).stdout_text.splitlines() - for item in output[1:]: - if stdio_handler_file: - if item.split()[0] != "virtiofsd": - test.fail("When setting stdio_handler as file, the command" - "to write log should be virtiofsd!") - else: - if item.split()[0] != "virtlogd": - test.fail("When setting stdio_handler as logd, the command" - "to write log should be virtlogd!") - ret = virsh.detach_device_alias(vm.name, alias, ignore_status=True, - debug=True, wait_for_event=True, - event_timeout=10) - else: - ret = virsh.detach_device(vm.name, fs_dev.xml, ignore_status=True, - debug=True, wait_for_event=True) - libvirt.check_exit_status(ret, status_error) - check_filesystem_in_guest(vm, fs_dev) - check_detached_xml(vm) - finally: - for vm in vms: - alias = fs_dev.alias['name'] - process.run('rm -f /var/log/libvirt/qemu/%s-%s-virtiofsd.log' % (vm.name, alias)) - if vm.is_alive(): - umount_fs(vm) - vm.destroy(gracefully=False) - for vmxml_backup in vmxml_backups: - vmxml_backup.sync() - for index in range(fs_num): - process.run('rm -rf %s' % '/var/tmp/' + str(dir_prefix) + str(index), ignore_status=False) - process.run('rm -rf %s' % source_socket, ignore_status=False, shell=True) - if launched_mode == "externally": - process.run('restorecon %s' % path, ignore_status=False, shell=True) - utils_memory.set_num_huge_pages(backup_huge_pages_num) - if stdio_handler_file: - qemu_config.restore() - utils_libvirtd.Libvirtd().restart() diff --git a/libvirt/tests/src/virtual_device/input_devices_plug_unplug.py b/libvirt/tests/src/virtual_device/input_devices_plug_unplug.py new file mode 100644 index 00000000000..08ccc9e697f --- /dev/null +++ b/libvirt/tests/src/virtual_device/input_devices_plug_unplug.py @@ -0,0 +1,106 @@ +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Copyright Red Hat +# +# SPDX-License-Identifier: GPL-2.0 +# Author: Dan Zheng +# + +from virttest.libvirt_xml.devices.input import Input +from virttest.libvirt_xml.vm_xml import VMXML +from virttest import virsh +from virttest.utils_libvirt import libvirt_pcicontr + + +def prepare_vm_xml(vm_xml, device_type, test): + """ + Remove specified devices from the vm xml for the test + + :param vm_xml: vm xml + :param device_type: str, device type + :param test: test object + """ + vm_xml.remove_all_device_by_type(device_type) + vm_xml.sync() + test.log.debug("The VM xml after preparation:" + "\n%s", VMXML.new_from_dumpxml(vm_xml.vm_name)) + + +def check_dumpxml(vm_name, expect_device_types, expect_bus, expect_exist, test): + """ + Check whether the specified devices are(or aren't) shown in the guest xml + + :param vm_name: str, vm name + :param expect_device_types: list, device types, like ['keyboard', 'mouse'] + :param expect_bus: str, device bus, like 'virtio' + :param expect_exist: boolean, True for existence, False for not + :param test: test object + """ + current_vmxml = VMXML.new_from_dumpxml(vm_name) + input_devices = current_vmxml.get_devices(device_type="input") + test.log.debug("Current vm xml:\n%s", current_vmxml) + for device_type in expect_device_types: + found = False + for dev in input_devices: + if dev.type_name == device_type and dev.input_bus == expect_bus: + found = True + test.log.debug("Found the expected %s device " + "with %s bus", device_type, expect_bus) + break + if found == expect_exist: + test.log.debug("Verify guest xml for the %s device " + "with %s bus - PASS", device_type, expect_bus) + + else: + test.fail("Expect the %s device with %s bus %s " + "exist." % (device_type, + expect_bus, + 'not' if not expect_exist else '')) + + +def run(test, params, env): + """ + Test the input virtual devices + + 1. Start a guest + 2. Test hotplug and hotunplug different input devices + 3. check the result + """ + vm_name = params.get("main_vm", "avocado-vt-vm1") + libvirt_pcicontr.reset_pci_num(vm_name) + vm = env.get_vm(vm_name) + vm_xml = VMXML.new_from_dumpxml(vm_name) + vm_xml_backup = vm_xml.copy() + + bus_type = params.get("bus_type") + device_types = eval(params.get("device_types")) + virsh_dargs = {'ignore_status': False, 'debug': True} + device_list = [] + + if vm.is_alive(): + vm.destroy() + + try: + test.log.info("STEP: Clean input devices from VM xml.") + prepare_vm_xml(vm_xml, 'input', test) + test.log.info("STEP: Start VM") + virsh.start(vm_name, **virsh_dargs) + vm.wait_for_login().close() + for input_type in device_types: + input_dev = Input(type_name=input_type) + input_dev.input_bus = bus_type + device_list.append(input_dev) + test.log.info("STEP: Hotplug device:%s", input_dev) + virsh.attach_device(vm_name, input_dev.xml, **virsh_dargs) + check_dumpxml(vm_name, device_types, bus_type, True, test) + for input_dev in device_list: + test.log.info("STEP: Hotunplug device:%s", input_dev) + virsh.detach_device(vm_name, input_dev.xml, + wait_for_event=True, event_timeout=10, + **virsh_dargs) + check_dumpxml(vm_name, device_types, bus_type, False, test) + finally: + if vm.is_alive(): + virsh.destroy(vm_name) + vm_xml_backup.sync() diff --git a/libvirt/tests/src/virtual_device/swtpm_cmd.py b/libvirt/tests/src/virtual_device/swtpm_cmd.py new file mode 100644 index 00000000000..0ec5885bb02 --- /dev/null +++ b/libvirt/tests/src/virtual_device/swtpm_cmd.py @@ -0,0 +1,109 @@ +import os +import time +import psutil +import shutil +import subprocess +import logging as log + +from avocado.utils import process +from glob import glob + +# Using as lower capital is not the best way to do, but this is just a +# workaround to avoid changing the entire file. +logging = log.getLogger('avocado.' + __name__) + + +def check_process_exist(process_cmd, check_cmd): + """ + Check if a cmd process exists in system processes. + + :param process_cmd: the process to check + :param check_cmd: the cmd for how to check process + :return: boolean value for exist or not + """ + p_list = process.run(check_cmd, shell=True, ignore_status=True).stdout_text + ret = True if process_cmd in p_list else False + return ret + + +def kill_process(name): + """ + Kill a process by name + + :param name: the process name to kill + """ + for proc in psutil.process_iter(): + if proc.name() == name: + logging.debug('Killing process %s', name) + proc.kill() + + +def run(test, params, env): + """ + Test the swtpm_setup or 'swtpm_socket' cmds + """ + swtpm_setup_cmd = params.get("swtpm_setup_cmd") + swtpm_socket_cmd = params.get("swtpm_socket_cmd", "") + qemu_cmd = params.get("qemu_cmd", "") + extra_option = params.get("extra_option", "") + co_cmd = params.get("co_cmd", "") + unexpected_error = params.get("unexpected_error", "") + tpm_state_dir = params.get("tpm_state_dir", "") + p2 = None + + if extra_option: + swtpm_socket_cmd += " " + extra_option + if tpm_state_dir and not os.path.exists(tpm_state_dir): + os.mkdir(tpm_state_dir) + + swtpm_check_cmd = "ps aux|grep 'swtpm socket'\ + |grep -v avocado-runner-avocado-vt|grep -v grep" + + try: + if co_cmd: + logging.debug("Running '%s'", co_cmd) + p_out = subprocess.Popen(co_cmd, shell=True, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE).stdout.read() + logging.debug("The cocurrent swtpm_setup output \ + including 'read' is:\n%s", p_out) + if unexpected_error in str(p_out): + test.fail(p_out) + else: + process.run(swtpm_setup_cmd, shell=True, ignore_status=False) + process.run(swtpm_socket_cmd, shell=True, ignore_status=False) + qemu_check_cmd = "ps aux|grep '/usr/libexec/qemu-kvm -tpmdev' \ + |grep -v avocado-runner-avocado-v|grep -v grep" + if qemu_cmd and check_process_exist(swtpm_socket_cmd, + swtpm_check_cmd): + p2 = subprocess.Popen(qemu_cmd, shell=True, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + logging.debug("Running '%s'", qemu_cmd) + time.sleep(3) + check_process_exist(qemu_cmd, qemu_check_cmd) + if p2.poll() is None: + logging.debug('Killing qemu cmd...') + p2.kill() + check_process_exist(qemu_cmd, qemu_check_cmd) + swtpm_socket_exists = check_process_exist(swtpm_socket_cmd, + swtpm_check_cmd) + if swtpm_socket_exists and '--terminate' in swtpm_socket_cmd: + test.fail("swtpm process should exit with '--terminate'\ + when qemu is killed.") + elif not swtpm_socket_exists and \ + '--terminate' not in swtpm_socket_cmd: + test.fail("swtpm process should not exit\ + without '--terminate' when qemu is killed.") + + finally: + logging.debug('Cleaning env...') + if check_process_exist(swtpm_socket_cmd, swtpm_check_cmd): + kill_process('swtpm') + if p2 and p2.poll() is None: + p2.kill() + if os.path.exists(tpm_state_dir): + shutil.rmtree(tpm_state_dir) + for folder in glob("/tmp/vtpm*"): + shutil.rmtree(folder) + process.run("rm -rf /var/lib/swtpm-localca/*", shell=True, ignore_status=True) diff --git a/libvirt/tests/src/virtual_device/tpm_device.py b/libvirt/tests/src/virtual_device/tpm_device.py index fa82e8913e5..53b0d6ce8b3 100644 --- a/libvirt/tests/src/virtual_device/tpm_device.py +++ b/libvirt/tests/src/virtual_device/tpm_device.py @@ -6,6 +6,7 @@ import platform import shutil import glob +import subprocess from virttest import data_dir from virttest import libvirt_version @@ -15,7 +16,6 @@ from virttest import utils_misc from virttest import utils_libguestfs from virttest import utils_libvirtd -from virttest import libvirt_version from virttest.libvirt_xml.devices.tpm import Tpm from virttest.libvirt_xml.vm_xml import VMXML @@ -54,6 +54,7 @@ def run(test, params, env): tpm_model = params.get("tpm_model") backend_type = params.get("backend_type") backend_version = params.get("backend_version") + backend_debug = params.get("backend_debug") device_path = params.get("device_path") tpm_num = int(params.get("tpm_num", 1)) # After first start of vm with vtpm, do operations, check it still works @@ -86,13 +87,13 @@ def run(test, params, env): remove_pcrbank = ('yes' == params.get("remove_pcrbank", "no")) pcrbank_change = params.get("pcrbank_change") test_rsaencypt = ('yes' == params.get("test_rsaencypt", "no")) + test_sign = ('yes' == params.get("test_sign", "no")) active_pcr_banks = params.get("active_pcr_banks") statedir = params.get("statedir") audit_cmd = params.get("audit_cmd") ausearch_check = params.get("ausearch_check") skip_start = ('yes' == params.get("skip_start", "no")) - swtpm_setup_path = params.get("swtpm_setup_path") - swtpm_path = params.get("swtpm_path") + p2 = None source_attrs_str = params.get("source_attrs") if source_attrs_str: source_attrs = ast.literal_eval(source_attrs_str) @@ -283,6 +284,8 @@ def check_dumpxml(vm_name): if backend_version: check_ver = backend_version if backend_version not in ["none", "default"] else '2.0' xpaths.append({'element_attrs': [".//backend[@version='%s']" % check_ver]}) + if backend_debug: + xpaths.append({'element_attrs': [".//backend[@debug='%s']" % backend_debug]}) if active_pcr_banks and not remove_pcrbank: check_active_pcr_banks(xml_after_adding_device) if backend_type == "passthrough": @@ -302,7 +305,7 @@ def check_dumpxml(vm_name): def launch_external_swtpm(skip_setup): """ - Launch externally swtpm + Launch external swtpm :param skip_setup: whether skip swtpm_setup steps """ @@ -311,16 +314,19 @@ def launch_external_swtpm(skip_setup): shutil.rmtree(statedir) os.mkdir(statedir) process.run("ls -lZd %s" % statedir) - process.run('chcon -t virtd_exec_t %s' % swtpm_setup_path, ignore_status=False, shell=True) - cmd1 = "systemd-run %s --tpm2 --tpmstate %s --create-ek-cert --create-platform-cert --overwrite" % (swtpm_setup_path, statedir) - process.run('chcon -t virtd_exec_t %s' % swtpm_path, ignore_status=False, shell=True) - cmd2 = "systemd-run %s socket --ctrl type=unixio,path=%s,mode=0600 --tpmstate dir=%s,mode=0600 --tpm2 --terminate" % (swtpm_path, source_socket, statedir) + cmd1 = "swtpm_setup --tpm2 --tpmstate %s --create-ek-cert --create-platform-cert --overwrite" % statedir + cmd2 = "swtpm socket --ctrl type=unixio,path=%s,mode=0600 --tpmstate dir=%s,mode=0600 --tpm2 --terminate" % (source_socket, statedir) try: if not skip_setup: process.run(cmd1, ignore_status=False, shell=True) - process.run(cmd2, ignore_status=False, shell=True) + logging.debug("Running '%s'", cmd2) + p2 = subprocess.Popen(cmd2, shell=True, stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + process.run("ps aux|grep 'swtpm socket'|grep -v avocado-runner-avocado-vt|grep -v grep", ignore_status=True, shell=True) + if p2.poll() is not None: + test.error('External swtpm socket process does not exist') # Make sure the socket is created - utils_misc.wait_for(lambda: os.path.isdir(source_socket), timeout=3) + utils_misc.wait_for(lambda: os.path.exists(source_socket), timeout=3) process.run('chcon -t svirt_image_t %s' % source_socket, ignore_status=False, shell=True) process.run('chown qemu:qemu %s' % source_socket, ignore_status=False, shell=True) except Exception as err: @@ -397,6 +403,8 @@ def check_swtpm(domid, domuuid, vm_name): pattern_list.remove("--log") if prepare_secret: pattern_list.extend(["--key", "--migration-key"]) + if backend_debug: + pattern_list.extend(["level=%s" % backend_debug]) for pattern in pattern_list: if not re.search(pattern, cmdline): test.fail("Can not find the %s for tpm device " @@ -572,6 +580,8 @@ def run_test_suite_in_guest(session): # Download test suite if tpm_testsuite_url.count("EXAMPLE"): test.error("Please provide the URL %s" % tpm_testsuite_url) + if not utils_package.package_install('wget', session, 60): + test.fail("Failed to install wget in guest OS.") download_cmd = "wget %s -O %s" % (tpm_testsuite_url, "/root/linux.tar.xz") output = session.cmd_output(download_cmd, timeout=480) logging.debug("Command output: %s", output) @@ -606,19 +616,28 @@ def run_test_suite_in_guest(session): test.fail("test suite check failed.") logging.info("------PASS on kernel test suite check------") - def test_rsaencypt_in_guest(session): + def prepare_rsa_key(session, test_msg="my message"): """ - Test tpm RSA encryption in guest. + Create RSA key and load it, also prepare data file. :param session: Guest session to be tested + :param test_msg: message to put in data file """ if not utils_package.package_install(["tpm2-tools"], session, 360): test.error("Failed to install tpm2-tools package in guest") - session.cmd_status_output("tpm2_createprimary -c primary.ctx") - session.cmd("tpm2_create -C primary.ctx -Grsa2048 -u key.pub -r key.priv") + session.cmd_status_output("tpm2_createprimary -C e -c primary.ctx") + session.cmd("tpm2_create -C primary.ctx -G rsa2048 -u key.pub -r key.priv") session.cmd("tpm2_load -C primary.ctx -u key.pub -r key.priv -c key.ctx") - test_msg = 'my message' session.cmd("echo %s > msg.dat" % test_msg) + + def test_rsaencypt_in_guest(session): + """ + Test tpm RSA encryption in guest. + + :param session: Guest session to be tested + """ + test_msg = 'my encrypt decrypt test message' + prepare_rsa_key(session, test_msg) for padding_scheme in ['oaep', 'rsaes', 'null']: status, output = session.cmd_status_output("tpm2_rsaencrypt -c key.ctx -o msg.enc -s %s msg.dat" % padding_scheme) if status: @@ -633,6 +652,19 @@ def test_rsaencypt_in_guest(session): session.cmd("rm -f msg.enc msg.ptext") session.cmd("rm -f primary.ctx key.pub key.priv key.ctx msg.dat") + def test_sign_in_guest(session): + """ + Test tpm signature in guest. + + :param session: Guest session to be tested + """ + prepare_rsa_key(session) + for hash_algorithm in ['sha1', 'sha256', 'sha384', 'sha512']: + status, output = session.cmd_status_output("tpm2_sign -c key.ctx -g %s -o sig.rssa msg.dat" % hash_algorithm) + if status: + test.fail("tpm2_sign failed with %s hash algorithm: %s" % (hash_algorithm, output)) + session.cmd("rm -f primary.ctx key.pub key.priv key.ctx msg.dat sig.rssa") + def persistent_test(vm, vm_xml): """ Test vtpm with persistent_state for transient vm. @@ -724,6 +756,20 @@ def check_swtpmpidfile(vm_name, test_stage): if swtpm_pidfile and libvirt_version.version_compare(8, 7, 0): test.error('swtpm.pid still exists after %s: %s' % (test_stage, swtpm_pidfile)) + def test_swtpm_logging(): + """ + test logging level for swtpm when backend_debug is set + """ + log_pattern_list = ["SWTPM_IO_Read", "SWTPM_IO_Write"] + swtpm_log = "/var/log/swtpm/libvirt/qemu/" + vm.name + "-swtpm.log" + with open(swtpm_log) as f: + lines = "".join(f.readlines()) + for log_pattern in log_pattern_list: + if re.search(log_pattern, lines): + logging.info("Finding msg<%s> in swtpm log", log_pattern) + else: + test.fail("Can not find msg:<%s> in swtpm log" % log_pattern) + try: tpm_real_v = None sec_uuids = [] @@ -751,6 +797,8 @@ def check_swtpmpidfile(vm_name, test_stage): if backend_type == "emulator": if backend_version != 'none': backend.backend_version = backend_version + if backend_debug: + backend.backend_debug = backend_debug if persistent_state: backend.persistent_state = "yes" if prepare_secret: @@ -805,18 +853,20 @@ def check_swtpmpidfile(vm_name, test_stage): return if tpm_model and backend_version != 'default': expect_fail = False + if ausearch_check: + cmd = "truncate -s 0 /var/log/audit/audit.log*" + process.run(cmd, shell=True) + ausearch_ret = process.run(audit_cmd, verbose=True, shell=True, ignore_status=True) + if not ausearch_ret: + test.fail('audit log is not cleaned well.') try: vm.start() except VMStartError as detail: - if secret_value == 'none' or secret_uuid == 'nonexist' or not source_socket: + if secret_value == 'none' or secret_uuid == 'nonexist' or (source_attrs_str and not source_socket): logging.debug("Expected failure: %s", detail) return else: test.fail(detail) - if ausearch_check: - process.run("echo > /var/log/audit/audit.log", ignore_status=True) - ausearch_result = process.run(audit_cmd, verbose=True, shell=True) - libvirt.check_result(ausearch_result, expected_match=ausearch_check) if undefine_flag: time.sleep(5) vm.destroy() @@ -921,6 +971,9 @@ def check_swtpmpidfile(vm_name, test_stage): return domid = vm.get_id() check_qemu_cmd_line(vm, vm_name, domid) + if ausearch_check: + ausearch_result = process.run(audit_cmd, verbose=True, shell=True) + libvirt.check_result(ausearch_result, expected_match=ausearch_check) if backend_type == "passthrough": if tpm_real_v == "1.2" and tpm_model == "tpm-crb": expect_fail = True @@ -937,9 +990,13 @@ def check_swtpmpidfile(vm_name, test_stage): run_test_suite_in_guest(session) elif test_rsaencypt: test_rsaencypt_in_guest(session) + elif test_sign: + test_sign_in_guest(session) else: test_guest_tpm(expect_version, session, expect_fail) session.close() + if backend_debug: + test_swtpm_logging() if multi_vms: reuse_by_vm2(tpm_dev) if backend_type != "passthrough": @@ -982,10 +1039,11 @@ def check_swtpmpidfile(vm_name, test_stage): vm_xml_backup.sync(options="--nvram --managed-save") check_swtpmpidfile(vm_name, "test finished") if backend_type == 'external' and not status_error: - process.run("restorecon %s" % swtpm_setup_path, ignore_status=False, shell=True) - process.run("restorecon %s" % swtpm_path, ignore_status=False, shell=True) if os.path.exists(statedir): shutil.rmtree(statedir) + if p2 and p2.poll() is None: + p2.kill() + process.run("rm -rf /var/lib/swtpm-localca/*", shell=True, ignore_status=True) # Remove swtpm log file in case of impact on later runs if os.path.exists("/var/log/swtpm/libvirt/qemu/%s-swtpm.log" % vm.name): os.remove("/var/log/swtpm/libvirt/qemu/%s-swtpm.log" % vm.name) diff --git a/libvirt/tests/src/virtual_device/video_devices.py b/libvirt/tests/src/virtual_device/video_devices.py index d258ca96790..03876f141e3 100644 --- a/libvirt/tests/src/virtual_device/video_devices.py +++ b/libvirt/tests/src/virtual_device/video_devices.py @@ -223,6 +223,9 @@ def up_round_to_power_of_two(num): guest_arch = params.get("vm_arch_name") with_packed = params.get("with_packed", "no") == "yes" driver_packed = params.get("driver_packed", "on") + resolution_test = params.get("resolution_test", "no") == "yes" + resolution_x = params.get("resolution_x") + resolution_y = params.get("resolution_y") vm_xml = VMXML.new_from_dumpxml(vm_name) vm_xml_backup = vm_xml.copy() @@ -243,9 +246,11 @@ def up_round_to_power_of_two(num): if heads_test and not default_primary_heads: kwargs["model_heads"] = primary_heads if mem_test and not default_mem_size: - kwargs["model_"+mem_type] = mem_size + kwargs["model_" + mem_type] = mem_size if model_type == "virtio" and with_packed: kwargs["driver"] = {"packed": driver_packed} + if resolution_test: + kwargs["resolution"] = {"x": resolution_x, "y": resolution_y} add_video_device(model_type, vm_xml, is_primary, status_error, **kwargs) if secondary_video_model: @@ -266,6 +271,9 @@ def up_round_to_power_of_two(num): "device xml. details: %s " % res) logging.debug("vm started successfully in positive cases.") + if resolution_test: + libvirt.check_qemu_cmd_line(params.get("qemu_line")) + if model_test: check_model_test_cmd_line(model_type, is_primary) @@ -283,6 +291,8 @@ def up_round_to_power_of_two(num): check_mem_test_xml(model_type, mem_type, mem_size) check_mem_test_cmd_line(model_type, mem_type, mem_size) + + vm.wait_for_login().close() finally: if vm.is_alive(): vm.destroy(vm_name) diff --git a/libvirt/tests/src/virtual_device/vsock.py b/libvirt/tests/src/virtual_device/vsock.py index e8df713ac8c..61498bd6d17 100644 --- a/libvirt/tests/src/virtual_device/vsock.py +++ b/libvirt/tests/src/virtual_device/vsock.py @@ -9,9 +9,12 @@ from avocado.utils import process +from virttest import libvirt_version +from virttest import ssh_key from virttest import virsh from virttest import utils_test from virttest import utils_misc +from virttest import utils_package from virttest.utils_test import libvirt from virttest.libvirt_xml import vm_xml from virttest.libvirt_xml.devices.vsock import Vsock @@ -183,6 +186,43 @@ def managedsave_restore(): result = virsh.start(vm_name) utils_test.libvirt.check_exit_status(result, expect_error=False) + def add_guest_user(name, passwd): + """ + Added a user account in guest + + :param name: user name + :param passwd: password of user account + """ + try: + session = vm.wait_for_login() + session.cmd_output('useradd %s' % name) + finally: + session.close() + virsh.set_user_password(vm_name, name, passwd, debug=True) + + def forward_vsock_to_sshd(): + """ + Run a service that forwards VSOCK <=> SSHD communication + """ + + session = vm.wait_for_login() + try: + session.cmd("socat VSOCK-LISTEN:22,reuseaddr,fork TCP:localhost:22 &") + except Exception as e: + test.fail("Forwarding vsock to sshd communication failed: %s" % e) + + def check_systemd_version(): + """ + Check the version of systemd inside the guest + """ + try: + session = vm.wait_for_login() + systemd_version = session.cmd_output(systemd_version_cmd) + logging.debug("systemd version of guest is %s" % systemd_version) + finally: + session.close() + return systemd_version + start_vm = params.get("start_vm", "no") vm_name = params.get("main_vm", "avocado-vt-vm1") vm = env.get_vm(params["main_vm"]) @@ -197,6 +237,9 @@ def managedsave_restore(): vsock_num = params.get("num") communication = params.get("communication", "no") == "yes" detach_device_alias = params.get("detach_device_alias", "no") == "yes" + guest_user = params.get("guest_user") + guest_user_passwd = params.get("guest_user_passwd") + systemd_version_cmd = params.get("systemd_version_cmd") # Backup xml file vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) backup_xml = vmxml.copy() @@ -217,7 +260,7 @@ def managedsave_restore(): logging.debug(vsock_dev) if start_vm == "no" and vm.is_alive(): - virsh.destroy() + vm.destroy() try: if edit_xml: @@ -244,6 +287,28 @@ def managedsave_restore(): else: result = virsh.start(vm_name, debug=True) utils_test.libvirt.check_exit_status(result, expect_error=False) + elif guest_user: + libvirt_version.is_libvirt_feature_supported(params) + if not utils_package.package_install(["libvirt-ssh-proxy"]): + test.cancel("Failed to install libvirt-ssh-proxy on host") + + vmxml.add_device(vsock_dev) + vmxml.sync() + logging.debug(vmxml) + vm.start() + vm_ip = vm.wait_for_get_address(0, timeout=60) + vm.prepare_guest_agent() + add_guest_user(guest_user, guest_user_passwd) + ssh_key.setup_ssh_key(vm_ip, guest_user, guest_user_passwd) + + if int(check_systemd_version()) < 256: + forward_vsock_to_sshd() + + # For convenienence in automation, Fully disable host key checking. + ssh_proxy_cmd = ("ssh -o StrictHostKeyChecking=no %s@qemu/%s hostname" + % (guest_user, vm_name)) + if process.run(ssh_proxy_cmd, shell=True, ignore_status=True).exit_status != 0: + test.fail("ssh proxy for vsock is not working.") else: session = vm.wait_for_login() session.close() diff --git a/libvirt/tests/src/virtual_disks/at_dt_iscsi_disk.py b/libvirt/tests/src/virtual_disks/at_dt_iscsi_disk.py index 6e2f9fa1991..1333bffc156 100644 --- a/libvirt/tests/src/virtual_disks/at_dt_iscsi_disk.py +++ b/libvirt/tests/src/virtual_disks/at_dt_iscsi_disk.py @@ -8,6 +8,7 @@ from aexpect import ShellError +from avocado.core.exceptions import TestError from avocado.utils import process from virttest import virsh @@ -16,6 +17,7 @@ from virttest.remote import LoginError from virttest.virt_vm import VMError from virttest.utils_test import libvirt +from virttest.utils_libvirt import libvirt_disk from virttest.libvirt_xml import vm_xml from virttest.libvirt_xml import pool_xml from virttest.libvirt_xml.secret_xml import SecretXML @@ -386,13 +388,10 @@ def find_attach_disk(expect=True): # recognize the hotplugged disk on PPC if on_ppc: time.sleep(10) - cmd = "grep %s /proc/partitions" % disk_target - s, o = session.cmd_status_output(cmd) - logging.info("%s output: %s", cmd, o) - session.close() - if s == 0: - found_disk = True - except (LoginError, VMError, ShellError) as e: + disk, _ = libvirt_disk.get_non_root_disk_name(session) + logging.debug("Found new disk in VM as %s", disk) + found_disk = True + except (LoginError, VMError, ShellError, TestError) as e: logging.error(str(e)) if found_disk == expect: logging.debug("Check disk inside the VM PASS as expected") diff --git a/libvirt/tests/src/virtual_disks/startup_policy.py b/libvirt/tests/src/virtual_disks/startup_policy.py index dc3ae6527ca..d77daf46784 100644 --- a/libvirt/tests/src/virtual_disks/startup_policy.py +++ b/libvirt/tests/src/virtual_disks/startup_policy.py @@ -351,6 +351,7 @@ def rename_file(source_file, target_file, revert=False): # Get start,restore configuration parameters. start_error = "yes" == params.get("start_error", "no") restore_error = "yes" == params.get("restore_error", "no") + revert_error = "yes" == params.get("revert_error", "no") virsh_dargs = {'debug': True, 'ignore_status': True} attach_option = params.get("attach_option") @@ -415,6 +416,9 @@ def rename_file(source_file, target_file, revert=False): logging.debug("Attach device throws exception:%s", str(attach_device_exception)) os.remove(media_file) test.error("Attach %s fail" % device_type) + # The guest can restore successfully for optional cdrom disk. + if device_type == "cdrom" and startup_policy == "optional": + restore_error = False # Check update policy operations. if disk_type == "file" and update_policy: vm.start() @@ -445,6 +449,10 @@ def rename_file(source_file, target_file, revert=False): # Step 4. Save the domain normally, then remove the source file # and restore it back + if startup_policy == "optional": + # Restart the guest with optional disk because the previous optional disk will be lost after the above steps + vm.destroy() + vm.start() vm.save_to_file(save_file) rename_file(media_file, media_file_new) result = virsh.restore(save_file, **virsh_dargs) @@ -485,6 +493,10 @@ def rename_file(source_file, target_file, revert=False): vm.start() # Step 4 Save the domain normally, then remove the source file,then restore domain. + if startup_policy == "optional": + # Restart the guest with optional disk because the previous optional disk will be lost after the above steps + vm.destroy() + vm.start() vm.save_to_file(save_file) rename_file(vol_path, vol_path_new) cmd_result = virsh.pool_refresh(pool_name) @@ -500,10 +512,12 @@ def rename_file(source_file, target_file, revert=False): if restore_error: result = virsh.restore(save_file, **virsh_dargs) libvirt.check_exit_status(result) - ret = virsh.snapshot_create_as(vm_name, snapshot_name, **virsh_dargs) + snapshot_options = params.get("snapshot_options", "") % (snapshot_name, target_dev, snapshot_name) + ret = virsh.snapshot_create_as(vm_name, "%s %s" % (snapshot_name, snapshot_options), **virsh_dargs) libvirt.check_exit_status(ret) rename_file(vol_path, vol_path_new) - ret = virsh.snapshot_revert(vm_name, snapshot_name, **virsh_dargs) + result = virsh.snapshot_revert(vm_name, snapshot_name, **virsh_dargs) + libvirt.check_exit_status(result, expect_error=revert_error) # Clean up snapshot. libvirt.clean_up_snapshots(vm_name, domxml=vmxml_backup) finally: diff --git a/libvirt/tests/src/virtual_disks/vhostvdpa_block_backend_type/blockcopy_vhostvdpa_backend_disk.py b/libvirt/tests/src/virtual_disks/vhostvdpa_block_backend_type/blockcopy_vhostvdpa_backend_disk.py new file mode 100644 index 00000000000..a9cf26ae4a8 --- /dev/null +++ b/libvirt/tests/src/virtual_disks/vhostvdpa_block_backend_type/blockcopy_vhostvdpa_backend_disk.py @@ -0,0 +1,73 @@ +from virttest import libvirt_version +from virttest import utils_disk +from virttest import utils_misc +from virttest import utils_vdpa +from virttest import virsh +from virttest.libvirt_xml import vm_xml +from virttest.utils_libvirt import libvirt_disk +from virttest.utils_libvirt import libvirt_vmxml + +VIRSH_ARGS = {'debug': True, 'ignore_status': False} + + +def run(test, params, env): + """ + Verify that blockcopy a disk of vhostvdpa backend can succeed + """ + libvirt_version.is_libvirt_feature_supported(params) + disk_attrs = eval(params.get("disk_attrs", "{}")) + bc_disk_attrs = eval(params.get("bc_disk_attrs", "{}")) + disk_target = params.get("disk_target", "vdb") + + vm_name = params.get("main_vm") + vm = env.get_vm(vm_name) + + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + bkxml = vmxml.copy() + + try: + test.log.info("TEST_STEP: Prepare two simulated vhost-vdpa disks on host.") + test_env_obj = utils_vdpa.VDPASimulatorTest(sim_dev_module="vdpa_sim_blk", mgmtdev="vdpasim_blk") + test_env_obj.setup(dev_num=2) + + test.log.info("TEST_STEP: Define a VM with vhost-vdpa disk.") + vm_xml.VMXML.set_memoryBacking_tag(vm_name, access_mode="shared", hpgs=False) + libvirt_vmxml.modify_vm_device(vm_xml.VMXML.new_from_dumpxml(vm_name), "disk", disk_attrs, 1) + vm.start() + vm_session = vm.wait_for_login() + + test.log.info("TEST_STEP: Check r/w operations on vhostvdpa disk.") + new_disk = libvirt_disk.get_non_root_disk_name(vm_session)[0] + utils_disk.mount(f"/dev/{new_disk}", "/mnt", session=vm_session) + before_bc_string = utils_misc.generate_random_string(8) + cmd_in_vm = "echo {0} >> /mnt/test ;sync; grep {0} /mnt/test".format(before_bc_string) + vm_session.cmd(cmd_in_vm) + + test.log.info("TEST_STEP: Blockcopy the vhostvdpa disk to a new vhostdisk location.") + bc_xml_obj = libvirt_vmxml.create_vm_device_by_type("disk", bc_disk_attrs) + bc_options = params.get("bc_options").format(bc_xml_obj.xml) + virsh.blockcopy(vm_name, disk_target, "", options=bc_options, **VIRSH_ARGS) + + test.log.info("TEST_STEP: Check VM's xml.") + vdpa_device = vm_xml.VMXML.new_from_dumpxml(vm.name)\ + .devices.by_device_tag("disk")[-1] + vdpa_dev_attrs = vdpa_device.fetch_attrs() + test.log.debug(vdpa_dev_attrs) + vdpa_dev_source = vdpa_dev_attrs["source"]["attrs"].get("dev") + exp_dev_source = bc_disk_attrs["source"]["attrs"].get("dev") + if vdpa_dev_source != exp_dev_source: + test.fail("Incorrect disk dev after blockcopy! Expected: '%s', " + "Actual: '%s'." % (exp_dev_source, vdpa_dev_source)) + + test.log.info("TEST_STEP: Check r/w operations on vhostvdpa disk after blockcopy") + vm_session = vm.wait_for_login() + utils_disk.mount(f"/dev/{new_disk}", "/mnt", session=vm_session) + cmd_in_vm = "grep {0} /mnt/test".format(before_bc_string) + vm_session.cmd(cmd_in_vm) + after_bc_string = utils_misc.generate_random_string(8) + cmd_in_vm = "echo {0} >> /mnt/test ;sync; grep {0} /mnt/test".format(after_bc_string) + vm_session.cmd(cmd_in_vm) + + finally: + bkxml.sync() + test_env_obj.cleanup() diff --git a/libvirt/tests/src/virtual_disks/vhostvdpa_block_backend_type/define_start_vm_with_multi_vhostvdpa_backend_disks.py b/libvirt/tests/src/virtual_disks/vhostvdpa_block_backend_type/define_start_vm_with_multi_vhostvdpa_backend_disks.py new file mode 100644 index 00000000000..d26b545dc4a --- /dev/null +++ b/libvirt/tests/src/virtual_disks/vhostvdpa_block_backend_type/define_start_vm_with_multi_vhostvdpa_backend_disks.py @@ -0,0 +1,45 @@ +from virttest import libvirt_version +from virttest import utils_vdpa +from virttest.libvirt_xml import vm_xml +from virttest.utils_libvirt import libvirt_disk +from virttest.utils_libvirt import libvirt_vmxml + +VIRSH_ARGS = {'debug': True, 'ignore_status': False} + + +def run(test, params, env): + """ + Verify that a vm can have more than one vhost-vdpa backend disks, + and both the two disks can be successfully written to/read from. + """ + libvirt_version.is_libvirt_feature_supported(params) + disk_attrs = eval(params.get("disk_attrs", "{}")) + disk2_attrs = eval(params.get("disk2_attrs", "{}")) + + vm_name = params.get("main_vm") + vm = env.get_vm(vm_name) + + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + bkxml = vmxml.copy() + + try: + test.log.info("TEST_STEP: Define a VM with vhost-vdpa disk.") + test_env_obj = utils_vdpa.VDPASimulatorTest(sim_dev_module="vdpa_sim_blk", mgmtdev="vdpasim_blk") + test_env_obj.setup(dev_num=2) + vm_xml.VMXML.set_memoryBacking_tag(vm_name, access_mode="shared", hpgs=False) + libvirt_vmxml.modify_vm_device(vm_xml.VMXML.new_from_dumpxml(vm_name), "disk", disk_attrs, 1) + libvirt_vmxml.modify_vm_device(vm_xml.VMXML.new_from_dumpxml(vm_name), "disk", disk2_attrs, 2) + + vm.start() + vm_session = vm.wait_for_login() + + test.log.info("TEST_STEP: Check r/w operations on vhost-vdpa disk.") + new_disks = libvirt_disk.get_non_root_disk_names(vm_session) + vm_session.close() + for disk in new_disks: + if not libvirt_disk.check_virtual_disk_io(vm, disk[0]): + test.fail("Failed to check disk io for %s!" % disk[0]) + + finally: + bkxml.sync() + test_env_obj.cleanup() diff --git a/libvirt/tests/src/virtual_disks/vhostvdpa_block_backend_type/define_start_vm_with_vhostvdpa_backend_disk.py b/libvirt/tests/src/virtual_disks/vhostvdpa_block_backend_type/define_start_vm_with_vhostvdpa_backend_disk.py new file mode 100644 index 00000000000..f4cd20b5cb3 --- /dev/null +++ b/libvirt/tests/src/virtual_disks/vhostvdpa_block_backend_type/define_start_vm_with_vhostvdpa_backend_disk.py @@ -0,0 +1,75 @@ +from virttest import libvirt_version +from virttest import utils_vdpa +from virttest import virsh +from virttest.libvirt_xml import vm_xml +from virttest.utils_libvirt import libvirt_disk +from virttest.utils_libvirt import libvirt_vmxml +from virttest.utils_test import libvirt + +VIRSH_ARGS = {'debug': True, 'ignore_status': False} + + +def run(test, params, env): + """ + Verify that vm can be defined and started with vhost-vdpa backend disk, + and disk I/O in guest can work + """ + libvirt_version.is_libvirt_feature_supported(params) + disk_attrs = eval(params.get("disk_attrs", "{}")) + without_shared_memory = "yes" == params.get("without_shared_memory", "no") + define_error = "yes" == params.get("define_error", "no") + start_error = "yes" == params.get("start_error", "no") + vm_name = params.get("main_vm") + vm = env.get_vm(vm_name) + + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + bkxml = vmxml.copy() + + try: + test.log.info("TEST_STEP: Define a VM with vhostvdpa disk.") + test_env_obj = utils_vdpa.VDPASimulatorTest(sim_dev_module="vdpa_sim_blk", mgmtdev="vdpasim_blk") + test_env_obj.setup() + if not without_shared_memory: + vm_xml.VMXML.set_memoryBacking_tag(vm_name, access_mode="shared", hpgs=False) + disk_dev = libvirt_vmxml.create_vm_device_by_type("disk", disk_attrs) + vmxml_new = vm_xml.VMXML.new_from_dumpxml(vm_name) + vmxml_new.add_device(disk_dev) + + test.log.debug(f'VMXML of {vm_name}:\n{vmxml_new}') + cmd_result = virsh.define(vmxml_new.xml, debug=True) + libvirt.check_exit_status(cmd_result, define_error) + if define_error: + return + + test.log.info("TEST_STEP: Start the VM.") + cmd_result = virsh.start(vm_name) + libvirt.check_exit_status(cmd_result, start_error) + if start_error: + return + vm_session = vm.wait_for_login() + + test.log.info("TEST_STEP: Check VM's xml.") + vdpa_device = vm_xml.VMXML.new_from_dumpxml(vm.name)\ + .devices.by_device_tag("disk")[-1] + vdpa_dev_attrs = vdpa_device.fetch_attrs() + test.log.debug(vdpa_dev_attrs) + for k, v in disk_attrs.items(): + if k == "source": + act_dev = vdpa_dev_attrs[k]["attrs"].get("dev") + exp_dev = v["attrs"]["dev"] + test.log.debug(f"Actual dev: {act_dev}") + test.log.debug(f"Expected dev: {exp_dev}") + if act_dev != exp_dev: + test.fail("Incorrect disk dev!") + elif vdpa_dev_attrs[k] != v: + test.fail("Failed to get expected disk attributes(%s) in live xml!" + "It should be %s." % (vdpa_dev_attrs[k], v)) + + test.log.info("TEST_STEP: Check r/w operations on vhostvdpa disk.") + new_disk = libvirt_disk.get_non_root_disk_name(vm_session)[0] + if not libvirt_disk.check_virtual_disk_io(vm, new_disk): + test.fail("Failed to check disk io for %s!" % new_disk) + + finally: + bkxml.sync() + test_env_obj.cleanup() diff --git a/libvirt/tests/src/virtual_disks/vhostvdpa_block_backend_type/define_start_vms_with_same_vhostvdpa_backend_disk.py b/libvirt/tests/src/virtual_disks/vhostvdpa_block_backend_type/define_start_vms_with_same_vhostvdpa_backend_disk.py new file mode 100644 index 00000000000..cff4b87a732 --- /dev/null +++ b/libvirt/tests/src/virtual_disks/vhostvdpa_block_backend_type/define_start_vms_with_same_vhostvdpa_backend_disk.py @@ -0,0 +1,48 @@ +from virttest import libvirt_version +from virttest import utils_vdpa +from virttest import virsh +from virttest.libvirt_xml import vm_xml +from virttest.utils_libvirt import libvirt_vmxml +from virttest.utils_test import libvirt + +VIRSH_ARGS = {'debug': True, 'ignore_status': False} + + +def run(test, params, env): + """ + Verify that if two vms use the same vhost-vdpa backend, the second one will + fail to start + """ + libvirt_version.is_libvirt_feature_supported(params) + + disk_attrs = eval(params.get("disk_attrs", "{}")) + err_msg = params.get("err_msg") + vms = params.get('vms').split() + vm_list = [env.get_vm(v_name) for v_name in vms] + vm, vm2 = vm_list[:2] + + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm.name) + vm2_xml_backup = vm_xml.VMXML.new_from_inactive_dumpxml(vm2.name) + + bkxml = vmxml.copy() + + try: + test.log.info("TEST_STEP: Define two VMs with the same vhostvdpa disk.") + test_env_obj = utils_vdpa.VDPASimulatorTest( + sim_dev_module="vdpa_sim_blk", mgmtdev="vdpasim_blk") + test_env_obj.setup() + for _vm in [vm, vm2]: + vm_xml.VMXML.set_memoryBacking_tag( + _vm.name, access_mode="shared", hpgs=False) + libvirt_vmxml.modify_vm_device( + vm_xml.VMXML.new_from_dumpxml(_vm.name), "disk", disk_attrs, 1) + test.log.debug(f'VMXML of {_vm.name}:\n{virsh.dumpxml(_vm.name).stdout_text}') + + test.log.info("TEST_STEP: Start the VMs.") + vm.start() + cmd_result = virsh.start(vm2.name) + libvirt.check_result(cmd_result, err_msg) + finally: + bkxml.sync() + vm2_xml_backup.sync() + test_env_obj.cleanup() diff --git a/libvirt/tests/src/virtual_disks/vhostvdpa_block_backend_type/hotplug_vhostvdpa_backend_disk.py b/libvirt/tests/src/virtual_disks/vhostvdpa_block_backend_type/hotplug_vhostvdpa_backend_disk.py new file mode 100644 index 00000000000..869e2d19780 --- /dev/null +++ b/libvirt/tests/src/virtual_disks/vhostvdpa_block_backend_type/hotplug_vhostvdpa_backend_disk.py @@ -0,0 +1,72 @@ +from virttest import libvirt_version +from virttest import utils_vdpa +from virttest import virsh +from virttest.libvirt_xml import vm_xml +from virttest.utils_libvirt import libvirt_disk +from virttest.utils_libvirt import libvirt_vmxml +from virttest.utils_test import libvirt + +VIRSH_ARGS = {'debug': True, 'ignore_status': False} + + +def run(test, params, env): + """ + Hotplug/unplug vhost-vdpa backend disk + """ + libvirt_version.is_libvirt_feature_supported(params) + disk_attrs = eval(params.get("disk_attrs", "{}")) + status_error = "yes" == params.get("status_error", "no") + vm_name = params.get("main_vm") + vm = env.get_vm(vm_name) + + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + bkxml = vmxml.copy() + + try: + test.log.info("TEST_SETUP: Prepare a simulated vhost-vdpa disk on host.") + test_env_obj = utils_vdpa.VDPASimulatorTest( + sim_dev_module="vdpa_sim_blk", mgmtdev="vdpasim_blk") + test_env_obj.setup() + + test.log.info("TEST_STEP: Define a VM with shared memory.") + vm_xml.VMXML.set_memoryBacking_tag(vm_name, access_mode="shared", hpgs=False) + vm.start() + vm_session = vm.wait_for_login() + + test.log.info("TEST_STEP: Hotplug a vhost-vdpa disk to VM.") + disk_dev = libvirt_vmxml.create_vm_device_by_type("disk", disk_attrs) + cmd_result = virsh.attach_device(vm_name, disk_dev.xml, debug=True) + libvirt.check_exit_status(cmd_result, status_error) + if status_error: + return + + test.log.info("TEST_STEP: Check VM's xml.") + vdpa_device = vm_xml.VMXML.new_from_dumpxml(vm.name)\ + .devices.by_device_tag("disk")[-1] + vdpa_dev_attrs = vdpa_device.fetch_attrs() + test.log.debug(vdpa_dev_attrs) + for k, v in disk_attrs.items(): + if k == "source": + act_dev = vdpa_dev_attrs[k]["attrs"].get("dev") + exp_dev = v["attrs"]["dev"] + if act_dev != exp_dev: + test.fail("Incorrect disk dev! Expected: %s, Actual: %s." + % (exp_dev, act_dev)) + elif vdpa_dev_attrs[k] != v: + test.fail("Failed to get expected disk attributes(%s) in live xml!" + "It should be %s." % (vdpa_dev_attrs[k], v)) + + test.log.info("TEST_STEP: Check r/w operations on vhostvdpa disk.") + new_disk = libvirt_disk.get_non_root_disk_name(vm_session)[0] + if not libvirt_disk.check_virtual_disk_io(vm, new_disk): + test.fail("Failed to check disk io for %s!" % new_disk) + + test.log.info("TEST_STEP: Hotunplug a vhost-vdpa disk from VM.") + target_dev = disk_attrs['target']['dev'] + virsh.detach_disk(vm_name, target_dev, **VIRSH_ARGS) + vm_disks = vm_xml.VMXML.new_from_dumpxml(vm.name).devices.by_device_tag("disk") + if len(vm_disks) != 1: + test.fail("There should be only one disk but got %s." % vm_disks) + finally: + bkxml.sync() + test_env_obj.cleanup() diff --git a/libvirt/tests/src/virtual_disks/vhostvdpa_block_backend_type/nodedev_vhostvdpa_disk.py b/libvirt/tests/src/virtual_disks/vhostvdpa_block_backend_type/nodedev_vhostvdpa_disk.py new file mode 100644 index 00000000000..8543a75eb84 --- /dev/null +++ b/libvirt/tests/src/virtual_disks/vhostvdpa_block_backend_type/nodedev_vhostvdpa_disk.py @@ -0,0 +1,51 @@ +from virttest import libvirt_version +from virttest import utils_vdpa +from virttest import virsh +from virttest.libvirt_xml import nodedev_xml + +VIRSH_ARGS = {'debug': True, 'ignore_status': False} + + +def run(test, params, env): + """ + Verify nodedev related operations against vhost-vdpa disk. + """ + def check_nodedev_xml(dev_name): + """ + Check nodedev xml for vhost-vdpa device. + + :param dev_name: Device name + """ + test.log.info(f"TEST_STEP: Check xml for node device - {dev_name}.") + nodexml = nodedev_xml.NodedevXML.new_from_dumpxml(dev_name) + nodedev_attrs = nodexml.fetch_attrs() + nodedev_attrs.update({"cap": {"chardev": nodexml.cap.get_chardev()}}) + idx = nodedev_attrs["path"][-1] + exp_attrs = {"driver_name": "vhost_vdpa", "cap_type": "vdpa", + "cap": {"chardev": f"/dev/vhost-vdpa-{idx}"}} + test.log.debug(f"Exptected: {exp_attrs}") + test.log.debug(f"Actual: {nodedev_attrs}") + for k, v in exp_attrs.items(): + if nodedev_attrs.get(k) != v: + test.fail("Failed to check node device xml!") + + libvirt_version.is_libvirt_feature_supported(params) + + try: + test.log.info("TEST_STEP: Prepare vhost-vdpa disks.") + test_env_obj = utils_vdpa.VDPASimulatorTest( + sim_dev_module="vdpa_sim_blk", mgmtdev="vdpasim_blk") + test_env_obj.setup(dev_num=2) + + test.log.info("TEST_STEP: List node devices with vdpa capability on host.") + vdpa_devices = [d for d in test_env_obj.get_vdpa_dev_info()['dev']] + devs = virsh.nodedev_list( + cap="vdpa", **VIRSH_ARGS).stdout_text.strip().splitlines() + if devs != ["vdpa_" + d for d in vdpa_devices]: + test.fail("Failed to get vdpa devices!") + + for dev_name in devs: + check_nodedev_xml(dev_name) + + finally: + test_env_obj.cleanup() diff --git a/libvirt/tests/src/virtual_disks/vhostvdpa_block_backend_type/vm_lifecycle_vhostvdpa_backend_disk.py b/libvirt/tests/src/virtual_disks/vhostvdpa_block_backend_type/vm_lifecycle_vhostvdpa_backend_disk.py new file mode 100644 index 00000000000..b3620271bc6 --- /dev/null +++ b/libvirt/tests/src/virtual_disks/vhostvdpa_block_backend_type/vm_lifecycle_vhostvdpa_backend_disk.py @@ -0,0 +1,85 @@ +import os +from virttest import data_dir +from virttest import libvirt_version +from virttest import utils_disk +from virttest import utils_vdpa +from virttest import virsh +from virttest.libvirt_xml import vm_xml +from virttest.utils_libvirt import libvirt_disk +from virttest.utils_libvirt import libvirt_vmxml + +VIRSH_ARGS = {'debug': True, 'ignore_status': False} + + +def run(test, params, env): + """ + Verify vm lifecycle operations + """ + def check_disk_io(vm_session, disk, cmd_in_vm, mount_dst="/mnt", is_mount=True): + """ + Check disk I/O in guest + + :param vm_session: vm session + :param disk: disk name + :param cmd_in_vm: cmd to check disk io + :param mount_dst: mount destination + :param is_mount: Whether the disk is mounted + """ + if is_mount: + if not utils_disk.is_mount(f"/dev/{disk}", mount_dst, session=vm_session): + test.fail("%s should be mounted!" % disk) + else: + utils_disk.mount(f"/dev/{disk}", mount_dst, session=vm_session) + vm_session.cmd(cmd_in_vm) + + libvirt_version.is_libvirt_feature_supported(params) + disk_attrs = eval(params.get("disk_attrs", "{}")) + cmd_in_vm = "d=`date +%s`; echo $d >> /mnt/test ;sync; grep $d /mnt/test" + vm_name = params.get("main_vm") + vm = env.get_vm(vm_name) + + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + bkxml = vmxml.copy() + + try: + test.log.info("TEST_STEP: Define a VM with vhostvdpa disk.") + test_env_obj = utils_vdpa.VDPASimulatorTest( + sim_dev_module="vdpa_sim_blk", mgmtdev="vdpasim_blk") + test_env_obj.setup() + vm_xml.VMXML.set_memoryBacking_tag(vm_name, access_mode="shared", hpgs=False) + libvirt_vmxml.modify_vm_device(vm_xml.VMXML.new_from_dumpxml(vm_name), "disk", disk_attrs, 1) + + test.log.info("TEST_STEP: Start the VM, and check vhostvdpa disk r/w.") + vm.start() + vm_session = vm.wait_for_login() + new_disk = libvirt_disk.get_non_root_disk_name(vm_session)[0] + vm_session.cmd(f"mkfs.ext4 /dev/{new_disk}") + check_disk_io(vm_session, new_disk, cmd_in_vm, is_mount=False) + + test.log.info("TEST_STEP: Save and restore VM, check vhostvdpa disk r/w.") + save_path = os.path.join(data_dir.get_tmp_dir(), vm.name + '.save') + virsh.save(vm.name, save_path, **VIRSH_ARGS) + virsh.restore(save_path, **VIRSH_ARGS) + check_disk_io(vm_session, new_disk, cmd_in_vm) + + test.log.info("TEST_STEP: ManagedSave and Start VM, check vhostvdpa disk r/w.") + virsh.managedsave(vm.name, **VIRSH_ARGS) + virsh.start(vm.name, **VIRSH_ARGS) + check_disk_io(vm_session, new_disk, cmd_in_vm) + + test.log.info("TEST_STEP: Reboot VM, check vhostvdpa disk r/w.") + virsh.reboot(vm.name, **VIRSH_ARGS) + vm_session = vm.wait_for_login() + check_disk_io(vm_session, new_disk, cmd_in_vm, is_mount=False) + + test.log.info("TEST_STEP: Shutdown and start VM, check vhostvdpa disk r/w.") + virsh.shutdown(vm.name, wait_for_event=True, + event_type="disconnected.*(\n.*)*Shutdown Finished.*(\n.*)*Stopped", + **VIRSH_ARGS) + virsh.start(vm.name, **VIRSH_ARGS) + vm_session = vm.wait_for_login() + check_disk_io(vm_session, new_disk, cmd_in_vm, is_mount=False) + utils_disk.umount(f"/dev/{new_disk}", "/mnt", session=vm_session) + finally: + bkxml.sync() + test_env_obj.cleanup() diff --git a/libvirt/tests/src/virtual_disks/virtual_disks_blockresize.py b/libvirt/tests/src/virtual_disks/virtual_disks_blockresize.py new file mode 100644 index 00000000000..e912954266b --- /dev/null +++ b/libvirt/tests/src/virtual_disks/virtual_disks_blockresize.py @@ -0,0 +1,249 @@ +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Copyright Red Hat +# +# SPDX-License-Identifier: GPL-2.0 + +# Author: Chunfu Wen +# + +import logging +import os +import time + +from virttest import libvirt_version +from virttest import virsh +from virttest import virt_vm +from virttest import utils_misc + +from virttest.libvirt_xml import vm_xml, xcepts +from virttest.utils_libvirt import libvirt_disk +from virttest.utils_test import libvirt + +from avocado.utils import process + + +LOG = logging.getLogger('avocado.' + __name__) +cleanup_files = [] + + +def setup_scsi_debug_block_device(): + """ + Setup one scsi_debug block device + + :return: device name + """ + source_disk = libvirt.create_scsi_disk(scsi_option="", + scsi_size="100") + return source_disk + + +def check_image_virtual_size(image_file, expected_size, test): + """ + Check whether image virtual size queried by qemu-img is matched + + :param image_file: image file path + :param expected_size: expected size + :param test: test case itself + """ + disk_info_dict = utils_misc.get_image_info(image_file) + actual_size_in_bytes = str(disk_info_dict.get("vsize")) + if actual_size_in_bytes != expected_size: + test.fail(f"actual size of block disk is {actual_size_in_bytes}, but expected is : {expected_size}") + + +def create_customized_disk(params, test): + """ + Create one customized disk with related attributes + + :param params: dict wrapped with params + :param test: test case itself + """ + type_name = params.get("type_name") + disk_device = params.get("device_type") + device_target = params.get("target_dev") + device_bus = params.get("target_bus") + device_format = params.get("target_format") + source_file_path = None + source_raw_file_path = params.get("source_raw_file_path") + if source_raw_file_path: + libvirt.create_local_disk("file", source_raw_file_path, "1M", device_format) + cleanup_files.append(source_raw_file_path) + source_file_path = source_raw_file_path + else: + source_file_path = setup_scsi_debug_block_device() + overlay_source_file_path = params.get("overlay_source_file_path") + expected_size = params.get("block_size_in_bytes") + source_dict = {} + + # check block size + check_image_virtual_size(source_file_path, expected_size, test) + + if source_raw_file_path: + source_dict.update({"file": source_file_path}) + else: + source_dict.update({"dev": source_file_path}) + + if overlay_source_file_path: + libvirt.create_local_disk("file", overlay_source_file_path, "100M", device_format) + cleanup_files.append(overlay_source_file_path) + convert_cmd = "qemu-img convert -f qcow2 -O qcow2 %s %s" % (overlay_source_file_path, source_file_path) + process.run(convert_cmd, shell=True, verbose=True, ignore_status=False) + + disk_src_dict = {"attrs": source_dict} + + customized_disk = libvirt_disk.create_primitive_disk_xml( + type_name, disk_device, + device_target, device_bus, + device_format, disk_src_dict, None) + + # Sometimes, slice size can be gotten by command (du -b source_file_path), but here not necessary + disk_slice_attrs = params.get('disk_slice_attrs') + if disk_slice_attrs: + disk_source = customized_disk.source + disk_source.slices = customized_disk.new_slices(**eval(disk_slice_attrs)) + customized_disk.source = disk_source + + LOG.debug("create customized xml: %s", customized_disk) + return customized_disk + + +def check_slice_within_vm(vm, new_disk, slice_value): + """ + Check disk slices attributes in guest internal + + :param vm: vm object + :param new_disk: newly vm disk + :param slice_value: slice value + """ + session = None + try: + session = vm.wait_for_login() + cmd = ("lsblk |grep {0}" + .format(new_disk)) + status, output = session.cmd_status_output(cmd) + LOG.debug("Disk operation in VM:\nexit code:\n%s\noutput:\n%s", + status, output) + return slice_value in output + except Exception as err: + LOG.debug("Error happens when check slices in vm: %s", str(err)) + return False + finally: + if session: + session.close() + + +def check_vm_dumpxml(params, test, expected_attribute=True): + """ + Common method to check source in cdrom device + + :param params: one collective object representing wrapped parameters + :param test: test object + :param expected_attribute: bool indicating whether expected attribute exists or not + """ + vm_name = params.get("main_vm") + disk_vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) + target_dev = params.get('target_dev') + disk = disk_vmxml.get_disk_all()[target_dev] + slices = disk.find('source').find('slices') + if not expected_attribute: + if slices is not None: + test.fail("unexpected slices appear in vm disk xml") + else: + if slices is None: + test.fail("slices can not be found in vm disk xml") + + +def run(test, params, env): + """ + Test resize disk with slices. + + 1.Prepare a vm with block disk + 2.Attach block disk with slice attribute to the vm + 3.Start vm + 4.Resize the block disk + 5.Check resize operations + 6.Check status in VM internal + 7.Detach device + """ + vm_name = params.get("main_vm") + vm = env.get_vm(vm_name) + virsh_dargs = {'debug': True} + + hotplug = "yes" == params.get("virt_device_hotplug") + part_path = "/dev/%s" + + # Skip test if version not match expected one + libvirt_version.is_libvirt_feature_supported(params) + + # Get disk partitions info before hot/cold plug virtual disk + if vm.is_alive(): + vm.destroy(gracefully=False) + + # Backup vm xml + vmxml_backup = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + vmxml = vmxml_backup.copy() + + test_scenario = params.get("test_scenario") + target_bus = params.get("target_bus") + target_dev = params.get('target_dev') + status_error = "yes" == params.get("status_error") + type_name = params.get("type_name") + source_raw_file_path = params.get("source_raw_file_path") + try: + device_obj = create_customized_disk(params, test) + if not hotplug: + vmxml.add_device(device_obj) + vmxml.sync() + vm.start() + vm.wait_for_login() + if hotplug: + virsh.attach_device(vm_name, device_obj.xml, + ignore_status=False, debug=True) + except xcepts.LibvirtXMLError as xml_error: + test.fail("Failed to define VM:\n%s" % str(xml_error)) + except virt_vm.VMStartError as details: + test.fail("VM failed to start." + "Error: %s" % str(details)) + else: + session = vm.wait_for_login() + time.sleep(20) + new_disk, _ = libvirt_disk.get_non_root_disk_name(session) + session.close() + check_vm_dumpxml(params, test, True) + + slice_value = params.get("offset") + check_slice_within_vm(vm, new_disk, slice_value) + + if test_scenario in ["blockresize_save_restore"]: + vm_save = params.get("vm_save") + cleanup_files.append(vm_save) + virsh.save(vm_name, vm_save) + virsh.restore(vm_save) + vm.wait_for_login().close() + + resize_value = params.get("resize_value") + result = virsh.blockresize(vm_name, target_dev, + resize_value, **virsh_dargs) + libvirt.check_exit_status(result, status_error) + if test_scenario in ["not_align_with_multiple_1024"]: + actual_expectd_size = params.get("actual_resize_value") + check_image_virtual_size(source_raw_file_path, actual_expectd_size, test) + + if not status_error: + check_vm_dumpxml(params, test, False) + slice_value = params.get("size_in_mb") + check_slice_within_vm(vm, new_disk, slice_value) + if hotplug: + virsh.detach_device(vm_name, device_obj.xml, flagstr="--live", + debug=True, ignore_status=False) + finally: + if vm.is_alive(): + vm.destroy(gracefully=False) + vmxml_backup.sync() + if type_name in ["block"]: + libvirt.delete_scsi_disk() + for file_path in cleanup_files: + if os.path.exists(file_path): + os.remove(file_path) diff --git a/libvirt/tests/src/virtual_disks/virtual_disks_cdrom_device.py b/libvirt/tests/src/virtual_disks/virtual_disks_cdrom_device.py index 35e4fc54fc6..862a9251b49 100755 --- a/libvirt/tests/src/virtual_disks/virtual_disks_cdrom_device.py +++ b/libvirt/tests/src/virtual_disks/virtual_disks_cdrom_device.py @@ -4,20 +4,27 @@ import re import string import aexpect +import time from avocado.utils import linux_modules from avocado.utils import process +from avocado.utils import service from virttest import libvirt_version from virttest import virt_vm, utils_misc from virttest import virsh from virttest import utils_split_daemons +from virttest import utils_libvirtd from virttest.libvirt_xml import vm_xml, xcepts from virttest.utils_test import libvirt from virttest.utils_libvirt import libvirt_disk +from virttest.utils_config import LibvirtdConfig +from virttest.utils_config import VirtQemudConfig + + LOG = logging.getLogger('avocado.' + __name__) CLEANUP_FILES = [] @@ -452,7 +459,7 @@ def check_scsi_cdrom_hot_eject(vm, params, test): virsh_session = aexpect.ShellSession(virsh.VIRSH_EXEC, auto_close=True) event_cmd = "event --domain %s --event tray-change --loop" % vm.name virsh_session.sendline(event_cmd) - + time.sleep(60) device_target = params.get("target_dev") virsh.change_media(vm.name, device_target, " --eject --live", ignore_status=False, debug=True) @@ -478,6 +485,7 @@ def _get_qemu_state(): # check tray-change event virsh_session.send_ctrl("^C") ret_output = virsh_session.get_stripped_output().replace("\n", "").strip() + LOG.debug("event:\n%s", ret_output) event_matched_opened = r"event 'tray-change' for domain '%s' disk .*opened" % vm.name if not re.search(event_matched_opened, ret_output): @@ -493,6 +501,130 @@ def _get_qemu_state(): test.fail("cdrom disk can not be detached successfully") +def check_empty_source_cdrom(vm, params, test): + """ + Check hotplug empty source cdrom + + :param vm: one object representing VM + :param params: wrapped parameters in dictionary format + :param test: test assert object + """ + vm.wait_for_login().close() + # hotplug cdrom device + device_obj = params.get("cdrom_xml") + virsh.attach_device(vm.name, device_obj.xml, flagstr="--live", ignore_status=False, debug=True) + + # Check cdrom is present in disk xml + check_source_in_cdrom_device(vm, None, test) + + +def check_dropped_changed_events_startuppolicy_backend(vm, params, virsh_session, test): + """ + Check changed event for cdrom, and dropped event for disk + + :param vm: one object representing VM + :param params: wrapped parameters in dictionary format + :param virsh_session: virsh session + :param test: test assert object + """ + # check tray-change event + virsh_session.send_ctrl("^C") + ret_output = virsh_session.get_stripped_output().replace("\n", "").strip() + LOG.debug("dropped and changed events:\n%s", ret_output) + event_keywords = ["changed", "dropped"] + + for keyword in event_keywords: + event_pattern = r"event 'disk-change' for domain '%s' disk .*%s" % (vm.name, keyword) + if not re.search(event_pattern, ret_output): + test.fail("Can not find matched event: %s from event output: %s" % (event_pattern, ret_output)) + + +def create_block_cdrom_disk(params): + """ + + Create one block cdrom device + :param params: dict wrapped with parameter + """ + source_disk = libvirt.create_scsi_disk(scsi_option="", + scsi_size="100") + params.update({'virt_disk_device_source': source_disk}) + + block_cdrom_disk = create_customized_disk(params) + return block_cdrom_disk + + +def check_block_cdrom_log(vm, params, test): + """ + Check matched information in vm.log + + :param vm: one object representing VM + :param params: wrapped parameters in dictionary format + :param test: test assert object + """ + qemu_log = "/var/log/libvirt/qemu/%s.log" % vm.name + libvirt.check_logfile(" tainted: cdrom-passthrough", qemu_log, str_in_log=False) + + +def create_disconnect_audit_cdrom(params): + """ + + Create one file cdrom device + :param params: dict wrapped with parameter + """ + libvirtd_config = VirtQemudConfig() if utils_split_daemons.is_modular_daemon() else LibvirtdConfig() + libvirtd_config.audit_level = 1 + libvirtd_config.audit_logging = 1 + utils_libvirtd.Libvirtd('virtqemud').restart() + + # Clean up audit message in log file + cmd = "truncate -s 0 /var/log/audit/audit.log*" + process.run(cmd, shell=True) + + # ensure audit service is started + service_name = 'auditd' + service_mgr = service.ServiceManager() + status = service_mgr.status(service_name) + LOG.debug('Service status is %s', status) + + if not status: + service_mgr.start(service_name) + + block_cdrom_disk = create_iso_cdrom_disk(params) + return block_cdrom_disk + + +def check_disconnect_audit_cdrom(params, test): + """ + + check audit log when cdrom is disconnected + :param params: dict wrapped with parameter + :param test: test assert object + """ + source_file_path = params.get("virt_disk_device_source") + if os.path.exists(source_file_path): + os.remove(source_file_path) + + def _check_disk_message_from_audit_log(): + """ + Check whether disk related message in /var/log/audit/audit.log + """ + cmd = 'ausearch --start today -m VIRT_RESOURCE -i | grep update' + return process.system(cmd, ignore_status=True, shell=True) + + result = utils_misc.wait_for(lambda: _check_disk_message_from_audit_log(), timeout=30) + if not result: + test.fail("Failed to get expected messages: virt resource update from log file: /var/log/audit/audit.log.") + + +def restore_libvirtd_config(): + """ + restore to previous libvirtd config + """ + libvirtd_config = VirtQemudConfig() if utils_split_daemons.is_modular_daemon() else LibvirtdConfig() + libvirtd_config.restore() + utils_libvirtd.Libvirtd('virtqemud').restart() + + def run(test, params, env): """ Test attach cdrom device with option. @@ -557,6 +689,26 @@ def run(test, params, env): ignore_status=False, debug=True) if backend_device == "block_lun_source": device_obj = create_block_lun_source_disk(params) + if backend_device == "empty_source_cdrom_backend": + device_obj = create_customized_disk(params) + params.update({'cdrom_xml': device_obj}) + if backend_device == "dropped_changed_events_startuppolicy": + # First create cdrom disk, then create one more file disk + device_obj1 = create_customized_disk(params) + vmxml.add_device(device_obj1) + vmxml.sync() + params.update({'virt_disk_device_source': params.get("virt_disk_device_source_second")}) + params.update({'target_dev': "sdd"}) + params.update({'device_type': 'disk'}) + device_obj = create_customized_disk(params) + # start loop to wait for disk change event + virsh_session = aexpect.ShellSession(virsh.VIRSH_EXEC, auto_close=True) + event_cmd = "event --domain %s --event disk-change --loop" % vm.name + virsh_session.sendline(event_cmd) + if backend_device == "block_cdrom_tainted": + device_obj = create_block_cdrom_disk(params) + if backend_device == "disconnect_audit_cdrom_backend": + device_obj = create_disconnect_audit_cdrom(params) if not hotplug: # Sync VM xml. vmxml.add_device(device_obj) @@ -614,6 +766,14 @@ def run(test, params, env): check_cdrom_reboot_reset(vm, params, test) elif backend_device == "scsi_cdrom_hot_eject_backend": check_scsi_cdrom_hot_eject(vm, params, test) + elif backend_device == "empty_source_cdrom_backend": + check_empty_source_cdrom(vm, params, test) + elif backend_device == "dropped_changed_events_startuppolicy": + check_dropped_changed_events_startuppolicy_backend(vm, params, virsh_session, test) + elif backend_device == "block_cdrom_tainted": + check_block_cdrom_log(vm, params, test) + elif backend_device == "disconnect_audit_cdrom_backend": + check_disconnect_audit_cdrom(params, test) finally: # Recover VM. if vm.is_alive(): @@ -624,11 +784,13 @@ def run(test, params, env): for file_path in CLEANUP_FILES: if os.path.exists(file_path): os.remove(file_path) - if backend_device == "change_startuppolicy_cdrom_backend": + if backend_device in ["change_startuppolicy_cdrom_backend", "block_cdrom_tainted"]: # unload scsi_debug module if loaded def _unload(): linux_modules.unload_module("scsi_debug") return True utils_misc.wait_for(_unload, timeout=20, ignore_errors=True) + if backend_device in ["disconnect_audit_cdrom_backend"]: + restore_libvirtd_config() if backend_device == "block_lun_source": process.run("losetup -D", shell=True) diff --git a/libvirt/tests/src/virtual_disks/virtual_disks_ceph.py b/libvirt/tests/src/virtual_disks/virtual_disks_ceph.py index 5e05de2171b..716b411dc15 100755 --- a/libvirt/tests/src/virtual_disks/virtual_disks_ceph.py +++ b/libvirt/tests/src/virtual_disks/virtual_disks_ceph.py @@ -573,6 +573,7 @@ def get_secret_list(): key_opt = "" secret_uuid = None snapshot_path = None + converted_raw_file = "" key_file = os.path.join(TMP_DATA_DIR, "ceph.key") img_file = os.path.join(TMP_DATA_DIR, "%s_test.img" % vm_name) @@ -743,11 +744,19 @@ def get_secret_list(): first_disk = vm.get_first_disk_devices() blk_source = first_disk['source'] # Convert the image to remote storage - disk_cmd = ("rbd -m %s %s info %s 2> /dev/null|| qemu-img convert" - " -O %s %s %s" % (mon_host, key_opt, - disk_src_name, disk_format, - blk_source, disk_path)) - process.run(disk_cmd, ignore_status=False, shell=True) + directory = os.path.dirname(blk_source) + filename_with_extension = os.path.basename(blk_source) + + # Get the file name without extension and the extension + filename, _ = os.path.splitext(filename_with_extension) + converted_raw_file = os.path.join(directory, "%s.raw" % filename) + convert_cmd = ("qemu-img convert" + " -O %s %s %s" % (disk_format, blk_source, converted_raw_file)) + process.run(convert_cmd, ignore_status=False, verbose=True, shell=True) + disk_cmd = ("rbd -m %s %s info %s 2> /dev/null|| rbd -m %s %s import " + " %s %s" % (mon_host, key_opt, disk_src_name, mon_host, key_opt, converted_raw_file, + disk_src_name)) + process.run(disk_cmd, ignore_status=False, verbose=True, shell=True) elif create_volume: vol_params = {"name": vol_name, "capacity": int(vol_cap), @@ -1043,6 +1052,8 @@ def _check_slice_in_xml(): os.remove(key_file) if os.path.exists(img_file): os.remove(img_file) + if converted_raw_file and os.path.exists(converted_raw_file): + os.remove(converted_raw_file) # Clean up volume, pool if vol_name and vol_name in str(virsh.vol_list(pool_name).stdout): virsh.vol_delete(vol_name, pool_name) diff --git a/libvirt/tests/src/virtual_disks/virtual_disks_dasd.py b/libvirt/tests/src/virtual_disks/virtual_disks_dasd.py index ec3acb3f325..e343e05a78b 100644 --- a/libvirt/tests/src/virtual_disks/virtual_disks_dasd.py +++ b/libvirt/tests/src/virtual_disks/virtual_disks_dasd.py @@ -6,7 +6,7 @@ from avocado.core.exceptions import TestError from virttest import virsh -from virttest.utils_zchannels import SubchannelPaths +from virttest.utils_zchannels import SubchannelPaths as paths from virttest.utils_misc import cmd_status_output, wait_for from virttest.libvirt_xml.vm_xml import VMXML @@ -14,6 +14,7 @@ TEST_DASD_ID = None TARGET = "vdb" # suppose guest has only one disk 'vda' +cleanup_actions = [] # Using as lower capital is not the best way to do, but this is just a @@ -28,25 +29,17 @@ def get_partitioned_dasd_path(devid): :param devid: the ccw device id, e.g. 0.0.5200 :return path: absolute path to block device, e.g. '/dev/dasda' """ - paths = SubchannelPaths() - paths.get_info() - device = None - if devid: - device = paths.get_device(devid) - else: - device = paths.get_first_unused_and_safely_removable() - if not device: - raise TestError("Couldn't find dasd device for test") + device = ccw.get_device_info(devid, True) global TEST_DASD_ID TEST_DASD_ID = device[paths.HEADER["Device"]] - enable_disk(TEST_DASD_ID) + try_enable_disk(TEST_DASD_ID) disk_path = get_device_path(TEST_DASD_ID) wait_for(lambda: ccw.format_dasd(disk_path, None), 10, first=1.0) wait_for(lambda: ccw.make_dasd_part(disk_path, None), 10, first=1.0) return disk_path -def enable_disk(disk_id): +def try_enable_disk(disk_id): """ Enables the disk so it can be used @@ -56,8 +49,10 @@ def enable_disk(disk_id): cmd = "chzdev -e %s" % disk_id err, out = cmd_status_output(cmd, shell=True) - if err: - raise TestError("Couldn't enable dasd '%s'. %s" % (disk_id, out)) + if 'already configured' not in out: + cleanup_actions.append(lambda: disable_disk(disk_id)) + if err: + raise TestError("Couldn't enable dasd '%s'. %s" % (disk_id, out)) def disable_disk(disk_id): @@ -155,17 +150,15 @@ def run(test, params, env): devid = params.get("devid") try: + cleanup_actions.append(lambda: vm.destroy()) disk_path = get_partitioned_dasd_path(devid) + attach_disk(vm_name, TARGET, disk_path) session = vm.wait_for_login() check_dasd_partition_table(session, TARGET) detach_disk(vm_name, TARGET) finally: - if vm.is_alive(): - vm.destroy(gracefully=False) - # sync will release attached disk, precondition for disablement - backup_xml.sync() - global TEST_DASD_ID - if TEST_DASD_ID: - disable_disk(TEST_DASD_ID) + cleanup_actions.reverse() + for action in cleanup_actions: + action() diff --git a/libvirt/tests/src/virtual_disks/virtual_disks_datastore.py b/libvirt/tests/src/virtual_disks/virtual_disks_datastore.py new file mode 100644 index 00000000000..7ed35d17dc7 --- /dev/null +++ b/libvirt/tests/src/virtual_disks/virtual_disks_datastore.py @@ -0,0 +1,97 @@ +import os + +from virttest import data_dir +from virttest import libvirt_version +from virttest import utils_disk +from virttest import virsh +from virttest.libvirt_xml import vm_xml +from virttest.utils_libvirt import libvirt_disk +from virttest.utils_libvirt import libvirt_vmxml +from virttest.utils_test import libvirt + +from provider.virtual_disk import disk_base + + +def run(test, params, env): + """ + Start guest with datastore and hotplug disk with datastore. + """ + def prepare_disk(): + """ + Prepare the disk. + + :params return: return the data file of new image. + """ + if with_block: + data_file = libvirt.setup_or_cleanup_iscsi(is_setup=True, is_login=True) + else: + data_file = data_dir.get_data_dir() + '/datastore.img' + libvirt.create_local_disk("file", data_file, "50M", "raw") + return data_file + + def hotplug_disk(data_file_option): + """ + Hotplug disk device. + + :params data_file_option: the option to create image with data file + :params return: return the new image path + """ + if not vm.is_alive(): + vm.start() + _, new_image_path = disk_obj.prepare_disk_obj(disk_type, disk_dict, new_image_path="", + extra=data_file_option) + disk_dict.update({'source': {'attrs': {'file': new_image_path}}}) + disk_dev = libvirt_vmxml.create_vm_device_by_type("disk", disk_dict) + virsh.attach_device(vm_name, disk_dev.xml, debug=True, ignore_status=False, wait_for_event=True) + return new_image_path, disk_dev + + def check_result(): + """ + Check the test result. + """ + if not vm.is_alive(): + vm.start() + vm_session = vm.wait_for_login() + disk_xml = virsh.dumpxml(vm_name, "--xpath //disk", debug=True).stdout_text + if "dataStore" not in disk_xml: + test.fail("Can't get the datastore element automatically!") + test.log.info("TEST_STEP: Do read/write for disk.") + new_disk = libvirt_disk.get_non_root_disk_name(vm_session)[0] + utils_disk.dd_data_to_vm_disk(vm_session, new_disk) + vm_session.close() + + vm_name = params.get("main_vm") + vm = env.get_vm(vm_name) + disk_dict = eval(params.get('disk_dict', '{}')) + disk_type = params.get("disk_type") + with_hotplug = "yes" == params.get("with_hotplug", "no") + with_block = "yes" == params.get("with_block", "no") + libvirt_version.is_libvirt_feature_supported(params) + + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + vmxml_backup = vmxml.copy() + disk_obj = disk_base.DiskBase(test, vm, params) + + try: + test.log.info("TEST_STEP: Prepare the guest.") + data_file = prepare_disk() + data_file_option = params.get("data_file_option") % data_file + if with_hotplug: + test.log.info("TEST_STEP: Hotplug disk with datastore.") + new_image_path, disk_dev = hotplug_disk(data_file_option) + else: + new_image_path = disk_obj.add_vm_disk(disk_type, disk_dict, new_image_path="", + extra=data_file_option) + test.log.info("TEST_STEP: Check the disk dumpxml.") + check_result() + if with_hotplug: + test.log.info("TEST_STEP: Hot-unplug disk.") + virsh.detach_device(vm_name, disk_dev.xml, debug=True, ignore_status=False, + wait_for_event=True) + finally: + vmxml_backup.sync() + if with_block: + libvirt.setup_or_cleanup_iscsi(is_setup=False) + for file in [new_image_path, data_file]: + if os.path.exists(file): + os.remove(file) diff --git a/libvirt/tests/src/virtual_disks/virtual_disks_discard_granularity.py b/libvirt/tests/src/virtual_disks/virtual_disks_discard_granularity.py new file mode 100644 index 00000000000..5a3b1d33f25 --- /dev/null +++ b/libvirt/tests/src/virtual_disks/virtual_disks_discard_granularity.py @@ -0,0 +1,283 @@ +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Copyright Red Hat +# +# SPDX-License-Identifier: GPL-2.0 + +# Author: Chunfu Wen +# + +import logging +import os +import re +import time + +from avocado.utils import process + +from virttest import libvirt_version +from virttest import virsh +from virttest import virt_vm + +from virttest.libvirt_xml import vm_xml, xcepts +from virttest.utils_libvirt import libvirt_disk +from virttest.utils_test import libvirt + +LOG = logging.getLogger('avocado.' + __name__) +cleanup_files = [] + + +def create_customized_disk(params): + """ + Create one customized disk with related attributes + + :param params: dict wrapped with params + :return: disk if create successfully + """ + type_name = params.get("type_name") + disk_device = params.get("device_type") + device_target = params.get("target_dev") + device_bus = params.get("target_bus") + device_format = params.get("target_format") + discard_granularity = params.get("discard_granularity") + source_file_path = params.get("source_file_path") + sock_path = params.get("socket_file") + source_dict = {} + + if source_file_path: + libvirt.create_local_disk("file", source_file_path, 1, device_format) + cleanup_files.append(source_file_path) + source_dict.update({"file": source_file_path}) + elif sock_path: + source_dict.update({"type": "unix", "path": sock_path}) + + disk_src_dict = {"attrs": source_dict} + customized_disk = libvirt_disk.create_primitive_disk_xml( + type_name, disk_device, + device_target, device_bus, + device_format, disk_src_dict, None) + if discard_granularity: + customized_disk.blockio = {'logical_block_size': "512", "discard_granularity": discard_granularity} + LOG.debug("create customized xml: %s", customized_disk) + return customized_disk + + +def create_vhostuser_image_file(vhost_image_path): + """ + Create vhostuser image file + + :param vhost_image_path: image file path + """ + libvirt.create_local_disk("file", vhost_image_path, size="100M") + chown_cmd = "chown qemu:qemu %s" % vhost_image_path + process.run(chown_cmd, ignore_status=False, shell=True) + + +def start_vhost_sock_service(file_path, socket_path): + """ + Start one vhost sock service + + :param file_path: image file path + :param socket_path: socket file path + :return: command output + """ + 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' + % (file_path, socket_path)) + cmd_output = process.run(start_sock_service_cmd, ignore_status=False, shell=True).stdout_text.strip() + ch_seccontext_cmd = "chcon -t svirt_image_t %s" % socket_path + process.run(ch_seccontext_cmd, ignore_status=False, shell=True) + set_bool_mmap_cmd = "setsebool domain_can_mmap_files 1 -P" + process.run(set_bool_mmap_cmd, ignore_status=False, shell=True) + return cmd_output + + +def check_blockio_discard_granularity(vm, new_disk, discard_granularity_in_unit): + """ + Check disk discard granularity in guest internal + + :param vm: vm object + :param new_disk: newly vm disk + :param discard_granularity_in_unit: discard granularity in unit + :return: boolean value indicating whether succeed or not + """ + session = None + try: + session = vm.wait_for_login() + cmd = ("lsblk --discard|grep {0}" + .format(new_disk)) + status, output = session.cmd_status_output(cmd) + LOG.debug("Disk operation in VM:\nexit code:\n%s\noutput:\n%s", + status, output) + return discard_granularity_in_unit in output + except Exception as err: + LOG.debug("Error happens when check disk io in vm: %s", str(err)) + return False + finally: + if session: + session.close() + + +def modify_line_with_pattern(file_path, pattern, replacement): + """ + Modify line with pattern, then write back to file + + :param file_path: file path + :param pattern: matched pattern + :param replacement: replaced content + """ + with open(file_path, 'r') as file: + lines = file.readlines() + for i, line in enumerate(lines): + if re.search(pattern, line): + lines[i] = re.sub(pattern, replacement, line) + break + with open(file_path, 'w') as file: + file.writelines(lines) + + +def check_vm_dumpxml(params, test, expected_attribute=True): + """ + Common method to check source in cdrom device + + :param params: one collective object representing wrapped parameters + :param test: test object + :param expected_attribute: bool indicating whether expected attribute exists or not + """ + vm_name = params.get("main_vm") + disk_vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) + target_dev = params.get('target_dev') + disk = disk_vmxml.get_disk_all()[target_dev] + actual_discard_granularity = disk.find('blockio').get('discard_granularity') + if not expected_attribute: + if actual_discard_granularity is not None: + test.fail("unexpected value for blockio in VM disk XML") + else: + if actual_discard_granularity is None: + test.fail("discard_granularity can not be found in vm disk xml") + else: + expected_discard_granularity = params.get("discard_granularity") + if actual_discard_granularity != expected_discard_granularity: + test.fail("actual discard_granularity: %s is not equal to expected: %s" % (actual_discard_granularity, expected_discard_granularity)) + + +def run(test, params, env): + """ + Test disk with discard_granularity. + + 1.Prepare a vm with discard_granularity disk + 2.Attach the virtual disk to the vm + 3.Start vm + 4.Check discard_granularity in vm + 5.Detach disk device + """ + vm_name = params.get("main_vm") + vm = env.get_vm(vm_name) + + hotplug = "yes" == params.get("virt_device_hotplug") + part_path = "/dev/%s" + + # Skip test if version not match expected one + libvirt_version.is_libvirt_feature_supported(params) + + if vm.is_alive(): + vm.destroy(gracefully=False) + + # Backup vm xml + vmxml_backup = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + vmxml = vmxml_backup.copy() + + test_scenario = params.get("test_scenario") + vhost_source_file_path = params.get("vhost_source_file_path") + discard_granularity_in_unit = params.get("discard_granularity_in_unit") + + vsock_service_id = None + target_bus = params.get("target_bus") + status_error = "yes" == params.get("status_error") + define_error = "yes" == params.get("define_error") + + try: + # For vhost user disk, it need setup socket first + if vhost_source_file_path: + create_vhostuser_image_file(vhost_source_file_path) + socket_path = params.get("socket_file") + vsock_service_id = start_vhost_sock_service(vhost_source_file_path, socket_path) + # For invalid discard granularity test, it need update value accordingly + elif test_scenario in ["failure_vm_tart"]: + params.update({'discard_granularity': params.get('invalid_discard_granularity')}) + + device_obj = create_customized_disk(params) + if test_scenario in ["live_update_discard_granularity"]: + device_obj_backup = device_obj.copy() + new_discard_granularity = params.get('new_discard_granularity') + discard_granularity = params.get('discard_granularity') + pattern = r'discard_granularity="%s"' % discard_granularity + replacement = 'discard_granularity="%s"' % new_discard_granularity + modify_line_with_pattern(device_obj_backup.xml, pattern, replacement) + if not hotplug: + vmxml.add_device(device_obj) + vmxml.sync() + vm.start() + vm.wait_for_login() + if hotplug: + virsh.attach_device(vm_name, device_obj.xml, + ignore_status=False, debug=True) + except xcepts.LibvirtXMLError as xml_error: + if not define_error: + test.fail("Failed to define VM:\n%s" % str(xml_error)) + else: + item_matched = params.get("define_error_msg") + if not re.search(r'%s' % item_matched, str(xml_error)): + test.fail("Get unexpected define error message from: %s" % str(xml_error)) + except virt_vm.VMStartError as details: + if not status_error: + test.fail("VM failed to start." + "Error: %s" % str(details)) + else: + status_error_msg = params.get("status_error_msg") + if not re.search(r'%s' % status_error_msg, str(details)): + test.fail("Get unexpected define error message from: %s" % str(details)) + else: + session = vm.wait_for_login() + time.sleep(20) + new_disk, _ = libvirt_disk.get_non_root_disk_name(session) + session.close() + + if not libvirt_disk.check_virtual_disk_io(vm, new_disk, path=part_path): + test.fail("fail to execute write operations on newly added disk:%s" % new_disk) + if test_scenario in ["live_update_discard_granularity"]: + result = virsh.update_device(vm_name, device_obj_backup.xml, flagstr="--live", + debug=True, ignore_status=True) + error_msg = params.get("error_msg") + libvirt.check_result(result, error_msg) + elif test_scenario in ["boundary_vm_tart"]: + expected_attribute = "yes" == params.get("expected_attribute") + check_vm_dumpxml(params, test, expected_attribute) + else: + if not check_blockio_discard_granularity(vm, new_disk, discard_granularity_in_unit): + test.fail("fail to check discard granularity on newly added disk:%s" % new_disk) + if hotplug: + virsh.detach_device(vm_name, device_obj.xml, flagstr="--live", + debug=True, ignore_status=False) + finally: + if vm.is_alive(): + vm.destroy(gracefully=False) + # Restoring vm + vmxml_backup.sync() + + if vhost_source_file_path: + # Kill all qemu-storage-daemon process on host + process.run("pidof qemu-storage-daemon && killall qemu-storage-daemon", + ignore_status=True, verbose=True, shell=True) + + if vsock_service_id: + stop_vsock_service_cmd = "systemctl stop %s" % vsock_service_id + process.run(stop_vsock_service_cmd, ignore_status=True, verbose=True, shell=True) + # Clean up files + for file_path in cleanup_files: + if os.path.exists(file_path): + os.remove(file_path) 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..57a910c8e4f --- /dev/null +++ b/libvirt/tests/src/virtual_disks/virtual_disks_discard_no_unref.py @@ -0,0 +1,193 @@ +# 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_libvirt import libvirt_disk +from virttest.utils_test import libvirt + +from provider.virtual_disk import disk_base + + +def check_result(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.") + libvirt_disk.check_virtual_disk_io(vm, target_dev) + + +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.") + check_result(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.") + check_result(vm, params, test) + test.log.debug("STEP5: detach disk.") + virsh.detach_device(vm_name, disk_xml.xml, debug=True, + wait_for_event=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 run_test_update_negative(vm, params, test): + """ + Scenario: update device for 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") + expect_error = params.get("expect_error") + + test.log.debug("STEP1: start a guest.") + if not vm.is_alive(): + vm.start() + test.log.debug("STEP2: prepare the disk xml.") + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + disk = vmxml.get_devices(device_type="disk")[0] + disk_driver = disk['driver'] + disk_driver.update({'discard_no_unref': 'on'}) + disk['driver'] = disk_driver + test.log.debug("STEP3: update the disk device.") + result = virsh.update_device(vm_name, disk.xml, debug=True) + libvirt.check_result(result, expect_error) + + +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 attribute. + 2) Define guest with invalid disk discard_no_unref attribute. + 3) Hotplug disk with discard_no_unref attribute. + """ + 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) diff --git a/libvirt/tests/src/virtual_disks/virtual_disks_filedescriptor.py b/libvirt/tests/src/virtual_disks/virtual_disks_filedescriptor.py index 54fc7199b68..3798fe1ede6 100644 --- a/libvirt/tests/src/virtual_disks/virtual_disks_filedescriptor.py +++ b/libvirt/tests/src/virtual_disks/virtual_disks_filedescriptor.py @@ -10,15 +10,12 @@ import logging import os -import platform import shutil import time from avocado.utils import process from virttest import libvirt_version -from virttest import utils_disk -from virttest import utils_misc from virttest import utils_selinux from virttest import virsh from virttest import virt_vm @@ -32,33 +29,6 @@ cleanup_files = [] -def get_added_disks(old_partitions, test, params, env): - """ - Get new virtual disks in VM after disk plug. - - :param old_partitions: already existing partitions in VM - :param test: test object - :param params: one dictionary wrapping parameters - :param env: environment representing running context - :return: New disks/partitions in VM - """ - vm_name = params.get("main_vm") - vm = env.get_vm(vm_name) - session = None - try: - session = vm.wait_for_login() - if platform.platform().count('ppc64'): - time.sleep(10) - added_partitions = utils_disk.get_added_parts(session, old_partitions) - LOG.debug("Newly added partition(s) is: %s", added_partitions) - return added_partitions - except Exception as err: - test.fail("Error happens when get new disk: %s" % str(err)) - finally: - if session: - session.close() - - def create_customized_disk(params): """ Create one customized disk with related attributes @@ -264,7 +234,6 @@ def run(test, params, env): if vm.is_dead(): vm.start() session = vm.wait_for_login() - old_partitions = utils_disk.get_parts_list(session) session.close() if not hotplug: vm.destroy(gracefully=False) @@ -305,13 +274,10 @@ def run(test, params, env): "Error: %s" % str(xml_error)) else: check_disk_file_selinux_label(test, params, "after_start") - utils_misc.wait_for(lambda: get_added_disks(old_partitions, test, params, env), 20) - new_disks = get_added_disks(old_partitions, test, params, env) - if len(new_disks) != 1: - test.fail("Attached 1 virtual disk but got %s." % len(new_disks)) - new_disk = new_disks[0] - if platform.platform().count('ppc64'): - time.sleep(10) + session = vm.wait_for_login() + new_disk, _ = libvirt_disk.get_non_root_disk_name(session) + session.close() + time.sleep(10) if disk_readonly: if libvirt_disk.check_virtual_disk_io(vm, new_disk, path=part_path): test.fail("Expect the newly added disk is not writable, but actually it is") diff --git a/libvirt/tests/src/virtual_disks/virtual_disks_gluster.py b/libvirt/tests/src/virtual_disks/virtual_disks_gluster.py index f404e37f501..8107f648c39 100644 --- a/libvirt/tests/src/virtual_disks/virtual_disks_gluster.py +++ b/libvirt/tests/src/virtual_disks/virtual_disks_gluster.py @@ -231,7 +231,7 @@ def test_pmsuspend(vm_name): virsh.undefine(vm_name, '--nvram', ignore_status=False) if virsh.create(vmxml_for_test.xml, **virsh_dargs).exit_status: vmxml_backup.define() - test.skip("can't create the domain") + test.cancel("can't create the domain") # Run the tests. if pm_enabled: diff --git a/libvirt/tests/src/virtual_disks/virtual_disks_https.py b/libvirt/tests/src/virtual_disks/virtual_disks_https.py new file mode 100644 index 00000000000..ca8595879bd --- /dev/null +++ b/libvirt/tests/src/virtual_disks/virtual_disks_https.py @@ -0,0 +1,91 @@ +from virttest import virsh +from virttest import libvirt_version + +from virttest.libvirt_xml import vm_xml +from virttest.utils_libvirt import libvirt_vmxml +from virttest.utils_test import libvirt +from virttest.utils_libvirtd import Libvirtd +from virttest.utils_config import LibvirtQemuConfig + + +def run(test, params, env): + """ + Start vm and hotplug/unplug https network disk with different options. + + 1. Start vm with/without https network disk. + 2. Hot-unplug https network disk. + 3. Hotplug the https network disk. + """ + def setup_test(): + """ + Prepare a https network disk test environment. + + :param qemu_config: return the qemu config. + """ + qemu_config = LibvirtQemuConfig() + qemu_config.storage_use_nbdkit = 1 + Libvirtd('virtqemud').restart() + return qemu_config + + def prepare_disk(): + """ + Prepare the https network disk. + + :param disk_obj: return the disk object. + """ + network_device = params.get("network_device") + disk_dict = eval(params.get("disk_dict", "{}") % network_device) + disk_obj = libvirt_vmxml.create_vm_device_by_type("disk", disk_dict) + if not with_hotplug: + libvirt.add_vm_device(vmxml, disk_obj) + vmxml.sync() + return disk_obj + + def check_result(disk_in_vm=True): + """ + Check the test result. + + :param disk_in_vm: boolean value to make sure if disk in vm. + """ + if disk_in_vm: + xml_after_adding_device = vm_xml.VMXML.new_from_dumpxml(vm_name) + libvirt_vmxml.check_guest_xml_by_xpaths(xml_after_adding_device, expected_xpaths) + libvirt_vmxml.check_guest_xml(vm_name, cookie_in_dumpxml, + option=" --security-info") + else: + domblklist_result = virsh.domblklist(vm_name, debug=True).stdout_text.strip() + if target_disk in domblklist_result: + test.fail("The target disk %s can't be detached from guest." % target_disk) + + libvirt_version.is_libvirt_feature_supported(params) + vm_name = params.get("main_vm") + vm = env.get_vm(vm_name) + target_disk = params.get("target_disk") + expected_xpaths = eval(params.get("expected_xpaths")) + cookie_in_dumpxml = params.get("cookie_in_dumpxml") + with_hotplug = "yes" == params.get("with_hotplug", "no") + + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + backup_vmxml = vmxml.copy() + + try: + qemu_config = setup_test() + disk_dev = prepare_disk() + test.log.info("TEST_STEP1: Start the guest.") + if not vm.is_alive(): + vm.start() + vm.wait_for_login().close() + test.log.debug("The current guest xml is: %s", virsh.dumpxml(vm_name).stdout_text) + disk_in_vm = not with_hotplug + check_result(disk_in_vm) + if with_hotplug: + test.log.info("TEST_STEP2: Hotplug the disk.") + virsh.attach_device(vm_name, disk_dev.xml, debug=True, ignore_status=False) + check_result() + test.log.info("TEST_STEP3: Hot-unplug the disk.") + virsh.detach_device(vm_name, disk_dev.xml, debug=True, ignore_status=False) + check_result(disk_in_vm=False) + finally: + backup_vmxml.sync() + qemu_config.restore() + Libvirtd('virtqemud').restart() diff --git a/libvirt/tests/src/virtual_disks/virtual_disks_io_error.py b/libvirt/tests/src/virtual_disks/virtual_disks_io_error.py new file mode 100644 index 00000000000..75860eed667 --- /dev/null +++ b/libvirt/tests/src/virtual_disks/virtual_disks_io_error.py @@ -0,0 +1,129 @@ +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Copyright Redhat +# +# SPDX-License-Identifier: GPL-2.0 + +# Author: Nannan Li +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +import os +import re +import subprocess + +from avocado.utils import process + +from virttest import virsh +from virttest import libvirt_version + +from virttest.libvirt_xml import vm_xml +from virttest.libvirt_xml.devices import disk +from virttest.utils_test import libvirt + +virsh_dargs = {"ignore_status": False, "shell": True} + + +def run(test, params, env): + """ + Make disk produce I/O error due to "message", then check the error + in "virsh event", vm log and "virsh dominfo" + + Note: "message" is a kind of I/O error reason. It means that the hypervisor + reported a string description of the I/O error. The errors are usually logged + into the domain log file or the last instance of the error string can be + queried via virDomainGetMessages(). + """ + + def setup_test(): + """ + Prepare one error device mapper。 + """ + test.log.info("Setup env.") + process.run(prepare_file, **virsh_dargs) + # Find a free loop device + global free_loop_dev + free_loop_dev = process.run("losetup --find", **virsh_dargs).stdout_text.strip() + # Setup a loop device and create error device mapper + process.run('losetup %s %s' % (free_loop_dev, device_manager_path), **virsh_dargs) + dm_table = """0 261144 linear %s 0 + 261144 5 error + 261149 787427 linear %s 261139""" % (free_loop_dev, free_loop_dev) + try: + subprocess.run(["sudo", "dmsetup", "create", device_manager], + input=dm_table.encode('utf-8'), stderr=subprocess.PIPE, check=True) + except subprocess.CalledProcessError as e: + test.log.debug("create device manager failed :%s", e.stderr.decode('utf-8')) + + def run_test(): + """ + Attach disk and check error message. + """ + test.log.info("TEST_STEP1: Attach a new disk") + vm.start() + session = vm.wait_for_login() + new_disk = disk.Disk() + new_disk.setup_attrs(**disk_dict) + virsh.attach_device(vm_name, new_disk.xml, flagstr="--current", + wait_for_event=True, event_timeout=100, **virsh_dargs) + + test.log.info("TEST_STEP2: Write file in guest and check I/O error message.") + virsh_session = virsh.EventTracker.start_get_event(vm_name) + try: + output = session.cmd(dd_in_guest) + except Exception as e: + if dd_msg not in str(e): + test.fail("Write data in guest should produce error: %s in %s" % (dd_msg, output)) + else: + test.fail("Except error: in %s" % output) + + test.log.info("TEST_STEP3: Check event output.") + event_output = virsh.EventTracker.finish_get_event(virsh_session) + if not re.search(event_msg, event_output): + test.fail('Not find: %s from event output:%s' % (event_msg, event_output)) + + test.log.info("TEST_STEP4: Check about I/O error in vm log.") + qemu_log = os.path.join('/var/log/libvirt/qemu/', "%s.log" % vm_name) + if not libvirt.check_logfile(guest_log_msg, qemu_log, str_in_log=True): + test.fail('Find unexpected error:%s in log file:%s' % (guest_log_msg, qemu_log)) + + test.log.info("TEST_STEP5: Check about I/O error in virsh domain info.") + dominfo = virsh.dominfo(vm_name, debug=True) + libvirt.check_result(dominfo, expected_match=dominfo_msg) + + def teardown_test(): + """ + Clean data. + """ + test.log.info("TEST_TEARDOWN: Clean up env.") + if session: + session.close() + bkxml.sync() + process.run('sudo losetup -d %s' % free_loop_dev, **virsh_dargs) + process.run('sudo dmsetup remove %s' % device_manager, **virsh_dargs) + if os.path.exists(device_manager_path): + os.remove(device_manager_path) + + libvirt_version.is_libvirt_feature_supported(params) + + vm_name = params.get("main_vm") + vm = env.get_vm(vm_name) + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + bkxml = vmxml.copy() + prepare_file = params.get("prepare_file") + device_manager = params.get("device_manager") + device_manager_path = params.get("device_manager_path") + disk_dict = eval(params.get("disk_dict", "{}")) + dd_in_guest = params.get("dd_in_guest") + dd_msg = params.get("dd_msg") + event_msg = params.get("event_msg") + guest_log_msg = params.get("guest_log_msg") + dominfo_msg = params.get("dominfo_msg") + session = None + + try: + setup_test() + run_test() + + finally: + teardown_test() diff --git a/libvirt/tests/src/virtual_disks/virtual_disks_iothreads_queue.py b/libvirt/tests/src/virtual_disks/virtual_disks_iothreads_queue.py new file mode 100755 index 00000000000..5d6f7414b20 --- /dev/null +++ b/libvirt/tests/src/virtual_disks/virtual_disks_iothreads_queue.py @@ -0,0 +1,360 @@ +import os +import time + +from virttest import data_dir +from virttest import libvirt_version +from virttest import utils_disk +from virttest import virsh + +from virttest.libvirt_xml import vm_xml +from virttest.libvirt_xml.devices.disk import Disk +from virttest.utils_libvirt import libvirt_disk +from virttest.utils_libvirt import libvirt_vmxml +from virttest.utils_test import libvirt + + +def prepare_vm_xml(params, vmxml, test): + """ + Configure the XML definition of the VM + + :param params: dict, test parameters + :param vmxml: VMXML instance + :param test: test object + :return: updated VMXML instance + """ + vm_attrs = eval(params.get("vm_attrs")) + plug_type = params.get("plug_type") + vmxml.setup_attrs(**vm_attrs) + if plug_type == 'coldplug': + disk_dict = eval(params.get("disk_dict", "{}")) + if disk_dict: + libvirt_vmxml.modify_vm_device(vmxml, + 'disk', + dev_dict=disk_dict, + sync_vm=False) + test.log.debug("Updated vm xml is %s", vmxml) + return vmxml + + +def teardown_test(vm, params, vmxml, test): + """ + Clean up the test + + :param params: dict, test parameters + :param vm: VM instance + :param vmxml: VMXML instance + """ + if vm.is_alive(): + virsh.destroy(vm.name) + vmxml.sync() + disks = params.get('remove_disks', []) + for a_disk in disks: + libvirt.delete_local_disk("file", a_disk) + test.log.debug("Remove disk %s", a_disk) + + +def run_common(params, vmxml, test): + """ + Common test steps + + :param params: dict, test parameters + :param vmxml: VMXML instance + :param test: test object + """ + vm_name = params.get("main_vm") + virsh_dargs = {"debug": True, "ignore_status": False} + + test.log.debug("Step: define the vm") + virsh.define(vmxml.xml, **virsh_dargs) + test.log.debug("Step: start the vm") + virsh.start(vm_name, **virsh_dargs) + test.log.debug("After vm is started, " + "vm xml:%s\n", vm_xml.VMXML.new_from_dumpxml(vm_name)) + + +def run_test_define_invalid(vm, params, vmxml, test): + """ + Test vm definition with invalid configurations + + :param vm: vm instance + :param params: dict, test parameters + :param vmxml: VMXML instance + :param test: test object + """ + err_msg = params.get("err_msg") + virsh_dargs = {"debug": True, "ignore_status": True} + test.log.debug("Step: define the vm") + ret = virsh.define(vmxml.xml, **virsh_dargs) + libvirt.check_result(ret, expected_fails=err_msg) + + +def prepare_disk_for_hotplug(params): + """ + Prepare a disk object for hotplugging + + :param params: dict, test parameters + :return Disk: disk object + """ + new_image_name = params.get("new_image_name") + disk_source_path = \ + os.path.join(data_dir.get_data_dir(), new_image_name) + libvirt.create_local_disk("file", path=disk_source_path, + size="1", disk_format='qcow2') + params['remove_disks'] = [disk_source_path] + new_disk_dict = eval(params.get("new_disk_dict") % disk_source_path) + disk_obj = Disk(type_name='file') + disk_obj.setup_attrs(**new_disk_dict) + return disk_obj + + +def verify_hotplugged_disk(vm_name, params, session, old_part_list, test): + """ + Verify the hotplugged disk within the vm and in vm xml + + :param vm_name: str, vm name + :param params: dict, test parameters + :param session: ShellSession instance + :param old_part_list: list, disk partition list + :param test: test object + :return list: added partition list + """ + new_driver_iothreads = eval(params.get("new_driver_iothreads")) + added_part = utils_disk.get_added_parts(session, old_part_list) + if not added_part: + test.fail("Can not find the hotplugged disk in VM") + vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) + disks = vmxml.get_devices('disk') + if len(disks) < 2: + test.fail("Can not find the hotplugged disk in VM xml") + plugged_disk = vmxml.get_devices('disk')[1] + plugged_disk_driver_iothreads = plugged_disk.driver_iothreads.fetch_attrs() + if plugged_disk_driver_iothreads != new_driver_iothreads: + test.fail("Expect the plugged disk driver " + "iothreads to be '%s', " + "but found '%s'" % (new_driver_iothreads, + plugged_disk_driver_iothreads)) + test.log.debug("Verify: the disk driver iothreads information " + "is as expected after hotplugging - PASS") + return added_part + + +def verify_hotunplugged_disk(vm_name, params, added_part, session, test): + """ + Verify the hotplugged disk information within vm and vm xml + + :param vm_name: str, vm name + :param params: dict, test parameters + :param added_part: str, disk newly added, like vdb + :param session: ShellSession instance + :param test: test object + """ + new_target_dev = params.get("new_target_dev") + non_root_disks = libvirt_disk.get_non_root_disk_names(session, ignore_status=True) + if non_root_disks and added_part[0] in non_root_disks: + test.fail("The unplugged disk '%s' is still found in VM" % added_part) + test.log.debug("Verify: Check lsblk in VM after hotunlug the disk - PASS") + + vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) + current_disks = vmxml.get_devices('disk') + for a_disk in current_disks: + if a_disk.target['dev'] == new_target_dev: + test.fail("The hotunplugged disk '%s' is " + "still found in VM XML" % new_target_dev) + test.log.debug("Verify: Check hotplugged disk in " + "VM xml after unhotplug the disk - PASS") + + +def test_with_hotplug(vm, params, vmxml, test): + """ + Test hotplug unplug a disk with driver iothreads to the vm + + :param vm: vm instance + :param params: dict, test parameters + :param vmxml: VMXML instance + :param test: test object + """ + virsh_dargs = {"debug": True, "ignore_status": False} + vm_name = params.get("main_vm") + check_libvirtd_log = params.get("check_libvirtd_log") + new_target_dev = params.get("new_target_dev") + + run_common(params, vmxml, test) + session = vm.wait_for_login() + old_part_list = utils_disk.get_parts_list(session) + + test.log.debug("Step: prepare a disk") + disk_obj = prepare_disk_for_hotplug(params) + + test.log.debug("Step: hotplug the disk to the vm") + virsh.attach_device(vm_name, disk_obj.xml, **virsh_dargs) + time.sleep(20) + added_part = verify_hotplugged_disk(vm_name, + params, + session, + old_part_list, + test) + libvirtd_log_file = os.path.join(test.debugdir, "libvirtd.log") + libvirt.check_logfile(check_libvirtd_log, libvirtd_log_file) + test.log.debug("Verify: Check libvirtd log - PASS") + + test.log.debug("Step: unhotplug the disk from the vm") + virsh.detach_disk(vm_name, new_target_dev, wait_for_event=True, **virsh_dargs) + verify_hotunplugged_disk(vm_name, params, added_part, session, test) + + +def test_with_coldplug(vm, params, vmxml, test): + """ + Test coldplug a disk (define) with driver iothreads to the vm + + :param vm: vm instance + :param params: dict, test parameters + :param vmxml: VMXML instance + :param test: test object + """ + driver_conf = eval(params.get("driver", "{}")) + driver_iothreads_conf = eval(params.get("driver_iothreads", "{}")) + check_qemu_pattern = params.get("check_qemu_pattern") + + run_common(params, vmxml, test) + vmxml = vm_xml.VMXML.new_from_dumpxml(vm.name) + first_disk = vmxml.get_devices('disk')[0] + expect_value = driver_conf.get("queues", '') + if expect_value and first_disk.driver.get("queues") != expect_value: + test.fail("Expect the disk driver " + "'queues' to be '%s', " + "but found '%s'" % (expect_value, + first_disk.driver.get("queues"))) + test.log.debug("Verify: Check disk driver queues number - PASS") + actual_driver_iothreads = first_disk.driver_iothreads.fetch_attrs() + if driver_iothreads_conf and actual_driver_iothreads != driver_iothreads_conf: + test.fail("Expect the disk " + "driver iothreads to be '%s', " + "but found '%s'" % (driver_iothreads_conf, + actual_driver_iothreads)) + test.log.debug("Verify: Check disk driver iothreads - PASS") + if check_qemu_pattern: + libvirt.check_qemu_cmd_line(check_qemu_pattern) + + +def run_test_define_start(vm, params, vmxml, test): + """ + Test define and start vm with specified driver iothreads configuration + + :param vm: vm instance + :param params: dict, test parameters + :param vmxml: VMXML instance + :param test: test object + """ + plug_type = params.get("plug_type") + if plug_type == "coldplug": + test_with_coldplug(vm, params, vmxml, test) + else: + test_with_hotplug(vm, params, vmxml, test) + + +def run_test_update_delete_iothread(vm, params, vmxml, test): + """ + Test to delete an iothread being used by a disk + + :param vm: vm instance + :param params: dict, test parameters + :param vmxml: VMXML instance + :param test: test object + """ + vm_name = params.get("main_vm") + err_msg = params.get("err_msg") + del_iothread_id = params.get("del_iothread_id") + virsh_dargs = {"debug": True, "ignore_status": True} + + run_common(params, vmxml, test) + test.log.debug("Step: delete an iothread") + ret = virsh.iothreaddel(vm_name, del_iothread_id, **virsh_dargs) + libvirt.check_result(ret, expected_fails=err_msg) + + +def run_test_live_update_disk(vm, params, vmxml, test): + """ + Test to live update iothread_vq_mapping of a disk. + + :param vm: vm instance + :param params: dict, test parameters + :param vmxml: VMXML instance + :param test: test object + """ + + def _get_driver_iothreads(vmxml): + """ + Utility function for getting the device object and driver iothreads + + :param vmxml: VMXML instance + :return tuple: device xml object, dict of driver_iothreads + """ + dev_obj, _ = libvirt.get_vm_device(vmxml, "disk") + iothreads = None + if dev_obj.fetch_attrs().get("driver_iothreads") is not None: + iothreads = dev_obj.driver_iothreads + return dev_obj, iothreads + + vm_name = params.get("main_vm") + status_error = "yes" == params.get("status_error", "no") + err_msg = params.get("err_msg") + old_driver_iothreads = eval(params.get("driver_iothreads")) + new_driver_iothreads = eval(params.get("new_driver_iothreads")) + virsh_dargs = {"debug": True, "ignore_status": True} + + run_common(params, vmxml, test) + test.log.debug("Step: update the disk with new driver iothreads") + dev_obj, iothreads = _get_driver_iothreads(vmxml) + iothreads.update(**new_driver_iothreads) + dev_obj.driver_iothreads = iothreads + test.log.debug("The new disk xml is:\n%s", dev_obj) + ret = virsh.update_device(vm_name, dev_obj.xml, **virsh_dargs) + updated_vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) + _, new_iothreads = _get_driver_iothreads(updated_vmxml) + if new_iothreads is None and old_driver_iothreads != {}: + test.fail( + "Expect driver iothreads in the disk " + "to be '%s', but found None" % (old_driver_iothreads) + ) + elif ( + new_iothreads is not None + and new_iothreads.fetch_attrs() != old_driver_iothreads + ): + test.fail( + "Expect driver iothreads in the disk " + "to be '%s', but found '%s'" + % (old_driver_iothreads, new_iothreads.fetch_attrs()) + ) + else: + test.log.debug("Verify: the disk's driver iothreads is not changed - PASS") + libvirt.check_exit_status(ret, status_error) + if err_msg: + libvirt.check_result(ret, expected_fails=err_msg) + + +def run(test, params, env): + """ + Test disk driver iothreads + + 1.Update vm xml using given parameters + 2.Perform test operation and verify checkpoints + 3.Recover test environment + """ + libvirt_version.is_libvirt_feature_supported(params) + vm_name = params.get("main_vm") + vm = env.get_vm(vm_name) + + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + vmxml_backup = vmxml.copy() + test_scenario = params.get("scenario") + case_name = "run_test_%s" % test_scenario + run_test_case = eval(case_name) + try: + if vm.is_alive(): + vm.destroy() + test.log.info("Step: Prepare VM XML") + vmxml = prepare_vm_xml(params, vmxml, test) + run_test_case(vm, params, vmxml, test) + + finally: + teardown_test(vm, params, vmxml_backup, test) diff --git a/libvirt/tests/src/virtual_disks/virtual_disks_multiattributes.py b/libvirt/tests/src/virtual_disks/virtual_disks_multiattributes.py new file mode 100644 index 00000000000..6a9293d422a --- /dev/null +++ b/libvirt/tests/src/virtual_disks/virtual_disks_multiattributes.py @@ -0,0 +1,121 @@ +# Copyright Red Hat +# SPDX-License-Identifier: GPL-2.0 +# Author: Meina Li + +import os + +from avocado.utils import process + +from virttest import data_dir +from virttest import virsh +from virttest.libvirt_xml import vm_xml +from virttest.libvirt_xml.devices import disk +from virttest.utils_libvirt import libvirt_vmxml +from virttest.utils_test import libvirt + +from provider.virtual_disk import disk_base + + +def update_bootable_disk(vm, vmxml, disk_obj, params): + """ + Prepare a guest with multiple disk attributes. + + :params vm: vm instance + :params vmxml: the vm xml + :params disk_obj: the disk objective + :params return: return the image list to delete after test + """ + disk_type = params.get("disk_type") + disk_dict = eval(params.get("disk_dict", "{}")) + disk1_dict = eval(params.get("disk1_dict", "{}")) + disk_target_dev = params.get("disk_target_dev") + dom_iothreads = params.get("dom_iothreads") + bootable_image = disk_obj.get_source_list(vmxml, disk_type, disk_target_dev)[0] + libvirt_vmxml.remove_vm_devices_by_type(vm, "disk") + vmxml = vm_xml.VMXML.new_from_dumpxml(vm.name) + vmxml.iothreads = int(dom_iothreads) + vmxml.sync() + if disk_type == "file": + cmd1 = "echo %s | sed s/qcow2/raw/g" % bootable_image + bootable_raw_image = process.run(cmd1, ignore_status=False, shell=True).stdout_text.strip() + cmd2 = "qemu-img convert -f qcow2 %s -O raw %s" % (bootable_image, bootable_raw_image) + process.run(cmd2, ignore_status=False, shell=True) + disk1_dict.update({'source': {'attrs': {'file': bootable_raw_image}}}) + disk_obj.add_vm_disk(disk_type, disk1_dict, bootable_raw_image) + image_list.append(bootable_raw_image) + if disk_type == "block": + device = libvirt.create_scsi_disk(scsi_option="", scsi_size="10240") + cmd = "qemu-img convert -f qcow2 %s -O raw %s; sync" % (bootable_image, device) + process.run(cmd, ignore_status=False, shell=True) + disk_dict.update({'source': {'attrs': {'dev': device}}}) + disk_add = disk.Disk(disk_dict) + disk_add.setup_attrs(**disk_dict) + vmxml.remove_all_boots() + vmxml.add_device(disk_add) + vmxml.sync() + return image_list + + +def add_second_disk(image_list, disk_obj, params): + """ + Prepare a guest with multiple disk attributes. + + :params disk_obj: the disk objective + :params image_list: get the image of bootable disk + :params return: return the image list to delete after test + """ + disk_type = params.get("disk_type") + disk2_dict = eval(params.get("disk2_dict", "{}")) + if disk_type == "file": + new_image_path = data_dir.get_data_dir() + '/test.img' + libvirt.create_local_disk("file", path=new_image_path, size="500M", disk_format="raw") + disk_obj.add_vm_disk(disk_type, disk2_dict, new_image_path) + image_list.append(new_image_path) + return image_list + + +def run(test, params, env): + """ + This case is to verify starting a guest with file/block disk which has multiple driver attributes. + 1) Prepare a guest with multiple disk attributes. + 2) Start the guest. + 3) Login the guest and read/write disk. + """ + vm_name = params.get("main_vm") + disk_type = params.get("disk_type") + disk_dev = params.get("another_disk_dev") + + vm = env.get_vm(vm_name) + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm.name) + bkxml = vmxml.copy() + disk_obj = disk_base.DiskBase(test, vm, params) + global image_list + image_list = [] + + try: + test.log.info("STEP1: prepare a guest with multiple disk attributes.") + image_list = update_bootable_disk(vm, vmxml, disk_obj, params) + image_list = add_second_disk(image_list, disk_obj, params) + test.log.info("STEP2: start the guest.") + test.log.debug("The current guest xml is: %s" % virsh.dumpxml(vm_name).stdout_text.strip()) + if not vm.is_alive(): + vm.start() + test.log.info("STEP3: login the guest and read/write.") + session = vm.wait_for_login() + if disk_type == "file": + session.cmd("mkfs.ext4 /dev/%s && mount /dev/%s /mnt" % (disk_dev, disk_dev)) + status, output = session.cmd_status_output("dd if=/dev/zero of=/mnt/file bs=1M count=100") + if status: + test.error("Failed to read/write in guest: %s" % output) + else: + test.log.debug("Read/write in guest successfully") + session.close + + finally: + bkxml.sync() + if disk_type == "block": + libvirt.delete_scsi_disk() + if image_list: + for image in image_list: + if os.path.exists(image): + os.remove(image) diff --git a/libvirt/tests/src/virtual_disks/virtual_disks_multidisks.py b/libvirt/tests/src/virtual_disks/virtual_disks_multidisks.py index 45f2b5ddb4d..32f606440d5 100644 --- a/libvirt/tests/src/virtual_disks/virtual_disks_multidisks.py +++ b/libvirt/tests/src/virtual_disks/virtual_disks_multidisks.py @@ -37,6 +37,7 @@ from virttest.libvirt_xml import pool_xml from virttest.staging import lv_utils from virttest.utils_libvirt import libvirt_pcicontr +from virttest.utils_libvirt import libvirt_disk from virttest import libvirt_version @@ -78,6 +79,19 @@ def run(test, params, env): virsh.detach_disk(vm_name, disk.target['dev'], extra='--config', debug=True) + def _delete_scsi_disk(): + """ Helper function for wait_for in finally """ + libvirt.delete_scsi_disk() + cmd = "lsscsi|grep scsi_debug" + s1, _ = utils_misc.cmd_status_output(cmd, + shell=True, + ignore_status=False) + cmd = "lsmod|grep scsi_debug" + s2, _ = utils_misc.cmd_status_output(cmd, + shell=True, + ignore_status=False) + return s1 + s2 == 2 + def check_disk_order(targets_name): """ Check VM disk's order on pci/ccw bus. @@ -389,11 +403,13 @@ def check_vm_block_size(targets_name, log_size, phy_size): logging.info("Checking VM block size...") try: session = vm.wait_for_login() + new_disks = libvirt_disk.get_non_root_disk_names(session) + new_disk_names = [disk_info[0] for disk_info in new_disks] # Here the script needs wait for a while for the guest to # recognize the block on PPC add_sleep() - for target in targets_name: - cmd = "cat /sys/block/%s/queue/" % target + for disk_name in new_disk_names: + cmd = "cat /sys/block/%s/queue/" % disk_name s, o = session.cmd_status_output("%slogical_block_size" % cmd) logging.debug("logical block size in VM:\n%s", o) @@ -412,15 +428,14 @@ def check_vm_block_size(targets_name, log_size, phy_size): logging.error(str(e)) return False - def check_vm_discard(target_name): + def check_vm_discard(): """ Check VM discard value. - - :param target_name. Device target name. """ logging.info("Checking VM discard...") try: session = vm.wait_for_login() + target_name, _ = libvirt_disk.get_non_root_disk_name(session) cmd = ("fdisk -l /dev/{0} && mkfs.ext4 -F /dev/{0} && " "mkdir -p test && mount /dev/{0} test && " "dd if=/dev/zero of=test/file bs=1M count=300 && sync" @@ -503,8 +518,10 @@ def check_bootorder_snapshot(disk_name): snapshot1 = "s1" snapshot2 = "s2" snapshot2_file = os.path.join(data_dir.get_data_dir(), "s2") - ret = virsh.snapshot_create(vm_name, "", **virsh_dargs) - libvirt.check_exit_status(ret) + # Skip internal snapshot for ovmf guest + if "os_firmware" not in vmxml.os.fetch_attrs(): + ret = virsh.snapshot_create(vm_name, "", **virsh_dargs) + libvirt.check_exit_status(ret) ret = virsh.snapshot_create_as(vm_name, "%s --disk-only" % snapshot1, **virsh_dargs) @@ -560,15 +577,14 @@ def check_transient_disk_keyword(): if process.system(cmd, ignore_status=False, shell=True): test.fail("Check transident disk failed") - def check_restart_transient_vm(target_name): + def check_restart_transient_vm(): """ Check VM transient feature. - - :param target_name. Device target name. """ logging.info("Checking VM transident...") try: session = vm.wait_for_login() + target_name, _ = libvirt_disk.get_non_root_disk_name(session) cmd = ("fdisk -l /dev/{0} && mkfs.ext4 -F /dev/{0} && " "mkdir -p /test && mount /dev/{0} /test && " "dd if=/dev/zero of=/test/transient.txt bs=1M count=300 && sync" @@ -1101,19 +1117,25 @@ def check_info_in_libvird_log_file(matchedMsg=None): # For minimal VM xml,it need reconstruct one. if test_minimal_xml: + cpu_model_xml = params.get("cpu_model_xml", "") + aarch64_machine_type = params.get("aarch64_machine_type") + memory_size = params.get("memory_size", "1048576") + curr_mem_size = params.get("curr_mem_size", "1048576") minimal_vm_xml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + machine_type = aarch64_machine_type if aarch64_machine_type else machine first_disk = vm.get_first_disk_devices() first_disk_source = first_disk['source'] minimal_vm_xml_file = minimal_vm_xml.xml minimal_xml_content = """ %s - 1048576 - 1048576 + %s + %s 1 hvm + %s /usr/libexec/qemu-kvm @@ -1122,7 +1144,13 @@ def check_info_in_libvird_log_file(matchedMsg=None): - """ % (vm_name, arch, machine, first_disk_source) + """ % (vm_name, + memory_size, + curr_mem_size, + arch, + machine_type, + cpu_model_xml, + first_disk_source) with open(minimal_vm_xml_file, 'w') as xml_file: xml_file.seek(0) xml_file.truncate() @@ -1350,6 +1378,8 @@ def add_backingstore_element_to_disk_xml(disk_xml): osxml.type = vmxml.os.type osxml.arch = vmxml.os.arch osxml.machine = vmxml.os.machine + if vmxml.os.fetch_attrs().get("os_firmware") == "efi": + osxml.os_firmware = vmxml.os.os_firmware if test_boot_console: osxml.loader = "/usr/share/seabios/bios.bin" osxml.bios_useserial = "yes" @@ -1591,6 +1621,7 @@ def test_device_update_boot_order(disk_type, disk_path, error_msg): # Update disk cdrom/floppy with modified boot order,it expect fail. flopy_error_msg = params.get('flopy_error_msg', "") cdrom_error_msg = params.get('cdrom_error_msg', "") + stderr_output = None try: stderr_output = virsh.update_device(vm_name, addtional_disk.xml, debug=True).stderr_text except Exception as update_device_exception: @@ -1945,7 +1976,7 @@ def test_device_update_boot_order(disk_type, disk_path, error_msg): # Check discard in VM after command. if check_discard: - check_vm_discard(device_targets[0]) + check_vm_discard() # Check pci bridge in VM after command. if check_pci_bridge: @@ -1964,7 +1995,7 @@ def test_device_update_boot_order(disk_type, disk_path, error_msg): vm.wait_for_login() if disk_transient: check_transient_disk_keyword() - check_restart_transient_vm(device_targets[0]) + check_restart_transient_vm() # If we testing hotplug, detach the disk at last. if device_at_dt_disk: for i in list(range(len(disks))): @@ -2108,7 +2139,7 @@ def _check_disk_detach(): del img["disk_dev"] else: if img["format"] == "scsi": - utils_misc.wait_for(libvirt.delete_scsi_disk, + utils_misc.wait_for(_delete_scsi_disk, 120, ignore_errors=True) elif img["format"] == "iscsi" or network_iscsi_baseimg: libvirt.setup_or_cleanup_iscsi(is_setup=False) diff --git a/libvirt/tests/src/virtual_disks/virtual_disks_multipath.py b/libvirt/tests/src/virtual_disks/virtual_disks_multipath.py index 07001dd32c3..b1ee0696109 100644 --- a/libvirt/tests/src/virtual_disks/virtual_disks_multipath.py +++ b/libvirt/tests/src/virtual_disks/virtual_disks_multipath.py @@ -179,6 +179,7 @@ def _verify_multipathd_alive(): attach_option = "" if not hotplug_disk: attach_option = "--config" + time.sleep(15) result = virsh.attach_device(vm_name, disk_xml, flagstr=attach_option, ignore_status=True, debug=True) libvirt.check_exit_status(result, status_error) diff --git a/libvirt/tests/src/virtual_disks/virtual_disks_multivms.py b/libvirt/tests/src/virtual_disks/virtual_disks_multivms.py index aea740128a6..4f58410cf93 100644 --- a/libvirt/tests/src/virtual_disks/virtual_disks_multivms.py +++ b/libvirt/tests/src/virtual_disks/virtual_disks_multivms.py @@ -1,6 +1,7 @@ import os import logging as log import aexpect +import time from avocado.utils import process @@ -11,6 +12,7 @@ from virttest import remote from virttest import utils_disk from virttest import utils_misc +from virttest.utils_libvirt.libvirt_disk import get_non_root_disk_name from virttest.utils_test import libvirt from virttest.libvirt_xml import vm_xml from virttest.libvirt_xml.devices.disk import Disk @@ -36,6 +38,19 @@ def run(test, params, env): 6.Confirm the test result. """ + def _delete_scsi_disk(): + """ Helper function for wait_for in finally """ + libvirt.delete_scsi_disk() + cmd = "lsscsi|grep scsi_debug" + s1, _ = utils_misc.cmd_status_output(cmd, + shell=True, + ignore_status=False) + cmd = "lsmod|grep scsi_debug" + s2, _ = utils_misc.cmd_status_output(cmd, + shell=True, + ignore_status=False) + return s1 + s2 == 2 + def set_vm_controller_xml(vmxml): """ Set VM scsi controller xml. @@ -150,7 +165,7 @@ def get_vm_disk_xml(dev_type, dev_name, **options): is_setup=True, is_login=True, image_size=image_size) logging.debug("iscsi dev name: %s", disk_source) # Format the disk and make the file system. - libvirt.mk_label(disk_source) + libvirt.mk_label(disk_source, "gpt") libvirt.mk_part(disk_source, size="10M") if not utils_misc.wait_for(lambda: "%s1" % disk_source.split("/")[-1] in utils_disk.get_parts_list(), timeout=5): test.fail("Partition %s1 can not be ready" % disk_source) @@ -239,7 +254,8 @@ def get_vm_disk_xml(dev_type, dev_name, **options): test.fail('Failed to hotplug disk device') elif 0 == result and not vms_list[i]['status']: test.fail('Hotplug disk device unexpectedly.') - + time.sleep(5) + added_disk, _ = get_non_root_disk_name(session) # Check disk error_policy option in VMs. if test_error_policy: error_policy = vms_list[i]['disk'].driver["error_policy"] @@ -248,7 +264,7 @@ def get_vm_disk_xml(dev_type, dev_name, **options): if error_policy == "enospace": cmd = ("mount /dev/%s /mnt && dd if=/dev/zero of=/mnt/test" " bs=1M count=2000 2>&1 | grep 'No space left'" - % disk_target) + % added_disk) s, o = session.cmd_status_output(cmd) logging.debug("error_policy in vm0 exit %s; output: %s", s, o) if 0 != s: @@ -258,7 +274,7 @@ def get_vm_disk_xml(dev_type, dev_name, **options): break if session.cmd_status("fdisk -l /dev/%s && mount /dev/%s /mnt; ls /mnt" - % (disk_target, disk_target)): + % (added_disk, added_disk)): session.close() test.fail("Test error_policy: " "failed to mount disk") @@ -266,7 +282,7 @@ def get_vm_disk_xml(dev_type, dev_name, **options): try: session0 = vms_list[0]['vm'].wait_for_login(timeout=10) cmd = ("fdisk -l /dev/%s && mkfs.ext3 -F /dev/%s " - % (disk_target, disk_target)) + % (added_disk, added_disk)) s, o = session.cmd_status_output(cmd) logging.debug("error_policy in vm1 exit %s; output: %s", s, o) session.close() @@ -312,9 +328,10 @@ def _check_error(): test_str = "teststring" # Try to write on vm0. session0 = vms_list[0]['vm'].wait_for_login(timeout=10) + added_disk0, _ = get_non_root_disk_name(session0) cmd = ("fdisk -l /dev/%s && mount /dev/%s /mnt && echo '%s' " "> /mnt/test && umount /mnt" - % (disk_target, disk_target, test_str)) + % (added_disk0, added_disk0, test_str)) s, o = session0.cmd_status_output(cmd) logging.debug("session in vm0 exit %s; output: %s", s, o) if s: @@ -323,7 +340,7 @@ def _check_error(): # Try to read on vm1. cmd = ("fdisk -l /dev/%s && mount /dev/%s /mnt && grep %s" " /mnt/test && umount /mnt" - % (disk_target, disk_target, test_str)) + % (added_disk, added_disk, test_str)) s, o = session.cmd_status_output(cmd) logging.debug("session in vm1 exit %s; output: %s", s, o) if s: @@ -377,7 +394,7 @@ def _check_error(): for img in disks: if 'format' in img: if img["format"] == "scsi": - utils_misc.wait_for(libvirt.delete_scsi_disk, + utils_misc.wait_for(_delete_scsi_disk, 120, ignore_errors=True) elif img["format"] == "iscsi": libvirt.setup_or_cleanup_iscsi(is_setup=False) diff --git a/libvirt/tests/src/virtual_disks/virtual_disks_rerror_policy.py b/libvirt/tests/src/virtual_disks/virtual_disks_rerror_policy.py index fda67c34778..6795f6ec231 100755 --- a/libvirt/tests/src/virtual_disks/virtual_disks_rerror_policy.py +++ b/libvirt/tests/src/virtual_disks/virtual_disks_rerror_policy.py @@ -57,19 +57,19 @@ def create_customized_nbd_disk(params, nbd_server_host): return customized_disk -def operate_guest_disk_after_killing_nbdserver(vm, device_target): +def operate_guest_disk_after_killing_nbdserver(vm): """ Operate guest disk after killing nbd server. :params vm: VM instance - :params device_target: VM device target """ try: session = vm.wait_for_login() + nbd_disk_name, _ = libvirt_disk.get_non_root_disk_name(session) process.run("pidof qemu-nbd && killall qemu-nbd", ignore_status=True, shell=True) # Execute read disk operation - cmd = "dd if=/dev/%s of=file" % device_target + cmd = "dd if=/dev/%s of=file" % nbd_disk_name session.cmd_status_output(cmd) session.close() except (remote.LoginError, virt_vm.VMError, aexpect.ShellError) as e: @@ -89,7 +89,7 @@ def check_dmeg_and_domblkerror(params, vm, test, check_error_msg=True): error_msg = params.get("error_msg") device_target = params.get("target_dev") - operate_guest_disk_after_killing_nbdserver(vm, device_target) + operate_guest_disk_after_killing_nbdserver(vm) def _check_dmeg_msg(error_msg): """ diff --git a/libvirt/tests/src/virtual_disks/virtual_disks_scsi3_persistent_reservation.py b/libvirt/tests/src/virtual_disks/virtual_disks_scsi3_persistent_reservation.py index 992a96213e2..c17ccf61796 100644 --- a/libvirt/tests/src/virtual_disks/virtual_disks_scsi3_persistent_reservation.py +++ b/libvirt/tests/src/virtual_disks/virtual_disks_scsi3_persistent_reservation.py @@ -1,8 +1,10 @@ import logging as log import time import shutil +import os from avocado.utils import service +from avocado.utils import process from virttest import virt_vm from virttest import virsh @@ -143,6 +145,11 @@ def ppc_controller_update(): vmxml_backup = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) try: + # Prepare a /etc/target/pr directory based on BZ1652220 + target_pr = "/etc/target/pr" + if not os.path.exists(target_pr): + process.run("mkdir -p %s" % target_pr, shell=True, ignore_status=False) + # Setup iscsi target blk_dev = libvirt.setup_or_cleanup_iscsi(is_setup=True, is_login=True, @@ -206,3 +213,5 @@ def ppc_controller_update(): libvirt.setup_or_cleanup_iscsi(is_setup=False) # Stop qemu-pr-helper daemon start_or_stop_qemu_pr_helper(is_start=False) + if os.path.exists(target_pr): + shutil.rmtree(target_pr) diff --git a/libvirt/tests/src/virtual_disks/virtual_disks_ssh.py b/libvirt/tests/src/virtual_disks/virtual_disks_ssh.py new file mode 100644 index 00000000000..d1d425e54df --- /dev/null +++ b/libvirt/tests/src/virtual_disks/virtual_disks_ssh.py @@ -0,0 +1,117 @@ +import re +import os + +from virttest import virsh +from virttest import libvirt_version +from virttest import utils_disk +from virttest import data_dir + +from virttest.libvirt_xml import vm_xml +from avocado.utils import process +from virttest.utils_libvirt import libvirt_vmxml, libvirt_disk +from virttest.utils_config import LibvirtQemuConfig +from virttest.utils_libvirtd import Libvirtd + +from provider.virtual_disk import disk_base + + +def run(test, params, env): + """ + Verify start guest and hotplug/unplug ssh network disk. + + 1. Prepare disk xml with ssh network disk. + 2. Start guest with or without network disk based on scenarios. + 3. Hotplug network disk only for hotplugging test scenario. + 4. Check disk in guest. + 5. Hot-unplug network disk if necessary. + """ + def setup_test(): + """ + Prepare a ssh network disk test environment. + + :params qemu_config: return the qemu config. + """ + qemu_config = LibvirtQemuConfig() + qemu_config.storage_use_nbdkit = 1 + Libvirtd('virtqemud').restart() + return qemu_config + + def check_result(disk_in_vm=True): + """ + Check the dumpxml and the nbdkit process. + + :params disk_in_vm: boolean value to make sure if disk in vm. + """ + test.log.info("TEST_STEP: Check the nbdkit process.") + cmd = "ps aux | grep nbdkit | grep -v grep" + nbdkit_process = process.run(cmd, shell=True, ignore_status=True).stdout_text + match_result = re.findall(r"storage.socket", nbdkit_process) + if disk_in_vm and not match_result: + test.fail("Can't find the nbdkit process!") + if not disk_in_vm: + if match_result: + test.fail("Find the nbdkit process unexpectedly!") + else: + test.log.debug("Can't find nbdkit process after hot-unplugging as expect!") + return + + test.log.info("TEST_STEP: Check the vm xml.") + if with_secret_passwd: + expected_xpaths = eval(params.get("expected_xpaths") % + known_hosts_path) + else: + expected_xpaths = eval(params.get("expected_xpaths") % + (known_hosts_path, keyfile)) + xml_after_adding_device = vm_xml.VMXML.new_from_dumpxml(vm_name) + test.log.debug("The current guest xml is: %s", xml_after_adding_device) + libvirt_vmxml.check_guest_xml_by_xpaths(xml_after_adding_device, expected_xpaths) + + test.log.info("TEST_STEP: Do read/write for disk.") + vm_session = vm.wait_for_login() + new_disk = libvirt_disk.get_non_root_disk_name(vm_session)[0] + utils_disk.dd_data_to_vm_disk(vm_session, new_disk) + vm_session.close() + + vm_name = params.get("main_vm") + vm = env.get_vm(vm_name) + disk_type = params.get("disk_type") + disk_dict = eval(params.get("disk_dict", "{}")) + with_hotplug = "yes" == params.get("with_hotplug", "no") + with_secret_passwd = "yes" == params.get("with_secret_passwd", "no") + libvirt_version.is_libvirt_feature_supported(params) + keyfile = os.path.join(data_dir.get_tmp_dir(), "keyfile") + known_hosts_path = os.path.join(data_dir.get_tmp_dir(), "known_hosts") + kwargs = {"keyfile": keyfile, "known_hosts_path": known_hosts_path} + + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm.name) + bkxml = vmxml.copy() + disk_obj = disk_base.DiskBase(test, vm, params) + + try: + qemu_config = setup_test() + if not with_hotplug: + disk_obj.new_image_path = disk_obj.add_vm_disk(disk_type, + disk_dict, + **kwargs) + + test.log.info("TEST_STEP: Start the guest.") + if not vm.is_alive(): + virsh.start(vm_name, debug=True, ignore_status=False) + if with_hotplug: + test.log.info("TEST_STEP: Hotplug the disk to guest.") + disk_dev, disk_obj.new_image_path = \ + disk_obj.prepare_disk_obj(disk_type, disk_dict, **kwargs) + virsh.attach_device(vm_name, disk_dev.xml, debug=True, + ignore_status=False, wait_for_event=True) + check_result() + + if with_hotplug: + test.log.info("TEST_STEP: Hot-unplug the disk from guest.") + virsh.detach_device(vm_name, disk_dev.xml, debug=True, + ignore_status=False, wait_for_event=True) + check_result(disk_in_vm=False) + finally: + qemu_config.restore() + Libvirtd('virtqemud').restart() + bkxml.sync() + disk_obj.cleanup_disk_preparation(disk_type, **kwargs) diff --git a/libvirt/tests/src/virtual_disks/virtual_disks_transient_disk.py b/libvirt/tests/src/virtual_disks/virtual_disks_transient_disk.py index 3d898d56c7a..1ac4d556e6e 100644 --- a/libvirt/tests/src/virtual_disks/virtual_disks_transient_disk.py +++ b/libvirt/tests/src/virtual_disks/virtual_disks_transient_disk.py @@ -66,13 +66,14 @@ def check_share_transient_disk(vms_list): try: test_str = "teststring" - sha_cmd = ("sha1sum /dev/%s" % disk_target) + session0 = vms_list[0]['vm'].wait_for_login(timeout=10) + new_disk0, _ = libvirt_disk.get_non_root_disk_name(session0) + sha_cmd = ("sha1sum /dev/%s" % new_disk0) cmd = ("fdisk -l /dev/%s && mkfs.ext4 -F /dev/%s && mount /dev/%s" " /mnt && echo '%s' > /mnt/test && umount /mnt" - % (disk_target, disk_target, disk_target, test_str)) + % (new_disk0, new_disk0, new_disk0, test_str)) # check on vm0. - session0 = vms_list[0]['vm'].wait_for_login(timeout=10) s, o = session0.cmd_status_output(cmd) logging.debug("session in vm0 exit %s; output: %s", s, o) if s: @@ -85,11 +86,16 @@ def check_share_transient_disk(vms_list): # check on vm1. session = vms_list[1]['vm'].wait_for_login(timeout=10) + new_disk, _ = libvirt_disk.get_non_root_disk_name(session) + sha_cmd = ("sha1sum /dev/%s" % new_disk) vm1_disk_sha1 = session.cmd_output(sha_cmd) if vm0_disk_sha1 == vm1_disk_sha1: session.close() test.fail("Still can find file created in transient disk of vm0") + cmd = ("fdisk -l /dev/%s && mkfs.ext4 -F /dev/%s && mount /dev/%s" + " /mnt && echo '%s' > /mnt/test && umount /mnt" + % (new_disk, new_disk, new_disk, test_str)) s, o = session.cmd_status_output(cmd) logging.debug("session in vm1 exit %s; output: %s", s, o) if s: diff --git a/libvirt/tests/src/virtual_disks/virtual_disks_usb_startuppolicy.py b/libvirt/tests/src/virtual_disks/virtual_disks_usb_startuppolicy.py index 73e522d8f55..3bbcce4dea2 100644 --- a/libvirt/tests/src/virtual_disks/virtual_disks_usb_startuppolicy.py +++ b/libvirt/tests/src/virtual_disks/virtual_disks_usb_startuppolicy.py @@ -1,5 +1,6 @@ import logging import platform +import re import shutil import time @@ -132,6 +133,12 @@ def create_customized_disk(params): vm.start() session = vm.wait_for_login() old_partitions = utils_disk.get_parts_list(session) + # Clean usb partition if existed. + for partitions in old_partitions: + _, output = session.cmd_status_output( + "udevadm info --query=property --name=%s | grep ID_BUS" % (re.sub(r"[\d-]", "", partitions))) + if "ID_BUS=usb" in output and re.findall(r"\d+", partitions): + utils_disk.delete_partition_linux(session, partitions) session.close() vm.destroy(gracefully=False) diff --git a/libvirt/tests/src/virtual_interface/hotplug_mem.py b/libvirt/tests/src/virtual_interface/hotplug_mem.py index 08e654f72b1..e53cfad0566 100644 --- a/libvirt/tests/src/virtual_interface/hotplug_mem.py +++ b/libvirt/tests/src/virtual_interface/hotplug_mem.py @@ -188,7 +188,7 @@ def test_at_memory_to_vm_with_iface(dev_type): new_vmxml.get_current_mem(), new_vmxml.get_current_mem_unit()) + 1073741824 if not check_soft_memlock(expr_memlock): - test.fail("Unalbe to get correct MEMLOCK after VM startup!") + test.fail("Unable to get correct MEMLOCK after VM startup!") logging.info("Hotplug memory device.") mem_dict = eval(params.get('mem_dict', '{}')) @@ -198,7 +198,7 @@ def test_at_memory_to_vm_with_iface(dev_type): expr_memlock += normalize_mem_size( mem_dict['target']['size'], mem_dict['target']['size_unit']) if not check_soft_memlock(expr_memlock): - test.fail("Unalbe to get correct MEMLOCK after attaching a memory " + test.fail("Unable to get correct MEMLOCK after attaching a memory " "device!") def test_at_iface_and_memory(dev_type): @@ -216,7 +216,7 @@ def test_at_iface_and_memory(dev_type): vm.wait_for_serial_login(timeout=240).close() expr_memlock = 67108864 if not check_soft_memlock(expr_memlock): - test.fail("Unalbe to get correct default!") + test.fail("Unable to get correct default!") interface_base.attach_iface_device(vm_name, dev_type, params) @@ -226,7 +226,7 @@ def test_at_iface_and_memory(dev_type): new_vmxml.get_current_mem(), new_vmxml.get_current_mem_unit()) + 1073741824 if not check_soft_memlock(expr_memlock): - test.fail("Unalbe to get correct MEMLOCK after VM startup!") + test.fail("Unable to get correct MEMLOCK after VM startup!") logging.info("Hotplug memory devices.") for mem_attrs in ['mem_dict1', 'mem_dict2']: @@ -237,7 +237,7 @@ def test_at_iface_and_memory(dev_type): expr_memlock += normalize_mem_size( mem_dict['target']['size'], mem_dict['target']['size_unit']) if not check_soft_memlock(expr_memlock): - test.fail("Unalbe to get correct MEMLOCK after attaching a " + test.fail("Unable to get correct MEMLOCK after attaching a " "memory device!") logging.info("Detach a memory device and check memlock.") @@ -251,7 +251,7 @@ def test_at_iface_and_memory(dev_type): test.fail("Detaching mem failed, MEMLOCK should not change!") else: if not check_soft_memlock(expr_memlock): - test.fail("Unalbe to get correct MEMLOCK after detaching a " + test.fail("Unable to get correct MEMLOCK after detaching a " "memory device!") def setup_at_memory_to_vm_with_iface_and_locked_mem(dev_type): @@ -278,7 +278,7 @@ def test_at_memory_to_vm_with_iface_and_locked_mem(dev_type): expr_memlock = normalize_mem_size( new_vmxml.memtune.hard_limit, new_vmxml.memtune.hard_limit_unit) if not check_soft_memlock(expr_memlock): - test.fail("Unalbe to get correct MEMLOCK after VM startup!") + test.fail("Unable to get correct MEMLOCK after VM startup!") check_environment(params) # Variable assignment diff --git a/libvirt/tests/src/virtual_network/attach_detach_device/attach_iface_with_boot_order.py b/libvirt/tests/src/virtual_network/attach_detach_device/attach_iface_with_boot_order.py new file mode 100644 index 00000000000..d0e4e0fedbf --- /dev/null +++ b/libvirt/tests/src/virtual_network/attach_detach_device/attach_iface_with_boot_order.py @@ -0,0 +1,61 @@ +import logging + +from virttest import virsh +from virttest.libvirt_xml import vm_xml +from virttest.utils_libvirt import libvirt_vmxml +from virttest.utils_test import libvirt + +VIRSH_ARGS = {'ignore_status': False, 'debug': True} + +LOG = logging.getLogger('avocado.' + __name__) + + +def run(test, params, env): + """ + Test attach interface with boot order + """ + vm_name = params.get('main_vm') + vm = env.get_vm(vm_name) + status_error = 'yes' == params.get('status_error', 'no') + err_msg = params.get('err_msg') + iface_attrs = eval(params.get('iface_attrs', '{}')) + os_attrs = eval(params.get('os_attrs', '{}')) + disk_attrs = eval(params.get('disk_attrs', '{}')) + + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + bkxml = vmxml.copy() + + try: + vmxml.del_device('interface', by_tag=True) + vmxml.sync() + + if os_attrs: + vmxml.setup_attrs(os=os_attrs) + if disk_attrs: + osxml = vmxml.os + osxml.del_boots() + vmxml.os = osxml + vmxml.sync() + libvirt_vmxml.modify_vm_device(vmxml, 'disk', disk_attrs) + + LOG.debug(f'VMXML of {vm_name}:\n{virsh.dumpxml(vm_name).stdout_text}') + + vm.start() + vm.wait_for_serial_login().close() + + iface = libvirt_vmxml.create_vm_device_by_type( + 'interface', iface_attrs) + LOG.debug(f'Interface to attach:\n{iface}') + + def check_attach(option=''): + at_result = virsh.attach_device(vm_name, iface.xml, flagstr=option, + debug=True) + libvirt.check_exit_status(at_result, status_error) + if err_msg: + libvirt.check_result(at_result, err_msg) + + check_attach() + check_attach('--config') + + finally: + bkxml.sync() diff --git a/libvirt/tests/src/virtual_network/attach_detach_device/attach_mtu_malformed.py b/libvirt/tests/src/virtual_network/attach_detach_device/attach_mtu_malformed.py index d8c9529f5bf..95f8e93e93a 100644 --- a/libvirt/tests/src/virtual_network/attach_detach_device/attach_mtu_malformed.py +++ b/libvirt/tests/src/virtual_network/attach_detach_device/attach_mtu_malformed.py @@ -25,8 +25,8 @@ def run(test, params, env): net_name = 'net_' + rand_id source_net = params.get('source_net', net_name) host_iface = params.get('host_iface') - host_iface = host_iface if host_iface else utils_net.get_net_if( - state='UP')[0] + host_iface = host_iface if host_iface else utils_net.get_default_gateway( + iface_name=True, force_dhcp=True, json=True) iface_attrs = eval(params.get('iface_attrs', '{}')) net_attrs = eval(params.get('net_attrs', '{}')) diff --git a/libvirt/tests/src/virtual_network/attach_detach_device/attach_user_type_iface.py b/libvirt/tests/src/virtual_network/attach_detach_device/attach_user_type_iface.py new file mode 100644 index 00000000000..82199c7f6d5 --- /dev/null +++ b/libvirt/tests/src/virtual_network/attach_detach_device/attach_user_type_iface.py @@ -0,0 +1,116 @@ +import logging + +import aexpect +from virttest import remote +from virttest import utils_net +from virttest import virsh +from virttest.libvirt_xml import vm_xml +from virttest.utils_libvirt import libvirt_unprivileged +from virttest.utils_libvirt import libvirt_vmxml + +from provider.virtual_network import network_base + +VIRSH_ARGS = {'ignore_status': False, 'debug': True} + +LOG = logging.getLogger('avocado.' + __name__) + + +def run(test, params, env): + """ + Test attach interface with user type + """ + root = 'root_user' == params.get('user_type', '') + if root: + vm_name = params.get('main_vm') + vm = env.get_vm(vm_name) + virsh_ins = virsh + else: + vm_name = params.get('unpr_vm_name') + test_user = params.get('test_user', '') + test_passwd = params.get('test_passwd', '') + unpr_vm_args = { + 'username': params.get('username'), + 'password': params.get('password'), + } + vm = libvirt_unprivileged.get_unprivileged_vm(vm_name, test_user, + test_passwd, + **unpr_vm_args) + uri = f'qemu+ssh://{test_user}@localhost/session' + virsh_ins = virsh.Virsh(uri=uri) + host_session = aexpect.ShellSession('su') + remote.VMManager.set_ssh_auth(host_session, 'localhost', test_user, + test_passwd) + host_session.close() + + iface_attrs = eval(params.get('iface_attrs', '{}')) + expect_ipv4 = params.get('expect_ipv4') + expect_ipv6 = params.get('expect_ipv6') + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml( + vm_name, virsh_instance=virsh_ins) + bkxml = vmxml.copy() + + try: + vmxml.del_device('interface', by_tag=True) + vmxml.sync(virsh_instance=virsh_ins) + mac = iface_attrs['mac_address'] + LOG.debug( + f'VMXML of {vm_name}:\n{virsh_ins.dumpxml(vm_name).stdout_text}') + + vm.start() + vm.wait_for_serial_login().close() + + iface = libvirt_vmxml.create_vm_device_by_type( + 'interface', iface_attrs) + LOG.debug(f'Interface to attach:\n{iface}') + + virsh_ins.attach_device(vm_name, iface.xml, **VIRSH_ARGS) + LOG.debug(virsh_ins.dumpxml(vm_name).stdout_text) + + # Check attached xml + iface_at = network_base.get_iface_xml_inst( + vm_name, 'after attached on vm', virsh_ins=virsh_ins) + if iface_at.mac_address != iface.mac_address: + test.fail(f'Mac address of attached iface xml does not match with ' + f'original xml, attach might failed') + + # log in the guest, and check the network function, it works well, + # ip and ping + session = vm.wait_for_serial_login() + vm_iface_info = utils_net.get_linux_iface_info( + mac=mac, session=session) + LOG.debug(f'Interface in vm: {vm_iface_info}') + for addr in vm_iface_info['addr_info']: + if addr['scope'] != 'global': + continue + if addr['family'] == 'inet': + if addr['local'] != expect_ipv4: + test.fail(f'Wrong ipv4 addr: {addr["local"]}') + if addr['family'] == 'inet6': + if not addr['local'].startswith(expect_ipv6): + test.fail(f'Wrong ipv6 addr {addr["local"]}') + + LOG.info('Login vm to check whether the network works well via ping.') + ips = {'outside_ip': params.get('outside_ip')} + network_base.ping_check(params, ips, session, force_ipv4=True) + + # Detach iface + virsh_ins.detach_device( + vm_name, iface.xml, wait_for_event=True, **VIRSH_ARGS) + + # Check iface in vm disappeared + vm_iface_info_unplug = utils_net.get_linux_iface_info( + mac=mac, session=session) + LOG.debug(vm_iface_info_unplug) + if vm_iface_info_unplug is not None: + test.fail(f'iface should be removed, should not found ' + f'{vm_iface_info_unplug} in vm') + + # Check xml disappeared + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml( + vm_name, virsh_instance=virsh_ins) + iface_list = vmxml.devices.by_device_tag('interface') + if len(iface_list): + test.fail('Found interface xml on vm which should be detached:' + f'{iface_list}') + finally: + bkxml.sync(virsh_instance=virsh_ins) diff --git a/libvirt/tests/src/virtual_network/connectivity/connectivity_check_bridge_interface.py b/libvirt/tests/src/virtual_network/connectivity/connectivity_check_bridge_interface.py index 803e3c9fb03..b61e46d4838 100644 --- a/libvirt/tests/src/virtual_network/connectivity/connectivity_check_bridge_interface.py +++ b/libvirt/tests/src/virtual_network/connectivity/connectivity_check_bridge_interface.py @@ -2,9 +2,9 @@ import re from avocado.utils import process - from virttest import utils_misc from virttest import utils_net +from virttest import libvirt_version from virttest import virsh from virttest.libvirt_xml import nwfilter_xml from virttest.libvirt_xml import vm_xml @@ -49,11 +49,12 @@ def run(test, params, env): iface_attrs['source']['bridge'] = bridge_name vm_attrs = eval(params.get('vm_attrs', '{}')) nwfilter_attrs = parse_attrs('nwfilter_attrs', params) - iface_in_vm = params.get('iface_in_vm', 'eno') + iface_in_vm = params.get('iface_in_vm') + iface_in_vm = iface_in_vm if iface_in_vm else 'eno' host_iface = params.get('host_iface') - host_iface = host_iface if host_iface else utils_net.get_net_if( - state="UP")[0] + host_iface = host_iface if host_iface else utils_net.get_default_gateway( + iface_name=True, force_dhcp=True, json=True) bkxmls = list(map(vm_xml.VMXML.new_from_inactive_dumpxml, vms)) @@ -64,22 +65,30 @@ def run(test, params, env): elif bridge_type == 'ovs_br': utils_net.create_ovs_bridge(bridge_name) - if nwfilter_attrs: + if nwfilter_attrs and not libvirt_version.version_compare(8, 0, 0): nwf = nwfilter_xml.NwfilterXML() nwf.setup_attrs(**nwfilter_attrs) virsh.nwfilter_define(nwf.xml, **VIRSH_ARGS) LOG.debug('nwfilter xml:\n' + virsh.nwfilter_dumpxml( nwfilter_attrs['filter_name']).stdout_text) + if libvirt_version.version_compare(8, 0, 0): + if 'filterref' in iface_attrs: + iface_attrs.pop('filterref') + vmxml, ep_vmxml = list(map(vm_xml.VMXML.new_from_inactive_dumpxml, vms)) if vm_attrs: [vmxml_i.setup_attrs(**vm_attrs) for vmxml_i in [vmxml, ep_vmxml]] + mac, ep_mac = list(map(vm_xml.VMXML.get_first_mac_by_name, vms)) + [vmxml_i.del_device('interface', by_tag=True) for vmxml_i in [vmxml, ep_vmxml]] - [libvirt_vmxml.modify_vm_device(vmxml_i, 'interface', iface_attrs) - for vmxml_i in [vmxml, ep_vmxml]] + libvirt_vmxml.modify_vm_device( + vmxml, 'interface', {**iface_attrs, **{'mac_address': mac}}) + libvirt_vmxml.modify_vm_device( + ep_vmxml, 'interface', {**iface_attrs, **{'mac_address': ep_mac}}) [LOG.debug(f'VMXML of {vm_x}:\n{virsh.dumpxml(vm_x).stdout_text}') for vm_x in vms] @@ -87,7 +96,6 @@ def run(test, params, env): [vm_i.start() for vm_i in [vm, ep_vm]] session, ep_session = (vm_inst.wait_for_serial_login() for vm_inst in [vm, ep_vm]) - mac, ep_mac = list(map(vm_xml.VMXML.get_first_mac_by_name, vms)) ips_v4 = network_base.get_test_ips(session, mac, ep_session, ep_mac, net_name=None, diff --git a/libvirt/tests/src/virtual_network/connectivity/connectivity_check_bridge_interface_unprivileged.py b/libvirt/tests/src/virtual_network/connectivity/connectivity_check_bridge_interface_unprivileged.py index f8873524ffb..8098e013dbc 100644 --- a/libvirt/tests/src/virtual_network/connectivity/connectivity_check_bridge_interface_unprivileged.py +++ b/libvirt/tests/src/virtual_network/connectivity/connectivity_check_bridge_interface_unprivileged.py @@ -29,8 +29,8 @@ def run(test, params, env): linux_bridge = 'br_' + rand_id br_conf_file = '/etc/qemu-kvm/bridge.conf' host_iface = params.get('host_iface') - host_iface = host_iface if host_iface else utils_net.get_net_if( - state="UP")[0] + host_iface = host_iface if host_iface else utils_net.get_default_gateway( + iface_name=True, force_dhcp=True, json=True) unpr_user = params.get('unpr_user', 'test_unpr') + rand_id diff --git a/libvirt/tests/src/virtual_network/connectivity/connectivity_check_direct_interface.py b/libvirt/tests/src/virtual_network/connectivity/connectivity_check_direct_interface.py index acfe38f2ecf..79e896aeb4a 100644 --- a/libvirt/tests/src/virtual_network/connectivity/connectivity_check_direct_interface.py +++ b/libvirt/tests/src/virtual_network/connectivity/connectivity_check_direct_interface.py @@ -22,8 +22,8 @@ def run(test, params, env): vm, ep_vm = (env.get_vm(vm_i) for vm_i in vms) outside_ip = params.get('outside_ip') host_iface = params.get('host_iface') - host_iface = host_iface if host_iface else utils_net.get_net_if( - state="UP")[0] + host_iface = host_iface if host_iface else utils_net.get_default_gateway( + iface_name=True, force_dhcp=True, json=True) iface_attrs = eval(params.get('iface_attrs', '{}')) bkxmls = list(map(vm_xml.VMXML.new_from_inactive_dumpxml, vms)) @@ -31,10 +31,14 @@ def run(test, params, env): try: vmxml, ep_vmxml = list( map(vm_xml.VMXML.new_from_inactive_dumpxml, vms)) + mac, ep_mac = list(map(vm_xml.VMXML.get_first_mac_by_name, vms)) [vmxml_i.del_device('interface', by_tag=True) for vmxml_i in [vmxml, ep_vmxml]] - [libvirt_vmxml.modify_vm_device(vmxml_i, 'interface', iface_attrs) - for vmxml_i in [vmxml, ep_vmxml]] + + libvirt_vmxml.modify_vm_device( + vmxml, 'interface', {**iface_attrs, **{'mac_address': mac}}) + libvirt_vmxml.modify_vm_device( + ep_vmxml, 'interface', {**iface_attrs, **{'mac_address': ep_mac}}) [LOG.debug(f'VMXML of {vm_x}:\n{virsh.dumpxml(vm_x).stdout_text}') for vm_x in vms] @@ -42,14 +46,15 @@ def run(test, params, env): [vm_i.start() for vm_i in [vm, ep_vm]] session, ep_session = (vm_inst.wait_for_serial_login() for vm_inst in [vm, ep_vm]) - mac, ep_mac = list(map(vm_xml.VMXML.get_first_mac_by_name, vms)) ips_v4 = network_base.get_test_ips(session, mac, ep_session, ep_mac, net_name=None, - ip_ver='ipv4') + ip_ver='ipv4', + host_iface=host_iface) ips_v6 = network_base.get_test_ips(session, mac, ep_session, ep_mac, net_name=None, - ip_ver='ipv6') + ip_ver='ipv6', + host_iface=host_iface) ips_v4['outside_ip'] = outside_ip ping_check_args = {'host_ping_outside': {'interface': host_iface}} diff --git a/libvirt/tests/src/virtual_network/connectivity/connectivity_check_ethernet_interface.py b/libvirt/tests/src/virtual_network/connectivity/connectivity_check_ethernet_interface.py index d97ad461eb3..3562c4b7740 100644 --- a/libvirt/tests/src/virtual_network/connectivity/connectivity_check_ethernet_interface.py +++ b/libvirt/tests/src/virtual_network/connectivity/connectivity_check_ethernet_interface.py @@ -1,6 +1,7 @@ import logging import aexpect +from avocado.utils import process from virttest import libvirt_version from virttest import remote from virttest import utils_misc @@ -11,6 +12,7 @@ from virttest.utils_libvirt import libvirt_vmxml from virttest.utils_test import libvirt +from provider.interface import interface_base from provider.virtual_network import network_base LOG = logging.getLogger('avocado.' + __name__) @@ -26,6 +28,7 @@ def run(test, params, env): vm_name = params.get('main_vm') vm = env.get_vm(vm_name) virsh_ins = virsh + test_user = 'root' else: vm_name = params.get('unpr_vm_name') test_user = params.get('test_user', '') @@ -38,7 +41,7 @@ def run(test, params, env): test_passwd, **unpr_vm_args) uri = f'qemu+ssh://{test_user}@localhost/session' - virsh_ins = virsh.VirshPersistent(uri=uri) + virsh_ins = virsh.Virsh(uri=uri) host_session = aexpect.ShellSession('su') remote.VMManager.set_ssh_auth(host_session, 'localhost', test_user, test_passwd) @@ -48,16 +51,18 @@ def run(test, params, env): bridge_name = 'br_' + rand_id tap_type = params.get('tap_type', '') tap_name = tap_type + '_' + rand_id + tap_name_2 = tap_name + '_2' tap_mtu = params.get('tap_mtu') iface_mtu = params.get('iface_mtu') - vm_iface = params.get('vm_iface') - host_ip = utils_net.get_host_ip_address(ip_ver='ipv4') + iface_mtu_2 = params.get('iface_mtu_2') iface_attrs = eval(params.get('iface_attrs')) - vm_iface = params.get('vm_iface', 'eno1') + iface_attrs_2 = eval(params.get('iface_attrs_2', '{}')) + iface_amount = params.get('iface_amount') outside_ip = params.get('outside_ip') host_iface = params.get('host_iface') - host_iface = host_iface if host_iface else utils_net.get_net_if( - state="UP")[0] + host_iface = host_iface if host_iface else utils_net.get_default_gateway( + iface_name=True, force_dhcp=True, json=True) + host_ip = utils_net.get_ip_address_by_interface(host_iface, ip_ver='ipv4') status_error = 'yes' == params.get('status_error', 'no') err_msg = params.get('err_msg') vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name, @@ -65,24 +70,48 @@ def run(test, params, env): bkxml = vmxml.copy() try: + mac_addr = vm_xml.VMXML.get_first_mac_by_name(vm_name, virsh_ins) + tap_flag = '' + iface_ori = network_base.get_iface_xml_inst( + vm_name, 'on vm', virsh_ins=virsh_ins) + for attr in (iface_attrs, iface_attrs_2, iface_ori.fetch_attrs()): + if attr.get('driver', {}).get('driver_attr', {}).get('queues'): + tap_flag = 'multi_queue' + break + if params.get('tap_flag') is not None: + tap_flag = params.get('tap_flag') if tap_type: if tap_type == 'tap': utils_net.create_linux_bridge_tmux(bridge_name, host_iface) - network_base.create_tap(tap_name, bridge_name, test_user) + network_base.create_tap( + tap_name, bridge_name, test_user, flag=tap_flag) + if iface_amount == 'two_ifaces': + network_base.create_tap( + tap_name_2, 'virbr0', test_user, flag=tap_flag) elif tap_type == 'macvtap': mac_addr = network_base.create_macvtap(tap_name, host_iface, test_user) - iface_attrs['mac_address'] = mac_addr - if tap_mtu: network_base.set_tap_mtu(tap_name, tap_mtu) + if iface_amount == 'two_ifaces': + network_base.set_tap_mtu(tap_name_2, tap_mtu) + + process.run('ip a') + iface_attrs['mac_address'] = mac_addr vmxml = vm_xml.VMXML.new_from_inactive_dumpxml( vm_name, virsh_instance=virsh_ins) - vmxml.del_device('interface', by_tag=True) libvirt_vmxml.modify_vm_device(vmxml, 'interface', iface_attrs, virsh_instance=virsh_ins) + if iface_attrs_2: + mac_addr_2 = utils_net.generate_mac_address_simple() + iface_attrs_2['mac_address'] = mac_addr_2 + LOG.debug('Adding a 2nd interface to vm xml') + libvirt_vmxml.modify_vm_device(vmxml, 'interface', iface_attrs_2, 1, + virsh_instance=virsh_ins) + + LOG.debug(f'VMxml is:\n{virsh.dumpxml(vm_name, uri=uri).stdout_text}') start_result = virsh.start(vm_name, debug=True, uri=uri) libvirt.check_exit_status(start_result, status_error) @@ -98,7 +127,36 @@ def run(test, params, env): 'outside_ip': outside_ip, 'host_public_ip': host_ip, } - network_base.ping_check(params, ips, session, force_ipv4=True) + vm_default_gw = utils_net.get_default_gateway(session=session, json=True) + if isinstance(vm_default_gw, list): + vm_default_gw = [gw for gw in vm_default_gw if gw.startswith('192')][0] + LOG.debug(f'vm_default_gw is {vm_default_gw}') + + if iface_amount == 'two_ifaces': + ping_params = { + mac_addr: + {'vm_ping_outside': params.get('vm_ping_outside'), + 'vm_ping_host_public': params.get('vm_ping_host_public'), }, + mac_addr_2: + {'vm_ping_outside': params.get('vm_ping_outside')} + } + ips_2 = { + mac_addr: ips, + mac_addr_2: {'outside_ip': vm_default_gw} + } + for mac in (mac_addr, mac_addr_2): + iface_vm_info = utils_net.get_linux_iface_info( + mac=mac, session=session) + iface_vm = iface_vm_info['ifname'] + LOG.debug(f'Check connetivity of iface {iface_vm}({mac})') + ping_args = { + 'vm_ping_outside': {'interface': iface_vm}, + 'vm_ping_host_public': {'interface': iface_vm}, + } + network_base.ping_check(ping_params[mac], ips_2[mac], session, + force_ipv4=True, **ping_args) + else: + network_base.ping_check(params, ips, session, force_ipv4=True) if iface_mtu: # Check mtu of live vmxml @@ -113,6 +171,7 @@ def run(test, params, env): LOG.info('MTU check of vmxml PASS') # Check mtu inside vm + vm_iface = interface_base.get_vm_iface(session) vm_iface_info = utils_net.get_linux_iface_info(iface=vm_iface, session=session) vm_mtu = vm_iface_info['mtu'] @@ -134,10 +193,10 @@ def run(test, params, env): session.close() finally: - bkxml.sync(virsh_instance=virsh_ins) - if not root: - del virsh_ins if tap_type: network_base.delete_tap(tap_name) + if iface_amount == 'two_ifaces': + network_base.delete_tap(tap_name_2) if tap_type == 'tap': utils_net.delete_linux_bridge_tmux(bridge_name, host_iface) + bkxml.sync(virsh_instance=virsh_ins) diff --git a/libvirt/tests/src/virtual_network/connectivity/connectivity_check_mcast_interface.py b/libvirt/tests/src/virtual_network/connectivity/connectivity_check_mcast_interface.py index fb3e38743fe..e73b88e4ea8 100644 --- a/libvirt/tests/src/virtual_network/connectivity/connectivity_check_mcast_interface.py +++ b/libvirt/tests/src/virtual_network/connectivity/connectivity_check_mcast_interface.py @@ -67,7 +67,7 @@ def run(test, params, env): # Build omping command ip_suf, ip_suf_c = (ip_i.split('.')[-1] for ip_i in (ip, ip_c)) - ip_pre = ip.replace(f'.{ip_suf}', '') + ip_pre = '.'.join(ip.split('.')[:3]) omping_cmd = f'omping -m {mcast_addr} {ip_pre}.{{{ip_suf},{ip_suf_c}}}' # omping from vm to vm_c @@ -75,7 +75,7 @@ def run(test, params, env): status, output = utils_net.raw_ping(omping_cmd, 5, session, output_func=LOG.debug) if 'response message never received' not in output: - test.fail('omping should fail with remote vm firewalld on') + test.fail(f'omping failed due to "{output}"') # Keep omping process alive on vm then omping from vm_c to vm session.sendline(omping_cmd) diff --git a/libvirt/tests/src/virtual_network/connectivity/connectivity_check_tcp_tunnel_interface.py b/libvirt/tests/src/virtual_network/connectivity/connectivity_check_tcp_tunnel_interface.py index 7d3ebc9e2b3..8f2106b65f5 100644 --- a/libvirt/tests/src/virtual_network/connectivity/connectivity_check_tcp_tunnel_interface.py +++ b/libvirt/tests/src/virtual_network/connectivity/connectivity_check_tcp_tunnel_interface.py @@ -32,9 +32,13 @@ def run(test, params, env): try: vmxml, cli_vmxml = list( map(vm_xml.VMXML.new_from_inactive_dumpxml, vms)) + mac, cli_mac = list(map(vm_xml.VMXML.get_first_mac_by_name, vms)) [vmxml_i.del_device('interface', by_tag=True) for vmxml_i in [vmxml, cli_vmxml]] + iface_attrs.update({'mac_address': mac}) + cli_iface_attrs.update({'mac_address': cli_mac}) + [libvirt_vmxml.modify_vm_device(vmxml_i, 'interface', attrs) for vmxml_i, attrs in [(vmxml, iface_attrs), (cli_vmxml, cli_iface_attrs)]] diff --git a/libvirt/tests/src/virtual_network/connectivity/connectivity_check_udp_tunnel_interface.py b/libvirt/tests/src/virtual_network/connectivity/connectivity_check_udp_tunnel_interface.py index 5ea0759fc3d..e8bf6a20f35 100644 --- a/libvirt/tests/src/virtual_network/connectivity/connectivity_check_udp_tunnel_interface.py +++ b/libvirt/tests/src/virtual_network/connectivity/connectivity_check_udp_tunnel_interface.py @@ -31,9 +31,13 @@ def run(test, params, env): try: vmxml, cli_vmxml = list( map(vm_xml.VMXML.new_from_inactive_dumpxml, vms)) + mac, cli_mac = list(map(vm_xml.VMXML.get_first_mac_by_name, vms)) [vmxml_i.del_device('interface', by_tag=True) for vmxml_i in [vmxml, cli_vmxml]] + iface_attrs.update({'mac_address': mac}) + cli_iface_attrs.update({'mac_address': cli_mac}) + [libvirt_vmxml.modify_vm_device(vmxml_i, 'interface', attrs) for vmxml_i, attrs in [(vmxml, iface_attrs), (cli_vmxml, cli_iface_attrs)]] @@ -44,7 +48,6 @@ def run(test, params, env): [vm_i.start() for vm_i in [vm, cli_vm]] session, cli_session = (vm_inst.wait_for_serial_login() for vm_inst in [vm, cli_vm]) - mac, cli_mac = list(map(vm_xml.VMXML.get_first_mac_by_name, vms)) iface_info = utils_net.get_linux_iface_info(mac=mac, session=session) cli_iface_info = utils_net.get_linux_iface_info( diff --git a/libvirt/tests/src/virtual_network/connectivity/connectivity_check_user_interface.py b/libvirt/tests/src/virtual_network/connectivity/connectivity_check_user_interface.py index aba514d1bf0..394b0489934 100644 --- a/libvirt/tests/src/virtual_network/connectivity/connectivity_check_user_interface.py +++ b/libvirt/tests/src/virtual_network/connectivity/connectivity_check_user_interface.py @@ -5,6 +5,7 @@ from virttest import remote from virttest import utils_net from virttest import virsh +from virttest import libvirt_version from virttest.libvirt_xml import vm_xml from virttest.utils_libvirt import libvirt_unprivileged from virttest.utils_libvirt import libvirt_vmxml @@ -64,7 +65,7 @@ def run(test, params, env): vm = libvirt_unprivileged.get_unprivileged_vm(vm_name, test_user, test_passwd, **unpr_vm_args) - virsh_ins = virsh.VirshPersistent(uri=virsh_uri) + virsh_ins = virsh.Virsh(uri=virsh_uri) host_session = aexpect.ShellSession('su') remote.VMManager.set_ssh_auth(host_session, 'localhost', test_user, test_passwd) @@ -76,8 +77,9 @@ def run(test, params, env): iface_attrs = eval(params.get('iface_attrs')) outside_ip = params.get('outside_ip') host_iface = params.get('host_iface') - host_iface = host_iface if host_iface else utils_net.get_net_if( - state='UP')[0] + backend = params.get('backend') + host_iface = host_iface if host_iface else utils_net.get_default_gateway( + iface_name=True, force_dhcp=True, json=True) ipv4_addr = params.get('ipv4_addr') ipv4_prefix = params.get('ipv4_prefix') @@ -91,10 +93,15 @@ def run(test, params, env): bkxml = vmxml.copy() try: + mac = vm_xml.VMXML.get_first_mac_by_name(vm_name, virsh_ins) vmxml.del_device('interface', by_tag=True) vmxml.sync(virsh_instance=virsh_ins) + if backend: + libvirt_version.is_libvirt_feature_supported(params) + iface_attrs['backend'] = eval(backend) iface = libvirt_vmxml.create_vm_device_by_type( - 'interface', iface_attrs) + 'interface', {**iface_attrs, **({'mac_address': mac} if mac else {})}) + LOG.debug('iface xml to be tested is: %s', iface) vmxml.add_device(iface) define_result = virsh.define(vmxml.xml, debug=True, uri=virsh_uri) libvirt.check_exit_status(define_result, expect_error) @@ -122,7 +129,7 @@ def run(test, params, env): check_val(ipv6_prefix, str(vm_ipv6_pfx), 'vm ipv6 prefix', test) default_gw_v4 = utils_net.get_default_gateway( - session=session, ip_ver='ipv4', force_dhcp=True) + session=session, ip_ver='ipv4', force_dhcp=True, json=True) LOG.debug(f'vm default gateway ipv4: {default_gw_v4}') check_val(ipv4_default_gw, default_gw_v4, 'default ipv4 gateway', test) vm_nameserver = utils_net.get_guest_nameserver(session) @@ -137,5 +144,3 @@ def run(test, params, env): vm.destroy() finally: bkxml.sync(virsh_instance=virsh_ins) - if not root: - del virsh_ins diff --git a/libvirt/tests/src/virtual_network/connectivity/netperf_nat_interface.py b/libvirt/tests/src/virtual_network/connectivity/netperf_nat_interface.py new file mode 100644 index 00000000000..1e350dc901c --- /dev/null +++ b/libvirt/tests/src/virtual_network/connectivity/netperf_nat_interface.py @@ -0,0 +1,36 @@ +from provider.virtual_network import network_base + +from virttest import virsh + +from virttest.libvirt_xml import vm_xml +from virttest.utils_libvirt import libvirt_network +from virttest.utils_libvirt import libvirt_vmxml + + +def run(test, params, env): + """ + Verify the guest can work well under the netperf stress test + """ + vms = params.get('vms').split() + vm_objs = [env.get_vm(vm_i) for vm_i in vms] + network_attrs = eval(params.get('network_attrs')) + iface_attrs = eval(params.get('iface_attrs')) + + bkxmls = list(map(vm_xml.VMXML.new_from_inactive_dumpxml, vms)) + + try: + libvirt_network.create_or_del_network(network_attrs) + test.log.debug(f'Network xml:\n' + f'{virsh.net_dumpxml(network_attrs["name"]).stdout_text}') + vmxml_lists = list(map(vm_xml.VMXML.new_from_inactive_dumpxml, vms)) + [libvirt_vmxml.modify_vm_device(vmxml_i, 'interface', iface_attrs) + for vmxml_i in vmxml_lists] + + test.log.info('TEST_STEP: Start the VM(s)') + [vm_inst.start() for vm_inst in vm_objs] + [vm_inst.wait_for_login() for vm_inst in vm_objs] + network_base.exec_netperf_test(params, env) + + finally: + [backup_xml.sync() for backup_xml in bkxmls] + libvirt_network.create_or_del_network(network_attrs, is_del=True) diff --git a/libvirt/tests/src/virtual_network/domifaddr.py b/libvirt/tests/src/virtual_network/domifaddr.py new file mode 100644 index 00000000000..a1160e1f839 --- /dev/null +++ b/libvirt/tests/src/virtual_network/domifaddr.py @@ -0,0 +1,152 @@ +import logging +import random + +from virttest import utils_misc +from virttest import utils_net +from virttest import virsh +from virttest.libvirt_xml import network_xml +from virttest.libvirt_xml import vm_xml +from virttest.utils_libvirt import libvirt_vmxml +from virttest.utils_test import libvirt + +from provider.virtual_network import network_base + +VIRSH_ARGS = {"ignore_status": False, "debug": True} + +LOG = logging.getLogger("avocado." + __name__) + + +def run(test, params, env): + """ + Test domifaddr for bridge and network type interface + """ + vm_name = params.get("main_vm") + vm = env.get_vm(vm_name) + net_name = params.get("net_name", "default") + net_ipv6_attrs = eval(params.get("net_ipv6_attrs", "{}")) + + rand_id = utils_misc.generate_random_string(3) + br_name = "linux_br_" + rand_id + host_iface = params.get("host_iface") + host_iface = ( + host_iface + if host_iface + else utils_net.get_default_gateway(iface_name=True, force_dhcp=True).split()[0] + ) + iface_a_attrs = eval(params.get("iface_a_attrs", "{}")) + iface_b_attrs = eval(params.get("iface_b_attrs", "{}")) + err_msg = params.get("err_msg") + + net_xml = network_xml.NetworkXML.new_from_net_dumpxml(net_name) + bk_net = net_xml.copy() + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + bk_xml = vmxml.copy() + + try: + utils_net.create_linux_bridge_tmux(br_name, host_iface) + net_ipv6 = network_xml.IPXML(ipv6=True) + net_ipv6.setup_attrs(**net_ipv6_attrs) + net_xml.add_ip(net_ipv6) + LOG.debug(f"Define network {net_name} with xml:\n{net_xml}") + net_xml.sync() + + vmxml.del_device("interface", by_tag=True) + libvirt_vmxml.modify_vm_device(vmxml, "interface", iface_a_attrs, 0) + libvirt_vmxml.modify_vm_device(vmxml, "interface", iface_b_attrs, 1) + LOG.debug(virsh.dumpxml(vm_name).stdout_text) + + iface_a = network_base.get_iface_xml_inst(vm_name, "interface A", 0) + iface_b = network_base.get_iface_xml_inst(vm_name, "interface B", 1) + # Make sure iface_b is network type, switch if not + if iface_b.type_name != "network": + iface_a, iface_b = iface_b, iface_a + mac_a, mac_b = iface_a.mac_address, iface_b.mac_address + + vm.start() + vm.set_state_guest_agent(True, serial=True) + session = vm.wait_for_serial_login() + ip_output = session.cmd_output("ip addr") + LOG.debug(ip_output) + ip_a = network_base.get_vm_ip(session, mac_a, ignore_error=True) + ip_b = network_base.get_vm_ip(session, mac_b, ignore_error=True) + + ipv6_a = network_base.get_vm_ip(session, mac_a, "ipv6", ignore_error=True) + ipv6_b = network_base.get_vm_ip(session, mac_b, "ipv6", ignore_error=True) + LOG.debug(ip_a) + LOG.debug(ip_b) + + vm_iface_a = utils_net.get_linux_iface_info(mac=mac_a, session=session)[ + "ifname" + ] + vm_iface_b = utils_net.get_linux_iface_info(mac=mac_b, session=session)[ + "ifname" + ] + + ip_gen = utils_net.gen_ipv4_addr("173.173.173.0") + ip_alias_a, ip_alias_b = random.choices(list(ip_gen), k=2) + + cmd_set_alias_a = f"ip addr add {ip_alias_a}/24 dev {vm_iface_a}" + cmd_set_alias_b = f"ip addr add {ip_alias_b}/24 dev {vm_iface_b}" + + session.cmd(cmd_set_alias_a) + session.cmd(cmd_set_alias_b) + + virsh.domiflist(vm_name, **VIRSH_ARGS) + virsh.domifaddr(vm_name, **VIRSH_ARGS) + libvirt.check_logfile(err_msg, params.get("libvirtd_debug_file"), False) + + domid = virsh.domid(vm_name).stdout_text.strip() + out_default = virsh.domifaddr(domid, **VIRSH_ARGS) + expect_info = ["vnet*", mac_b, "ipv4", ip_b, "ipv6", ipv6_b] + for s in expect_info: + libvirt.check_result(out_default, expected_match=s) + + domuuid = virsh.domuuid(vm_name).stdout_text.strip() + out_uuid = virsh.domifaddr(domuuid, **VIRSH_ARGS) + out_lease = virsh.domifaddr(domuuid, "--source lease", **VIRSH_ARGS) + for output in (out_uuid, out_lease): + if output.stdout_text.strip() == out_default.stdout_text.strip(): + LOG.info("Output match") + else: + test.fail("Output of domifaddr does not match, please check log") + + iface_info_a = utils_net.get_linux_iface_info(vm_iface_a, session=session) + ips_a = [addr.get("local") for addr in iface_info_a.get("addr_info", {})] + + iface_info_b = utils_net.get_linux_iface_info(vm_iface_b, session=session) + ips_b = [addr.get("local") for addr in iface_info_b.get("addr_info", {})] + + check_list_a = [mac_a] + ips_a + LOG.debug(check_list_a) + check_list_b = [mac_b] + ips_b + LOG.debug(check_list_b) + + out_agent = virsh.domifaddr(domuuid, "--source agent", **VIRSH_ARGS) + for str in check_list_a + check_list_b: + libvirt.check_result(out_agent, expected_match=str) + + out_agent_a = virsh.domifaddr( + vm_name, f"--source agent {vm_iface_a}", **VIRSH_ARGS + ) + for str in check_list_a: + libvirt.check_result(out_agent_a, expected_match=str) + if any([str in out_agent_a.stdout_text for str in check_list_b]): + test.fail( + f"Output with --source agent {vm_iface_a} should not " + f"contain info of other interface, please check log" + ) + + out_agent_a_full = virsh.domifaddr( + vm_name, f"--source agent {vm_iface_a} --full", **VIRSH_ARGS + ) + for str in check_list_a: + libvirt.check_result(out_agent_a_full, expected_match=str) + + out_arp = virsh.domifaddr(domuuid, "--source arp", **VIRSH_ARGS) + for str in (mac_b, ip_b): + libvirt.check_result(out_arp, expected_match=str) + + finally: + bk_xml.sync() + bk_net.sync() + utils_net.delete_linux_bridge_tmux(br_name, host_iface) diff --git a/libvirt/tests/src/virtual_network/driver/check_vhost_cpu_affinity_with_emulatorpin.py b/libvirt/tests/src/virtual_network/driver/check_vhost_cpu_affinity_with_emulatorpin.py new file mode 100644 index 00000000000..6cf55b086d1 --- /dev/null +++ b/libvirt/tests/src/virtual_network/driver/check_vhost_cpu_affinity_with_emulatorpin.py @@ -0,0 +1,108 @@ +import logging +import random +import re + +from avocado.core import exceptions +from avocado.utils import process +from virttest import cpu +from virttest import virsh +from virttest.libvirt_xml import vm_xml +from virttest.utils_libvirt import libvirt_misc +from virttest.utils_libvirt import libvirt_vmxml + +VIRSH_ARGS = {'ignore_status': False, 'debug': True} + +LOG = logging.getLogger('avocado.' + __name__) + + +def get_online_cpus(): + """ + Get online cpus + + :return: a list of online cpus + """ + cpu_range = cpu.get_cpu_info().get('On-line CPU(s) list') + online_cpus = [ + (lambda x: range(x[0], x[-1] + 1))(list(map(int, r.split('-')))) + for r in cpu_range.split(',') + ] + online_cpus = [cpu for r in online_cpus for cpu in r] + LOG.debug(f'Online cpus: {online_cpus}') + + return online_cpus + + +def check_cpu_affinity(vm_name, pid, epin_set): + """ + Check cpu affinity with virsh emulatorpin and taskset + + :param vm_name: vm name + :param pid: pid of vhost + :param epin_set: pre-set emulatorpin + """ + epin = libvirt_misc.convert_to_dict( + virsh.emulatorpin(vm_name, **VIRSH_ARGS).stdout_text, + r'\s+(\S+):\s+(\S+)') + + if epin['*'] != epin_set: + raise exceptions.TestFail(f'Incorrect cpu affinity (emulatorpin): ' + f'{epin["*"]}, Should be {epin_set}.') + + taskset_output = process.run( + f'taskset -cap {pid}', shell=True).stdout_text + search_pattern = "pid \d+'s current affinity list:\s(\S+)" + search_result = re.search(search_pattern, taskset_output) + if not search_result or search_result.group(1) != epin_set: + raise exceptions.TestFail(f'Expect current affinity to be {epin_set}, ' + f'not {search_result.group(1)}.') + + +def run(test, params, env): + """ + Check the vhost* thread's cpu affinity with emulatorpin setting + """ + vm_name = params.get('main_vm') + vm = env.get_vm(vm_name) + vcpu_set = params.get('vcpu_set') + iface_attrs = eval(params.get('iface_attrs', '{}')) + + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + bkxml = vmxml.copy() + + online_cpus = get_online_cpus() + epin_set = str(random.choice(online_cpus)) + online_cpus.remove(int(epin_set)) + epin_reset = str(random.choice(online_cpus)) + vm_attrs = eval(params.get('vm_attrs', '{}')) + + try: + vmxml.setup_attrs(**vm_attrs) + libvirt_vmxml.modify_vm_device(vmxml, 'interface', iface_attrs) + LOG.debug(f'VMXML of {vm_name}:\n{virsh.dumpxml(vm_name).stdout_text}') + + vm.start() + + cpu_affi = libvirt_misc.convert_to_dict( + virsh.vcpupin(vm_name, **VIRSH_ARGS).stdout_text) + + if cpu_affi['0'] != vcpu_set: + test.fail(f'Incorrect cpu affinity (vcpu): {cpu_affi["0"]},' + f'Should be {vcpu_set}.') + + process.run("ps -eL | grep vhost", shell=True) + pids = process.run( + "ps -eL|awk '/vhost/{print $2}'", shell=True + ).stdout_text.strip().split() + + for pid in pids: + check_cpu_affinity(vm_name, pid, epin_set) + + # Update the emulator pin to other cpu, + # and check the vhost thread's cpu affinity + virsh.emulatorpin(vm_name, epin_reset, **VIRSH_ARGS) + + for pid in pids: + check_cpu_affinity(vm_name, pid, epin_reset) + + finally: + bkxml.sync() diff --git a/libvirt/tests/src/virtual_network/driver/rx_tx_queue_size.py b/libvirt/tests/src/virtual_network/driver/rx_tx_queue_size.py new file mode 100644 index 00000000000..7285900c487 --- /dev/null +++ b/libvirt/tests/src/virtual_network/driver/rx_tx_queue_size.py @@ -0,0 +1,85 @@ +import json +import logging + +from avocado.utils import process +from virttest import utils_net +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.virtual_network import network_base + +VIRSH_ARGS = {'ignore_status': False, 'debug': True} + +LOG = logging.getLogger('avocado.' + __name__) + + +def run(test, params, env): + """ + Start vm with rx_queue_size and tx_queue_size setting + + """ + vm_name = params.get('main_vm') + vm = env.get_vm(vm_name) + iface_attrs = eval(params.get('iface_attrs', '{}')) + status_error = 'yes' == params.get('status_error', 'no') + + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + bkxml = vmxml.copy() + + try: + mac = vm_xml.VMXML.get_first_mac_by_name(vm_name) + iface_attrs['mac_address'] = mac + + vmxml.del_device('interface', by_tag=True) + libvirt_vmxml.modify_vm_device( + vmxml, 'interface', iface_attrs, sync_vm=False) + LOG.debug(f'Modify vmxml to:\n{vmxml}') + + if status_error: + if params.get('fail_operation') == 'define': + virsh_result = virsh.define(vmxml.xml, debug=True) + else: + vmxml.sync() + virsh_result = virsh.start(vm_name, debug=True) + libvirt.check_exit_status(virsh_result, status_error) + return + + vmxml.sync() + vm.start() + LOG.debug(f'VMXML of {vm_name}:\n{virsh.dumpxml(vm_name).stdout_text}') + vm_sess = vm.wait_for_serial_login() + + iface = network_base.get_iface_xml_inst(vm_name, 'after vm start') + actual_rx = int(iface.driver.driver_attr.get('rx_queue_size')) + actual_tx = int(params.get('actual_tx') or iface.driver.driver_attr.get('tx_queue_size')) + LOG.debug( + f'Actual rx_queue_size={actual_rx} tx_queue_size={actual_tx}') + if str(actual_rx) != iface_attrs['driver']['driver_attr']['rx_queue_size']: + test.fail(f"Wrong rx_queue_size {actual_rx}, should be " + f"{iface_attrs['driver']['driver_attr']['rx_queue_size']}") + if actual_tx != 256: + test.fail(f'Wrong tx_queue_size {actual_tx}, should be 256') + + process.run('ps -ef|grep qemu', shell=True) + + vm_iface = utils_net.get_linux_iface_info( + mac=mac, session=vm_sess)['ifname'] + + eth_output = vm_sess.cmd(f'ethtool -g {vm_iface}') + LOG.debug(eth_output) + eth_output_json = vm_sess.cmd_output(f'ethtool --json -g {vm_iface}') + LOG.debug(eth_output_json) + eth_info = json.loads(eth_output_json)[0] + if eth_info['rx-max'] != actual_rx or eth_info['rx'] != actual_rx: + test.fail('Wrong rx from vm, please check log') + if eth_info['tx-max'] != actual_tx or eth_info['tx'] != actual_tx: + test.fail('Wrong tx from vm, please check log') + + ips = {'outside_ip': params.get('outside_ip')} + network_base.ping_check(params, ips, vm_sess) + vm_sess.close() + + finally: + bkxml.sync() diff --git a/libvirt/tests/src/virtual_network/elements_and_attributes/attribute_port_isolated.py b/libvirt/tests/src/virtual_network/elements_and_attributes/attribute_port_isolated.py index 3efab3c7dd1..44907ff4879 100644 --- a/libvirt/tests/src/virtual_network/elements_and_attributes/attribute_port_isolated.py +++ b/libvirt/tests/src/virtual_network/elements_and_attributes/attribute_port_isolated.py @@ -35,8 +35,8 @@ def run(test, params, env): net_attrs = eval(params.get('net_attrs', '{}')) port_attrs = eval(params.get('port_attrs', '{}')) host_iface = params.get('host_iface') - host_iface = host_iface if host_iface else utils_net.get_net_if( - state='UP')[0] + host_iface = host_iface if host_iface else utils_net.get_default_gateway( + iface_name=True, force_dhcp=True, json=True) vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) bkxmls = list(map(vm_xml.VMXML.new_from_inactive_dumpxml, vms)) @@ -55,7 +55,7 @@ def run(test, params, env): net_attrs = {**net_attrs, **port_attrs} if not (set_iface and cli_iface_attrs): - cli_iface_attrs = iface_attrs + cli_iface_attrs = iface_attrs.copy() if create_linux_br: LOG.info(f'Create linux bridge: {linux_br}') @@ -65,10 +65,15 @@ def run(test, params, env): LOG.debug(f'Network xml:\n' f'{virsh.net_dumpxml(net_attrs["name"]).stdout_text}') + mac, cli_mac = list(map(vm_xml.VMXML.get_first_mac_by_name, vms)) + vmxml, cli_vmxml = list(map(vm_xml.VMXML.new_from_inactive_dumpxml, vms)) [vmxml_i.del_device('interface', by_tag=True) for vmxml_i in [vmxml, cli_vmxml]] + iface_attrs.update({'mac_address': mac}) + cli_iface_attrs.update({'mac_address': cli_mac}) + [libvirt_vmxml.modify_vm_device(vmxml_i, 'interface', attrs) for vmxml_i, attrs in [(vmxml, iface_attrs), (cli_vmxml, cli_iface_attrs)]] diff --git a/libvirt/tests/src/virtual_network/elements_and_attributes/element_coalesce.py b/libvirt/tests/src/virtual_network/elements_and_attributes/element_coalesce.py index d32c6d0a93a..7f449a8f817 100644 --- a/libvirt/tests/src/virtual_network/elements_and_attributes/element_coalesce.py +++ b/libvirt/tests/src/virtual_network/elements_and_attributes/element_coalesce.py @@ -31,8 +31,8 @@ def run(test, params, env): br_name = br_type + '_' + rand_id host_iface = params.get('host_iface') - host_iface = host_iface if host_iface else utils_net.get_net_if( - state="UP")[0] + host_iface = host_iface if host_iface else utils_net.get_default_gateway( + iface_name=True, force_dhcp=True, json=True) iface_attrs = eval(params.get('iface_attrs', '{}')) vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) @@ -45,8 +45,10 @@ def run(test, params, env): elif br_type == 'ovs_br': utils_net.create_ovs_bridge(br_name) + mac = vm_xml.VMXML.get_first_mac_by_name(vm_name) vmxml.del_device('interface', by_tag=True) - iface = libvirt_vmxml.create_vm_device_by_type('interface', iface_attrs) + iface = libvirt_vmxml.create_vm_device_by_type( + 'interface', {**iface_attrs, **{'mac_address': mac}}) vmxml.add_device(iface) LOG.debug(f'Interface to add to vm:\n{iface}') diff --git a/libvirt/tests/src/virtual_network/elements_and_attributes/element_mac_specific_addr.py b/libvirt/tests/src/virtual_network/elements_and_attributes/element_mac_specific_addr.py new file mode 100644 index 00000000000..f8feb63f6e4 --- /dev/null +++ b/libvirt/tests/src/virtual_network/elements_and_attributes/element_mac_specific_addr.py @@ -0,0 +1,104 @@ +import logging +import re + +from virttest import utils_net +from virttest import virsh +from virttest import libvirt_version +from virttest.libvirt_xml import vm_xml +from virttest.utils_libvirt import libvirt_vmxml +from virttest.utils_test import libvirt + +from provider.virtual_network import network_base + +VIRSH_ARGS = {'ignore_status': False, 'debug': True} + +LOG = logging.getLogger('avocado.' + __name__) + + +def run(test, params, env): + """ + Test start vm or hotplug interface with specific mac address + """ + libvirt_version.is_libvirt_feature_supported(params) + vm_name = params.get('main_vm') + vm = env.get_vm(vm_name) + scenario = params.get('scenario') + outside_ip = params.get('outside_ip') + status_error = 'yes' == params.get('status_error', 'no') + err_msg = params.get('err_msg') + set_mac = eval(params.get('mac', {})).get('mac_address') + iface_attrs = eval(params.get('iface_attrs', '{}')) + expect_xml_mac = params.get('expect_xml_mac') + expect_tap_mac = params.get('expect_tap_mac') + + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + bkxml = vmxml.copy() + + try: + vmxml.del_device('interface', by_tag=True) + if scenario == 'pre_set': + iface = libvirt_vmxml.create_vm_device_by_type('interface', + iface_attrs) + vmxml.add_device(iface) + LOG.debug(f'Interface to add to vm:\n{iface}') + + if status_error: + start_result = virsh.define(vmxml.xml, debug=True) + libvirt.check_exit_status(start_result, status_error) + if err_msg: + libvirt.check_result(start_result, expected_fails=err_msg) + return + else: + vmxml.sync() + vm.start() + + elif scenario == 'hotplug': + vmxml.sync() + vm.start() + if set_mac: + at_options = f'network default --mac {set_mac} --model virtio' + else: + at_options = f'network default --model virtio' + + at_result = virsh.attach_interface(vm_name, at_options, debug=True) + libvirt.check_exit_status(at_result, status_error) + if status_error: + if err_msg: + libvirt.check_result(at_result, expected_fails=err_msg) + return + + vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) + LOG.debug(f'VMXML of {vm_name}:\n{virsh.dumpxml(vm_name).stdout_text}') + iface_xml = vmxml.get_devices('interface')[0] + LOG.debug(f'Interface in vmxml:\n{iface_xml}') + vmxml_mac = iface_xml.mac_address + if not re.match(expect_xml_mac, vmxml_mac): + test.fail(f'Expect mac address on vmxml: {expect_tap_mac}, ' + f'not {vmxml_mac}') + + virsh.domiflist(vm_name, **VIRSH_ARGS) + iflist = libvirt.get_interface_details(vm_name) + LOG.debug(f'iflist of vm: {iflist}') + tap_on_host = iflist[0]['interface'] + LOG.debug(f'Tap device on host: {tap_on_host}') + + # Get the expected mac address of tap device from mac address on vmxml + expect_tap_mac = re.sub('^\w+:', expect_tap_mac, vmxml_mac) + LOG.debug(f'Expect mac address of tap device on host: {expect_tap_mac}') + tap_mac = utils_net.get_linux_iface_info(iface=tap_on_host)['address'] + if not re.match(expect_tap_mac, tap_mac): + test.fail(f'Expect mac address of tap device: {expect_tap_mac} ' + f'not {tap_mac}') + + session = vm.wait_for_serial_login() + ip_in_vm = session.cmd_output('ip addr') + LOG.debug(f'ip addr output on vm:\n{ip_in_vm}') + if vmxml_mac not in ip_in_vm: + test.fail(f'Not found mac address from vmxml {vmxml_mac} in vm.') + + ips = {'outside_ip': outside_ip} + network_base.ping_check(params, ips, session, force_ipv4=True) + session.close() + + finally: + bkxml.sync() diff --git a/libvirt/tests/src/virtual_network/elements_and_attributes/element_model.py b/libvirt/tests/src/virtual_network/elements_and_attributes/element_model.py index 07071e54d4b..c1fc2214246 100644 --- a/libvirt/tests/src/virtual_network/elements_and_attributes/element_model.py +++ b/libvirt/tests/src/virtual_network/elements_and_attributes/element_model.py @@ -1,21 +1,49 @@ import logging +from virttest import libvirt_version 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.virtual_network import network_base +from provider.interface import interface_base VIRSH_ARGS = {'ignore_status': False, 'debug': True} LOG = logging.getLogger('avocado.' + __name__) +def check_model_controller(vm_name, pci_model, test): + """ + Checks that the controllers are the expected pci model + + :param vm_name: VM name + :param pci_model: The expected pci model + :param test: Test instance + """ + vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) + iface = vmxml.get_devices('interface')[0] + LOG.debug(f'Interface xml after vm started:\n{iface}') + ctrl_index = int(iface.fetch_attrs()['address']['attrs']['bus'], 16) + controllers = vmxml.get_devices('controller') + iface_controller = [c for c in controllers if c.type == 'pci' and + c.index == str(ctrl_index)][0] + LOG.debug(f'Controller xml:\n{iface_controller}') + + if iface_controller.model == pci_model: + LOG.debug('XML controller model check: PASS') + else: + test.fail(f'Expect pci model: {pci_model}, ' + f'and got {iface_controller.model}') + + def run(test, params, env): """ Test 'model' element of interface """ + libvirt_version.is_libvirt_feature_supported(params) + vm_name = params.get('main_vm') vm = env.get_vm(vm_name) outside_ip = params.get('outside_ip') @@ -23,9 +51,9 @@ def run(test, params, env): err_msg = params.get('err_msg') pci_model = params.get('pci_model') iface_attrs = eval(params.get('iface_attrs', '{}')) - vm_iface = params.get('vm_iface') iface_driver = params.get('iface_driver') model_type = params.get('model_type') + check_pci_model = params.get('check_pci_model', 'yes') == "yes" if model_type == 'default': iface_attrs.pop('model') @@ -58,6 +86,7 @@ def run(test, params, env): f'but got {iface_info["model"]}') session = vm.wait_for_serial_login() + vm_iface = interface_base.get_vm_iface(session) eth_output = session.cmd_output(f'ethtool -i {vm_iface} | grep driver') LOG.debug(eth_output) @@ -71,19 +100,7 @@ def run(test, params, env): network_base.ping_check(params, ips, session, force_ipv4=True) session.close() - vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) - iface = vmxml.get_devices('interface')[0] - LOG.debug(f'Interface xml after vm started:\n{iface}') - ctrl_index = int(iface.fetch_attrs()['address']['attrs']['bus'], 16) - controllers = vmxml.get_devices('controller') - iface_controller = [c for c in controllers if c.type == 'pci' and - c.index == str(ctrl_index)][0] - LOG.debug(f'Controller xml:\n{iface_controller}') - - if iface_controller.model == pci_model: - LOG.debug('XML controller model check: PASS') - else: - test.fail(f'Expect pci model: {pci_model}, ' - f'and got {iface_controller.model}') + if check_pci_model: + check_model_controller(vm_name, pci_model, test) finally: bkxml.sync() diff --git a/libvirt/tests/src/virtual_network/hotplug/attach_detach_device/rollback_vdpafd_on_hotplug_failure.py b/libvirt/tests/src/virtual_network/hotplug/attach_detach_device/rollback_vdpafd_on_hotplug_failure.py new file mode 100644 index 00000000000..c000eeeaa87 --- /dev/null +++ b/libvirt/tests/src/virtual_network/hotplug/attach_detach_device/rollback_vdpafd_on_hotplug_failure.py @@ -0,0 +1,55 @@ +from provider.interface import interface_base +from provider.interface import vdpa_base + +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 + + +def run(test, params, env): + """ + Check opened fd on vdpa device is closed when device attaching failed + """ + + libvirt_version.is_libvirt_feature_supported(params) + + # Variable assignment + test_target = params.get('test_target', '') + dev_type = params.get('dev_type', 'vdpa') + iface_dict2 = eval(params.get("iface_dict2", "{}")) + iface2_dev = iface_dict2["source"]["dev"] + + vm_name = params.get('main_vm') + vm = env.get_vm(vm_name) + + vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) + backup_vmxml = vmxml.copy() + + test_obj = None + try: + test_obj, _ = vdpa_base.setup_vdpa(vm, params) + test.log.info("TEST_STEP: Start a vm, attach a vdpa interface with " + "acpi index=1.") + vm.start() + interface_base.attach_iface_device(vm_name, dev_type, params) + + test.log.info("TEST_STEP: Hotplug another vdpa interface with " + "acpi index=1.") + iface2 = interface_base.create_iface("vdpa", iface_dict2) + res = virsh.attach_device(vm.name, iface2.xml, debug=True) + libvirt.check_exit_status(res, True) + res = process.run(f"lsof {iface2_dev}", verbose=True, ignore_status=True) + libvirt.check_exit_status(res, True) + if res.stdout_text: + test.fail(f"{iface2_dev} may be used by qemu - {res.stdout_text}") + + test.log.info("TEST_STEP: Hotplug another vdpa interface with " + "acpi index=2.") + iface2.setup_attrs(**{'acpi': {'index': '2'}}) + virsh.attach_device(vm.name, iface2.xml, debug=True, ignore_status=False) + finally: + backup_vmxml.sync() + vdpa_base.cleanup_vdpa(test_target, test_obj) diff --git a/libvirt/tests/src/virtual_network/hotplug/attach_detach_interface/attach_interface_with_model.py b/libvirt/tests/src/virtual_network/hotplug/attach_detach_interface/attach_interface_with_model.py new file mode 100644 index 00000000000..b249c2392b8 --- /dev/null +++ b/libvirt/tests/src/virtual_network/hotplug/attach_detach_interface/attach_interface_with_model.py @@ -0,0 +1,128 @@ +import uuid + +from virttest import libvirt_version +from virttest import utils_net +from virttest import virsh +from virttest.libvirt_xml import vm_xml + +from virttest.utils_libvirt import libvirt_vmxml +from virttest.libvirt_xml.devices import interface +from virttest.utils_test import libvirt + +from provider.virtual_network import network_base +from provider.interface import interface_base + +VIRSH_ARGS = {"ignore_status": False, "debug": True} + + +def check_model_controller(vm_name, pci_model, test): + """ + Checks that the controllers are the expected pci model + + :param vm_name: VM name + :param pci_model: The expected pci model + :param test: Test instance + """ + vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) + iface = vmxml.get_devices("interface")[0] + test.log.debug(f"Interface xml after vm started:\n{iface}") + ctrl_index = int(iface.fetch_attrs()["address"]["attrs"]["bus"], 16) + controllers = vmxml.get_devices("controller") + iface_controller = [c for c in controllers if c.type == "pci" and + c.index == str(ctrl_index)][0] + test.log.debug(f"Controller xml:\n{iface_controller}") + + if iface_controller.model == pci_model: + test.log.debug("XML controller model check: PASS") + else: + test.fail(f"Expect pci model: {pci_model}, " + f"and got {iface_controller.model}") + + +def run(test, params, env): + """ + Attach-interface with different models and options + """ + libvirt_version.is_libvirt_feature_supported(params) + + vm_name = params.get("main_vm") + vm = env.get_vm(vm_name) + outside_ip = params.get("outside_ip") + pci_model = params.get("pci_model") + iface_driver = params.get("iface_driver") + model_type = params.get("model_type") + check_pci_model = params.get("check_pci_model", "yes") == "yes" + bridge_controller_needed = params.get("bridge_controller_needed", "yes") == "yes" + + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + bkxml = vmxml.copy() + + try: + if bridge_controller_needed: + pci_controllers = vmxml.get_controllers("pci") + for controller in pci_controllers: + if controller.get("model") == "pcie-to-pci-bridge": + break + else: + controller_dict = {"model": "pcie-to-pci-bridge"} + libvirt_vmxml.modify_vm_device(vmxml, "controller", controller_dict, 50) + + libvirt_vmxml.remove_vm_devices_by_type(vm, "interface") + test.log.debug(f"VMXML of {vm_name}:\n{virsh.dumpxml(vm_name).stdout_text}") + + vm.start() + session = vm.wait_for_serial_login() + + mac = utils_net.generate_mac_address_simple() + alias_name = "ua-" + str(uuid.uuid1()) + options = "network default --model {} --alias {} --mac {}".format( + model_type, alias_name, mac) + iface = interface.Interface() + iface.xml = virsh.attach_interface(vm_name, f"{options} --print-xml", **VIRSH_ARGS).stdout_text.strip() + test.log.debug(iface.fetch_attrs()) + exp_iface = {'model': model_type, 'source': {'network': 'default'}, + 'type_name': 'network', + 'alias': {'name': alias_name}, + 'mac_address': mac} + iface_attrs = iface.fetch_attrs() + + if exp_iface != iface_attrs: + test.fail("Failed to print xml! Expected: %s, Got: %s." % (exp_iface, iface_attrs)) + virsh.attach_interface(vm_name, options, **VIRSH_ARGS) + iflist = libvirt.get_interface_details(vm_name) + test.log.debug(f"iflist of vm: {iflist}") + iface_info = iflist[0] + if iface_info["model"] == model_type: + test.log.debug("Model check of domiflist: PASS") + else: + test.fail(f"Expect interface model {model_type}, " + f"but got {iface_info['model']}") + + session = vm.wait_for_serial_login() + vm_iface_info = interface_base.get_vm_iface_info(session) + if vm_iface_info.get("driver") != iface_driver: + test.fail("Failed to get expected driver \"{iface_driver}\" in ethtool output") + + ips = {"outside_ip": outside_ip} + network_base.ping_check(params, ips, session, force_ipv4=True) + + if check_pci_model: + check_model_controller(vm_name, pci_model, test) + + virsh.detach_device_alias(vm_name, alias_name, + wait_for_event=True, + event_timeout=20, + **VIRSH_ARGS) + iflist = libvirt.get_interface_details(vm_name) + test.log.debug(f"iflist of vm: {iflist}") + if iflist: + test.fail("Found unexpected interface in %s." % iflist) + vm_iface = interface_base.get_vm_iface(session, True) + if vm_iface: + test.fail("Found unexpected interface in %s." % vm_iface) + else: + test.log.debug(vm_iface) + session.close() + + finally: + bkxml.sync() diff --git a/libvirt/tests/src/virtual_network/iface_bridge.py b/libvirt/tests/src/virtual_network/iface_bridge.py index 25ed63dae25..4b7ec6351d9 100644 --- a/libvirt/tests/src/virtual_network/iface_bridge.py +++ b/libvirt/tests/src/virtual_network/iface_bridge.py @@ -17,6 +17,8 @@ from virttest.libvirt_xml.devices import interface from virttest.libvirt_xml import network_xml +from provider.virtual_network import network_base + NETWORK_SCRIPT = "/etc/sysconfig/network-scripts/ifcfg-" @@ -113,7 +115,9 @@ def check_net_functions(guest_ip, ping_count, ping_timeout, guest_session, host_ filter_name = params.get("filter_name", "vdsm-no-mac-spoofing") ping_count = params.get("ping_count", "5") ping_timeout = float(params.get("ping_timeout", "10")) - iface_name = utils_net.get_net_if(state="UP")[0] + host_iface = params.get("host_iface") + iface_name = host_iface if host_iface else utils_net.get_default_gateway( + iface_name=True, force_dhcp=True, json=True) bridge_script = NETWORK_SCRIPT + bridge_name iface_script = NETWORK_SCRIPT + iface_name iface_script_bk = os.path.join(data_dir.get_tmp_dir(), "iface-%s.bk" % iface_name) @@ -249,7 +253,7 @@ def check_net_functions(guest_ip, ping_count, ping_timeout, guest_session, host_ remote_url = params.get("remote_ip", "www.google.com") try: - vm1_ip = utils_net.get_guest_ip_addr(session1, mac) + vm1_ip = network_base.get_vm_ip(session1, mac) except Exception as errs: test.fail("vm1 can't get IP with the new create bridge: %s" % errs) if test_qos: @@ -287,7 +291,7 @@ def check_net_functions(guest_ip, ping_count, ping_timeout, guest_session, host_ driver_dict = eval(iface_driver) if session1 is None: session1 = vm1.wait_for_serial_login() - guest_iface_info = session1.cmd_output("ip l").strip() + guest_iface_info = session1.cmd_output("ip --color=never l").strip() guest_iface_name = re.findall(r"^\d+: (\S+?)[@:].*state UP.*$", guest_iface_info, re.MULTILINE)[0] comb_size = driver_dict.get('queues') rx_size = driver_dict.get('rx_queue_size') diff --git a/libvirt/tests/src/virtual_network/iface_coalesce.py b/libvirt/tests/src/virtual_network/iface_coalesce.py index 4e47a463491..6096cea83e1 100644 --- a/libvirt/tests/src/virtual_network/iface_coalesce.py +++ b/libvirt/tests/src/virtual_network/iface_coalesce.py @@ -191,7 +191,7 @@ def run(test, params, env): """ if not libvirt_version.version_compare(3, 3, 0): - test.skip("Coalesce setting is only supported by libvirt3.3.0 and above") + test.cancel("Coalesce setting is only supported by libvirt3.3.0 and above") vm_name = params.get("main_vm") vm = env.get_vm(vm_name) diff --git a/libvirt/tests/src/virtual_network/iface_hotplug.py b/libvirt/tests/src/virtual_network/iface_hotplug.py index 1019d4d8581..dac8387ded9 100644 --- a/libvirt/tests/src/virtual_network/iface_hotplug.py +++ b/libvirt/tests/src/virtual_network/iface_hotplug.py @@ -235,8 +235,7 @@ def get_all_mac_in_vm(): def check_iface_exist(): try: - session = vm.wait_for_serial_login(username=username, - password=password) + session = vm.wait_for_login(serial=True) if utils_net.get_linux_ifname(session, iface['mac']): return True else: @@ -291,8 +290,7 @@ def check_iface_exist(): # Start the domain if needed if vm.is_dead(): vm.start() - session = vm.wait_for_serial_login(username=username, - password=password) + session = vm.wait_for_login(serial=True) # check if interface is attached for iface in iface_list: diff --git a/libvirt/tests/src/virtual_network/iface_network.py b/libvirt/tests/src/virtual_network/iface_network.py index 450ed51398e..4a42a118f3e 100644 --- a/libvirt/tests/src/virtual_network/iface_network.py +++ b/libvirt/tests/src/virtual_network/iface_network.py @@ -26,6 +26,8 @@ from virttest.libvirt_xml.devices.interface import Interface from virttest import libvirt_version +from provider.virtual_network import network_base + # Using as lower capital is not the best way to do, but this is just a # workaround to avoid changing the entire file. @@ -445,11 +447,12 @@ def check_ipt_rules(check_ipv4=True, check_ipv6=False): ipv6_rules.extend(rules) if "mode" in net_forward and net_forward["mode"] == "nat" \ and nat_attrs.get('ipv6') == 'yes': + v6_nat_rules = [ - "MASQUERADE\s+tcp\s+{0}\s+!{0}".format(net_ipv6), - "MASQUERADE\s+udp\s+{0}\s+!{0}".format(net_ipv6), - "MASQUERADE\s+all\s+{0}\s+!{0}".format(net_ipv6), - ] + "MASQUERADE.*tcp.*{0}.*!{0}".format(net_ipv6), + "MASQUERADE.*udp.*{0}.*!{0}".format(net_ipv6), + "MASQUERADE.*all.*{0}.*!{0}".format(net_ipv6) + ] v6_output = process.run('ip6tables -t nat -L', shell=True).stdout_text for rule in v6_nat_rules: if not re.search(rule, v6_output): @@ -481,8 +484,8 @@ def run_ip_test(session, ip_ver): # It may take some time to get the ip address def get_ip_func(): - return utils_net.get_guest_ip_addr(session, iface_mac, - ip_version=ip_ver) + return network_base.get_vm_ip(session, iface_mac, + ip_ver=ip_ver) utils_misc.wait_for(get_ip_func, 5) if not get_ip_func(): @@ -672,6 +675,7 @@ def dig_test(session): ipt6_rules = [] define_macvtap = "yes" == params.get("define_macvtap", "no") net_dns_forwarders = params.get("net_dns_forwarders", "").split() + only_test_define = "yes" == params.get("only_test_define", "no") # Cancel if not yet supported in libvirt version under test if "floor" in ast.literal_eval(iface_bandwidth_inbound): @@ -794,10 +798,14 @@ def dig_test(session): netxml.sync() except xcepts.LibvirtXMLError as details: logging.info(str(details)) + if only_test_define and libvirt_version.version_compare(10, 8, 0): + define_error = False if define_error: return else: test.fail("Failed to define network") + if only_test_define: + return # Check open mode network xml if "mode" in forward and forward["mode"] == "open": @@ -1085,7 +1093,7 @@ def _check_lease(loop): if test_dhcp_range: dhcp_range = int(params.get("dhcp_range", "252")) utils_net.restart_guest_network(session, iface_mac) - vm_ip = utils_net.get_guest_ip_addr(session, iface_mac) + vm_ip = network_base.get_vm_ip(session, iface_mac) logging.debug("Guest has ip: %s", vm_ip) if not vm_ip and dhcp_range: test.fail("Guest has invalid ip address") @@ -1099,8 +1107,7 @@ def _check_lease(loop): vms_mac = vms.get_virsh_mac_address() # restart guest network to get ip addr utils_net.restart_guest_network(sess, vms_mac) - vms_ip = utils_net.get_guest_ip_addr(sess, - vms_mac) + vms_ip = network_base.get_vm_ip(sess, vms_mac, ignore_error=True) if not vms_ip and dhcp_range: test.fail("Guest has invalid ip address") elif vms_ip and not dhcp_range: diff --git a/libvirt/tests/src/virtual_network/iface_options.py b/libvirt/tests/src/virtual_network/iface_options.py index edde0bcf39b..f2c28632f2b 100644 --- a/libvirt/tests/src/virtual_network/iface_options.py +++ b/libvirt/tests/src/virtual_network/iface_options.py @@ -29,6 +29,7 @@ from virttest.staging import utils_memory from virttest import libvirt_version +from provider.virtual_network import network_base # Using as lower capital is not the best way to do, but this is just a @@ -382,8 +383,8 @@ def get_guest_ip(session, mac): utils_net.restart_guest_network(session, mac) # Wait for IP address is ready utils_misc.wait_for( - lambda: utils_net.get_guest_ip_addr(session, mac), 10) - return utils_net.get_guest_ip_addr(session, mac) + lambda: network_base.get_vm_ip(session, mac), 10) + return network_base.get_vm_ip(session, mac) def check_user_network(session): """ @@ -404,7 +405,8 @@ def check_user_network(session): " on guest") # Check gateway address gateway = str(utils_net.get_default_gateway(False, session)) - if expect_gw not in gateway: + pattern = re.compile(expect_gw, re.MULTILINE) + if not pattern.search(gateway): test.fail("The gateway on guest is %s, while expect is %s" % (gateway, expect_gw)) # Check dns server address diff --git a/libvirt/tests/src/virtual_network/iface_stat.py b/libvirt/tests/src/virtual_network/iface_stat.py index 5f117b9b4eb..af7340f7030 100644 --- a/libvirt/tests/src/virtual_network/iface_stat.py +++ b/libvirt/tests/src/virtual_network/iface_stat.py @@ -140,7 +140,8 @@ def _collect_and_compare_stat(vm_name, session, **virsh_args): for _ in range(3): session.cmd('curl -O https://avocado-project.org/data/' 'assets/jeos/27/jeos-27-64.qcow2.xz -L', - timeout=240) + timeout=60, ignore_all_errors=True) + session.sendcontrol("c") host_iface_stat = get_host_iface_stat(vm_name, iface_target_dev, **virsh_args) @@ -151,7 +152,8 @@ def _collect_and_compare_stat(vm_name, session, **virsh_args): host_iface = params.get("host_iface") if not host_iface: - host_iface = utils_net.get_net_if(state="UP")[0] + host_iface = utils_net.get_default_gateway( + iface_name=True, force_dhcp=True, json=True) if iface_type == 'direct': iface_dict = {k.replace('new_iface_', ''): v for k, v in params.items() @@ -186,6 +188,7 @@ def _collect_and_compare_stat(vm_name, session, **virsh_args): unpr_vmxml.del_device('interface', by_tag=True) libvirt_vmxml.modify_vm_device(unpr_vmxml, 'interface', iface_attrs) + unpr_vmxml.del_seclabel(by_attr=[('model', 'dac')]) network_base.define_vm_for_unprivileged_user(unpr_user, unpr_vmxml) unpr_vm_name = unpr_vmxml.vm_name diff --git a/libvirt/tests/src/virtual_network/iface_unprivileged.py b/libvirt/tests/src/virtual_network/iface_unprivileged.py index 428b615bfe7..98f918ac10f 100644 --- a/libvirt/tests/src/virtual_network/iface_unprivileged.py +++ b/libvirt/tests/src/virtual_network/iface_unprivileged.py @@ -1,22 +1,17 @@ -import logging as log -import shutil -import aexpect - -from avocado.utils import process +import logging +import aexpect from virttest import libvirt_version from virttest import remote from virttest import utils_misc from virttest import utils_net -from virttest import utils_package from virttest import virsh from virttest.libvirt_xml import vm_xml -from virttest.utils_test import libvirt +from virttest.utils_libvirt import libvirt_unprivileged +from provider.virtual_network import network_base -# Using as lower capital is not the best way to do, but this is just a -# workaround to avoid changing the entire file. -logging = log.getLogger('avocado.' + __name__) +LOG = logging.getLogger('avocado.' + __name__) def run(test, params, env): @@ -24,150 +19,64 @@ def run(test, params, env): Test interface with unprivileged user """ - def create_bridge(br_name, iface_name): - """ - Create bridge attached to physical interface - """ - # Make sure the bridge not exist - if libvirt.check_iface(br_name, "exists", "--all"): - test.cancel("The bridge %s already exist" % br_name) - - # Create bridge - utils_package.package_install('tmux') - cmd = 'tmux -c "ip link add name {0} type bridge; ip link set {1} up;' \ - ' ip link set {1} master {0}; ip link set {0} up; pkill dhclient; ' \ - 'sleep 6; dhclient {0}; ifconfig {1} 0"'.format(br_name, iface_name) - process.run(cmd, shell=True, verbose=True) - - def check_ping(dest_ip, ping_count, timeout, src_ip=None, session=None, - expect_success=True): - """ - Check if ping result meets expectation - """ - status, output = utils_net.ping(dest=dest_ip, count=ping_count, - interface=src_ip, timeout=timeout, - session=session, force_ipv4=True) - success = True if status == 0 else False - - if success != expect_success: - test.fail('Ping result not met expectation, ' - 'actual result is {}'.format(success)) - if not libvirt_version.version_compare(5, 6, 0): test.cancel('Libvirt version is too low for this test.') - vm_name = params.get('main_vm') - rand_id = '_' + utils_misc.generate_random_string(3) + vm_name = params.get('unpr_vm_name') + test_user = params.get('test_user', '') + test_passwd = params.get('test_passwd', '') + unpr_vm_args = { + 'username': params.get('username'), + 'password': params.get('password'), + } + vm = libvirt_unprivileged.get_unprivileged_vm(vm_name, test_user, + test_passwd, + **unpr_vm_args) + uri = f'qemu+ssh://{test_user}@localhost/session' + virsh_ins = virsh.Virsh(uri=uri) + host_session = aexpect.ShellSession('su') + remote.VMManager.set_ssh_auth(host_session, 'localhost', test_user, + test_passwd) + host_session.close() - upu_vm_name = 'upu_vm' + rand_id - user_vm_name = params.get('user_vm_name', 'non_root_vm') + rand_id = '_' + utils_misc.generate_random_string(3) bridge_name = params.get('bridge_name', 'test_br0') + rand_id device_type = params.get('device_type', '') - iface_name = params.get("iface_name") - if not iface_name: - iface_name = utils_net.get_net_if(state="UP")[0] + host_iface = params.get('host_iface') + if not host_iface: + host_iface = utils_net.get_default_gateway( + iface_name=True, force_dhcp=True).split()[0] tap_name = params.get('tap_name', 'mytap0') + rand_id macvtap_name = params.get('macvtap_name', 'mymacvtap0') + rand_id - remote_ip = params.get('remote_ip') - up_user = params.get('up_user', 'test_upu') + rand_id case = params.get('case', '') - # Create unprivileged user - logging.info('Create unprivileged user %s', up_user) - process.run('useradd %s' % up_user, shell=True, verbose=True) - root_vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) - - upu_args = { - 'unprivileged_user': up_user, - 'ignore_status': False, - 'debug': True, - } + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name, + virsh_instance=virsh_ins) + bkxml = vmxml.copy() try: - # Create vm as unprivileged user - logging.info('Create vm as unprivileged user') - upu_vmxml = root_vmxml.copy() - - # Prepare vm for unprivileged user - xml_devices = upu_vmxml.devices - disks = xml_devices.by_device_tag("disk") - for disk in disks: - ori_path = disk.source['attrs'].get('file') - if not ori_path: - continue - - file_name = ori_path.split('/')[-1] - new_disk_path = '/home/{}/{}'.format(up_user, file_name) - logging.debug('New disk path:{}'.format(new_disk_path)) - - # Copy disk image file and chown to make sure that - # unprivileged user has access - shutil.copyfile(ori_path, new_disk_path) - shutil.chown(new_disk_path, up_user, up_user) - - # Modify xml to set new path of disk - disk_index = xml_devices.index(disk) - source = xml_devices[disk_index].source - new_attrs = source.attrs - new_attrs['file'] = new_disk_path - source.attrs = new_attrs - xml_devices[disk_index].source = source - logging.debug(xml_devices[disk_index].source) - - upu_vmxml.devices = xml_devices - - new_xml_path = '/home/{}/upu.xml'.format(up_user) - shutil.copyfile(upu_vmxml.xml, new_xml_path) - - # Define vm for unprivileged user - virsh.define(new_xml_path, **upu_args) - virsh.domrename(vm_name, upu_vm_name, **upu_args) - logging.debug(virsh.dumpxml(upu_vm_name, **upu_args)) - upu_vmxml = vm_xml.VMXML() - upu_vmxml.xml = virsh.dumpxml(upu_vm_name, **upu_args).stdout_text - - # Remove nvram tag of os to avoid permission issue - os_xml = upu_vmxml.os - os_xml.del_nvram() - upu_vmxml.os = os_xml if case == 'precreated': if device_type == 'tap': # Create bridge - create_bridge(bridge_name, iface_name) + iface_attrs = network_base.get_iface_xml_inst( + vm_name, 'on vm', virsh_ins=virsh_ins).fetch_attrs() + if iface_attrs.get('driver', {}).get('driver_attr', {}).get('queues'): + tap_flag = 'multi_queue' + else: + tap_flag = '' + utils_net.create_linux_bridge_tmux(bridge_name, host_iface) - # Create tap device - tap_cmd = 'ip tuntap add mode tap user {user} group {user} ' \ - 'name {tap};ip link set {tap} up;ip link set {tap} ' \ - 'master {br}'.format(tap=tap_name, user=up_user, - br=bridge_name) - - # Execute command as root - process.run(tap_cmd, shell=True, verbose=True) + network_base.create_tap( + tap_name, bridge_name, test_user, tap_flag) if device_type == 'macvtap': # Create macvtap device - mac_addr = utils_net.generate_mac_address_simple() - macvtap_cmd = 'ip link add link {iface} name {macvtap} address' \ - ' {mac} type macvtap mode bridge;' \ - 'ip link set {macvtap} up'.format( - iface=iface_name, - macvtap=macvtap_name, - mac=mac_addr) - process.run(macvtap_cmd, shell=True, verbose=True) - cmd_get_tap = 'ip link show {} | head -1 | cut -d: -f1'.format(macvtap_name) - tap_index = process.run(cmd_get_tap, shell=True, verbose=True).stdout_text.strip() - device_path = '/dev/tap{}'.format(tap_index) - logging.debug('device_path: {}'.format(device_path)) - # Change owner and group for device - process.run('chown {user} {path};chgrp {user} {path}'.format( - user=up_user, path=device_path), - shell=True, verbose=True) - # Check if device owner is changed to unprivileged user - process.run('ls -l %s' % device_path, shell=True, verbose=True) + mac_addr = network_base.create_macvtap( + macvtap_name, host_iface, test_user) # Modify interface - all_devices = upu_vmxml.devices + all_devices = vmxml.devices iface_list = all_devices.by_device_tag('interface') if not iface_list: test.error('No iface to modify') @@ -194,47 +103,25 @@ def check_ping(dest_ip, ping_count, timeout, src_ip=None, session=None, if device_type == 'macvtap': iface.mac_address = mac_addr - logging.debug(iface) - - upu_vmxml.devices = all_devices - logging.debug(upu_vmxml) - - # Remove seclabel model="dac" since unprivileged user doesn't support this feature - upu_vmxml.del_seclabel([('model', 'dac'), ('relabel', 'yes')]) - # Define updated xml - shutil.copyfile(upu_vmxml.xml, new_xml_path) - upu_vmxml.xml = new_xml_path - virsh.define(new_xml_path, **upu_args) - logging.debug(virsh.dumpxml(upu_vm_name, **upu_args).stdout_text) - - # Switch to unprivileged user and modify vm's interface - # Start vm as unprivileged user and test network - virsh.start(upu_vm_name, debug=True, ignore_status=False, - unprivileged_user=up_user) - cmd = ("su - %s -c 'virsh console %s'" - % (up_user, upu_vm_name)) - session = aexpect.ShellSession(cmd) - session.sendline() - remote.handle_prompts(session, params.get("username"), - params.get("password"), r"[\#\$]\s*$", 60) - logging.debug(session.cmd_output('ifconfig')) - check_ping(remote_ip, 5, 10, session=session) + LOG.debug(iface) + + vmxml.devices = all_devices + LOG.debug(vmxml) + + vm.start() + session = vm.wait_for_serial_login(60) + LOG.debug(session.cmd_output('ifconfig')) + ips = {'outside_ip': params.get('outside_ip')} + network_base.ping_check(params, ips, session) session.close() finally: - if 'upu_virsh' in locals(): - virsh.destroy(upu_vm_name, unprivileged_user=up_user) - virsh.undefine(upu_vm_name, options='--nvram', unprivileged_user=up_user) + bkxml.sync(virsh_instance=virsh_ins) if case == 'precreated': try: - if device_type == 'tap': - process.run('ip tuntap del mode tap {}'.format(tap_name), shell=True, verbose=True) - elif device_type == 'macvtap': - process.run('ip l del {}'.format(macvtap_name), shell=True, verbose=True) + if device_type in ('tap', 'macvtap'): + network_base.delete_tap(tap_name) except Exception: pass finally: - cmd = 'tmux -c "ip link set {1} nomaster; ip link delete {0};' \ - 'pkill dhclient; sleep 6; dhclient {1}"'.format(bridge_name, iface_name) - process.run(cmd, shell=True, verbose=True, ignore_status=True) - process.run('pkill -u {0};userdel -f -r {0}'.format(up_user), shell=True, verbose=True, ignore_status=True) + utils_net.delete_linux_bridge_tmux(bridge_name, host_iface) diff --git a/libvirt/tests/src/virtual_network/iface_update.py b/libvirt/tests/src/virtual_network/iface_update.py index bea0475bc88..22123a3356f 100644 --- a/libvirt/tests/src/virtual_network/iface_update.py +++ b/libvirt/tests/src/virtual_network/iface_update.py @@ -314,7 +314,9 @@ def check_mtu(): state_map = "%s.*\n.*%s" % (iface_link_value.upper(), mac_addr) session = vm.wait_for_serial_login() logging.info("ip link output:%s", session.cmd_output("ip link")) - if_name = utils_net.get_net_if(runner=session.cmd_output, state=state_map)[0] + if_name = utils_net.get_net_if( + runner=session.cmd_output, state=state_map, + ip_options='--color=never')[0] if not check_iface_link(session, mac_addr, new_iface_link): test.fail('iface link check inside vm failed.') session.close() diff --git a/libvirt/tests/src/virtual_network/lifecycle/lifecycle_vdpa_interface.py b/libvirt/tests/src/virtual_network/lifecycle/lifecycle_vdpa_interface.py index 9ef792c9b32..18f003c09db 100644 --- a/libvirt/tests/src/virtual_network/lifecycle/lifecycle_vdpa_interface.py +++ b/libvirt/tests/src/virtual_network/lifecycle/lifecycle_vdpa_interface.py @@ -55,13 +55,17 @@ def run_test(dev_type, params, test_obj=None): check_points.check_network_accessibility( vm, test_obj=test_obj, config_vdpa=True, **params) - test.log.info("Save the VM.") - save_path = os.path.join(data_dir.get_tmp_dir(), vm.name + '.save') - virsh.save(vm.name, save_path, **VIRSH_ARGS) - test.log.info("Restore vm.") - virsh.restore(save_path, **VIRSH_ARGS) - check_points.check_network_accessibility( - vm, test_obj=test_obj, config_vdpa=False, **params) + save_supported_ver = { + 'func_supported_since_libvirt_ver': params.get('save_supported_ver', + '(8,5,0)')} + if libvirt_version.is_libvirt_feature_supported(save_supported_ver, True): + test.log.info("Save the VM.") + save_path = os.path.join(data_dir.get_tmp_dir(), vm.name + '.save') + virsh.save(vm.name, save_path, **VIRSH_ARGS) + test.log.info("Restore vm.") + virsh.restore(save_path, **VIRSH_ARGS) + check_points.check_network_accessibility( + vm, test_obj=test_obj, config_vdpa=False, **params) test.log.info("Suspend and resume the vm.") virsh.suspend(vm.name, **VIRSH_ARGS) diff --git a/libvirt/tests/src/virtual_network/lifecycle/restart_service.py b/libvirt/tests/src/virtual_network/lifecycle/restart_service.py new file mode 100644 index 00000000000..4048758baa0 --- /dev/null +++ b/libvirt/tests/src/virtual_network/lifecycle/restart_service.py @@ -0,0 +1,96 @@ +import re +import logging as log + +from avocado.utils import process +from virttest import virsh +from virttest import utils_misc +from virttest.staging import service +from virttest.libvirt_xml import network_xml +from virttest.utils_test import libvirt +from virttest.utils_libvirt import libvirt_network + +logging = log.getLogger('avocado.' + __name__) + + +def run(test, params, env): + """ + 1) make sure the network is active in healthy state; + 2) delete the bridge of the network, which cause an abnormal status; + 3) restart the network daemon, check the network status is inactive and clean; + 4) start the network and check it's healthy again; + """ + + def delete_bridge(net_name): + """ + Delete the bridge associated with the network created by libvirt to + prepare an abnormal scenario + + :params net_name: the name of the network + :return: None + """ + xml = network_xml.NetworkXML.new_from_net_dumpxml(net_name) + br_name = xml.bridge['name'] + logging.debug("Delete the bridge %s for network %s:", br_name, net_name) + cmd = "ip l delete %s" % br_name + process.run(cmd, shell=True) + cmd1 = "ip l show %s" % br_name + if not process.run(cmd1, shell=True, ignore_status=True).exit_status: + test.cancel("The bridge can not be deleted: %s" % br_name) + + def check_net_states(net_name, active): + """ + Check the network related status are expected, + when it is running, there should be 2 dnsmasq process, + and listening on specific ports. While inactive network + should be clean without these. + + :params net_name: string, name of the network + :params active: bool, True or False + """ + s_active = virsh.net_state_dict()[net_name]["active"] + xml = network_xml.NetworkXML.new_from_net_dumpxml(net_name) + br_ip = xml.ips[0]['address'] + logging.debug("br_ip is %s for network %s", br_ip, net_name) + + cmd = "ps aux|grep dnsmasq|grep -v grep | grep %s" % net_name + dnsmasq_process = process.run(cmd, shell=True, ignore_status=True).stdout_text.strip() + cmd1 = """ps aux|grep dnsmasq|grep -v grep | grep %s | awk '$1=="dnsmasq" {print $2}'""" % net_name + dnsmasq_pid = process.run(cmd1, shell=True, ignore_status=True).stdout_text.strip() + cmd2 = "lsof -i -P -n | grep %s" % dnsmasq_pid + listen_port = process.run(cmd2, shell=True, ignore_status=True).stdout_text.strip() + logging.debug("Check the dnsmasq process of the network: %s", dnsmasq_process) + logging.debug("Check the listen_port associated with the dnsmasq process: %s", listen_port) + if active: + pid_num = len(dnsmasq_process.splitlines()) + pattern_list = [rf'UDP\s+{br_ip}:53', + rf'TCP\s+{br_ip}:53', + r'UDP\s+\*:67'] + for pattern in pattern_list: + if not re.search(pattern, listen_port): + test.fail("Can not find the listen port %s" % pattern) + if (pid_num != 2) or not s_active: + test.fail("The network should be active with 2 dnsmasq process!") + if not active: + if s_active: + test.fail("The network %s should be inactive!" % net_name) + if dnsmasq_process or listen_port: + test.fail("There should not be any dnsmasq process nor listening port!") + + try: + net_name = utils_misc.generate_random_string(8) + net_attrs = eval(params.get('net_attrs', '{}')) + logging.debug("TEST_STEP1: Define and start a network") + libvirt_network.create_or_del_network(net_attrs) + virsh.net_start(net_name, ignore_status=True) + check_net_states(net_name, True) + logging.debug("TEST_STEP2: Delete the bridge to prepare an abnormal status") + delete_bridge(net_name) + logging.debug("TEST_STEP3: Restart virtnetworkd, check the network become inactive") + service.Factory.create_service("virtnetworkd").restart() + check_net_states(net_name, False) + logging.debug("TEST_STEP4: Start the network again and ensure it works well") + ret = virsh.net_start(net_name, ignore_status=False) + libvirt.check_result(ret) + finally: + virsh.net_destroy(net_name, ignore_status=True) + virsh.net_undefine(net_name, ignore_status=True) diff --git a/libvirt/tests/src/virtual_network/link_state/link_state_model_type.py b/libvirt/tests/src/virtual_network/link_state/link_state_model_type.py new file mode 100644 index 00000000000..0bf32658e25 --- /dev/null +++ b/libvirt/tests/src/virtual_network/link_state/link_state_model_type.py @@ -0,0 +1,116 @@ +from virttest import libvirt_version +from virttest import virsh +from virttest import utils_misc +from virttest import utils_net + +from virttest.libvirt_xml import vm_xml +from virttest.utils_libvirt import libvirt_unprivileged +from virttest.utils_libvirt import libvirt_vmxml +from virttest.utils_test import libvirt + +from provider.interface import interface_base +from provider.virtual_network import network_base + +import time + +VIRSH_ARGS = {"ignore_status": False, "debug": True} + + +def run(test, params, env): + """ + Start vm with different interface type with various model type and link + state setting + """ + libvirt_version.is_libvirt_feature_supported(params) + + outside_ip = params.get("outside_ip") + host_iface = params.get("host_iface") + host_iface = host_iface if host_iface else utils_net.get_default_gateway( + iface_name=True, force_dhcp=True, json=True) + rand_id = utils_misc.generate_random_string(3) + bridge_name = "br_" + rand_id + tap_name = "tap_" + rand_id + interface_type = params.get("interface_type") + iface_attrs = eval(params.get("iface_attrs", "{}")) + initial_link_state = params.get("initial_link_state", "") + if initial_link_state: + iface_attrs.update({"link_state": initial_link_state}) + test_states = [("yes", "up"), ("no", "down")] + if initial_link_state == "down": + test_states.reverse() + + virsh_ins = virsh + vm_name = params.get("main_vm") + vm = env.get_vm(vm_name) + test_passwd = params.get("test_passwd", "") + test_user = params.get("test_user", "root") + if test_user != "root": + unpr_vm_args = {"username": params.get("username"), + "password": params.get("password")} + vm_name = params.get("unpr_vm_name") + vm = libvirt_unprivileged.get_unprivileged_vm( + vm_name, test_user, test_passwd, **unpr_vm_args) + virsh_ins = virsh.Virsh(uri=vm.connect_uri) + + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml( + vm_name, virsh_instance=virsh_ins) + bkxml = vmxml.copy() + + try: + if interface_type == "ethernet": + utils_net.create_linux_bridge_tmux(bridge_name, host_iface) + network_base.create_tap(tap_name, bridge_name, "root") + + mac = vm_xml.VMXML.get_first_mac_by_name(vm_name, virsh_ins) + vmxml.del_device('interface', by_tag=True) + libvirt_vmxml.modify_vm_device( + vmxml, 'interface', {**iface_attrs, **{'mac_address': mac}}, + virsh_instance=virsh_ins) + test.log.debug(f'VMXML of {vm_name}:\n{virsh_ins.dumpxml(vm_name).stdout_text}') + vm.start() + session = vm.wait_for_serial_login() + vm_iface = interface_base.get_vm_iface(session) + + test.log.info("TEST_STEP: Check the link state in vm.") + iflist = libvirt.get_interface_details(vm_name, virsh_instance=virsh_ins) + test.log.debug(f'iflist of vm: {iflist}') + iface_info = iflist[0] + iface_mac = iface_info['mac'] + for exp_link_state, exp_domiflik_state in test_states: + if exp_link_state == test_states[-1][0]: + virsh_ins.domif_setlink( + vm_name, iface_mac, exp_domiflik_state, **VIRSH_ARGS) + time.sleep(3) + link_info = virsh_ins.domif_getlink( + vm_name, iface_mac, **VIRSH_ARGS).stdout_text + if exp_domiflik_state not in link_info: + test.fail("Failed to get expected interface link state '%s'!" + % exp_domiflik_state) + + output = session.cmd_output("ethtool %s" % vm_iface) + test.log.debug(output) + if "Link detected: %s" % exp_link_state not in output: + test.fail("Failed to get expected link state '%s' in ethtool " + "cmd!" % exp_link_state) + + if exp_link_state == "yes": + if exp_link_state == test_states[-1][0]: + utils_net.restart_guest_network(session) + ips = {'outside_ip': outside_ip} + network_base.ping_check(params, ips, session, force_ipv4=True) + vm_iface = vm_xml.VMXML.new_from_dumpxml(vm.name, + virsh_instance=virsh_ins)\ + .devices.by_device_tag("interface")[0] + + test.log.info("TEST_STEP: Check the live xml for the current link state.") + iface_attrs = vm_iface.fetch_attrs() + test.log.debug(f"iface attrs: {iface_attrs}") + if iface_attrs.get("link_state") != exp_domiflik_state: + test.fail("Failed to get expected link state '%s'." % exp_domiflik_state) + session.close() + + finally: + bkxml.sync(virsh_instance=virsh_ins) + if interface_type == "ethernet": + network_base.delete_tap(tap_name) + utils_net.delete_linux_bridge_tmux(bridge_name, host_iface) diff --git a/libvirt/tests/src/virtual_network/locked_memory_vdpa/hotplug_mem_to_vm_with_multiple_vdpa_interfaces.py b/libvirt/tests/src/virtual_network/locked_memory_vdpa/hotplug_mem_to_vm_with_multiple_vdpa_interfaces.py index 6de9538b8f9..a23e0509169 100644 --- a/libvirt/tests/src/virtual_network/locked_memory_vdpa/hotplug_mem_to_vm_with_multiple_vdpa_interfaces.py +++ b/libvirt/tests/src/virtual_network/locked_memory_vdpa/hotplug_mem_to_vm_with_multiple_vdpa_interfaces.py @@ -37,7 +37,7 @@ def setup_test(): 'iface_dict', "{'source': {'dev':'/dev/vhost-vdpa-0'}}")) iface_dev = interface_base.create_iface(dev_type, iface_dict) libvirt.add_vm_device(vm_xml.VMXML.new_from_dumpxml(vm_name), iface_dev) - test.log.debug("VM xml afater updating ifaces: %s.", + test.log.debug("VM xml after updating ifaces: %s.", vm_xml.VMXML.new_from_dumpxml(vm_name)) def run_test(): @@ -63,7 +63,7 @@ def run_test(): new_vmxml.get_current_mem(), new_vmxml.get_current_mem_unit()) + 1073741824 if not libvirt_memory.comp_memlock(expr_memlock): - test.fail("Unalbe to get correct MEMLOCK after VM startup!") + test.fail("Unable to get correct MEMLOCK after VM startup!") test.log.info("TEST_STEP2: Hotplug memory device.") mem_dict1 = eval(params.get('mem_dict1', '{}')) @@ -75,7 +75,7 @@ def run_test(): new_vmxml.get_current_mem(), new_vmxml.get_current_mem_unit()) + 1073741824 if not libvirt_memory.comp_memlock(expr_memlock): - test.fail("Unalbe to get correct MEMLOCK after attaching a memory " + test.fail("Unable to get correct MEMLOCK after attaching a memory " "device!") test.log.info("TEST_STEP3: Add one more vDPA interface.") @@ -89,7 +89,7 @@ def run_test(): new_vmxml.get_current_mem(), new_vmxml.get_current_mem_unit()) * 2 + 1073741824 if not libvirt_memory.comp_memlock(expr_memlock): - test.fail("Unalbe to get correct MEMLOCK after attaching the 2nd " + test.fail("Unable to get correct MEMLOCK after attaching the 2nd " "interface device!") test.log.info("TEST_STEP4: Hotplut one more memory device.") @@ -102,7 +102,7 @@ def run_test(): new_vmxml.get_current_mem(), new_vmxml.get_current_mem_unit()) * 2 + 1073741824 if not libvirt_memory.comp_memlock(expr_memlock): - test.fail("Unalbe to get correct MEMLOCK after attaching the 2nd " + test.fail("Unable to get correct MEMLOCK after attaching the 2nd " "interface device!") test.log.info("TEST_STEP5: Detach a memory device and vDPA interface.") @@ -110,7 +110,7 @@ def run_test(): vm_name).get_devices('memory')[-1] virsh.detach_device(vm_name, memxml.xml, debug=True) if not libvirt_memory.comp_memlock(expr_memlock): - test.fail("Unalbe to get correct MEMLOCK after detaching a memory " + test.fail("Unable to get correct MEMLOCK after detaching a memory " "device!") iface = vm_xml.VMXML.new_from_dumpxml(vm_name).get_devices( @@ -119,13 +119,13 @@ def run_test(): wait_for_event=True, **virsh_args) if not libvirt_memory.comp_memlock(expr_memlock): - test.fail("Unalbe to get correct MEMLOCK after detaching a vDPA " + test.fail("Unable to get correct MEMLOCK after detaching a vDPA " "interface!") test.log.info("TEST_STEP6: Hotplug a vDPA interface.") virsh.attach_device(vm_name, iface.xml, **virsh_args) if not libvirt_memory.comp_memlock(expr_memlock): - test.fail("Unalbe to get correct MEMLOCK after re-attaching a vDPA " + test.fail("Unable to get correct MEMLOCK after re-attaching a vDPA " "interface!") test.log.info("TEST_STEP7: Hotplug one more vDPA interface.") @@ -138,7 +138,7 @@ def run_test(): new_vmxml.get_current_mem(), new_vmxml.get_current_mem_unit()) * 3 + 1073741824 if not libvirt_memory.comp_memlock(expr_memlock): - test.fail("Unalbe to get correct MEMLOCK after attaching the 3rd " + test.fail("Unable to get correct MEMLOCK after attaching the 3rd " "interface device!") test.log.info("TEST_STEP8: Check qemu log.") diff --git a/libvirt/tests/src/virtual_network/locked_memory_vdpa/hotplug_mem_to_vm_with_vdpa.py b/libvirt/tests/src/virtual_network/locked_memory_vdpa/hotplug_mem_to_vm_with_vdpa.py new file mode 100644 index 00000000000..4537dbb5205 --- /dev/null +++ b/libvirt/tests/src/virtual_network/locked_memory_vdpa/hotplug_mem_to_vm_with_vdpa.py @@ -0,0 +1,207 @@ +from virttest import libvirt_version +from virttest import utils_misc +from virttest import utils_vdpa +from virttest import virsh + +from virttest.libvirt_xml import vm_xml +from virttest.libvirt_xml.devices.memory import Memory +from virttest.utils_libvirt import libvirt_memory +from virttest.utils_libvirt import libvirt_vmxml +from virttest.utils_test import libvirt + +from provider.interface import interface_base + +VIRSH_ARGS = {'debug': True, 'ignore_status': False} + + +def run(test, params, env): + """ + Hotplug memory to vm with vDPA type interface and check the locked memory + """ + + def check_environment(params): + """ + Check the test environment + + :param params: Dictionary with the test parameters + """ + libvirt_version.is_libvirt_feature_supported(params) + utils_misc.is_qemu_function_supported(params) + + def setup_test(): + """ + Set up test + + 1) Remove interface devices + 2) Setup test environment for a specific interface if needed + 3) Set VM attrs + + :return: An object of special test environment + """ + test.log.debug("Remove VM's interface devices.") + libvirt_vmxml.remove_vm_devices_by_type(vm, 'interface') + test_env_obj = None + if test_target == "simulator": + test_env_obj = utils_vdpa.VDPASimulatorTest() + else: + pf_pci = utils_vdpa.get_vdpa_pci() + test_env_obj = utils_vdpa.VDPAOvsTest(pf_pci) + test_env_obj.setup() + + test.log.debug("Update VM's settings.") + vm_attrs = eval(params.get('vm_attrs', '{}')) + vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) + vmxml.setup_attrs(**vm_attrs) + vmxml.sync() + test.log.debug("Updated VM xml: %s.", + vm_xml.VMXML.new_from_dumpxml(vm_name)) + return test_env_obj + + def teardown_test(): + """ + Cleanup vDPA environment + """ + if test_obj: + test_obj.cleanup() + + def setup_at_memory_to_vm_with_iface(): + """ + Prepare a vm with max memory, numa, and an interface + """ + test_env_obj = setup_test() + # Add interface device + iface_dict = eval(params.get('iface_dict', '{}')) + iface_dev = interface_base.create_iface(dev_type, iface_dict) + vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) + libvirt.add_vm_device(vmxml, iface_dev) + test.log.debug("VM xml after updating ifaces: %s.", + vm_xml.VMXML.new_from_dumpxml(vm_name)) + return test_env_obj + + def test_at_memory_to_vm_with_iface(): + """ + hotplug memory device to vm with an interface + + 1) Start vm and check the locked memory + 2) Hotplug memory device and check the locked memory + """ + vm.start() + vm.wait_for_serial_login(timeout=240).close() + new_vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) + + # MEMLOCK value is guest memory + 1G(for the passthrough device) + expr_memlock = libvirt_memory.normalize_mem_size( + new_vmxml.get_current_mem(), + new_vmxml.get_current_mem_unit()) + 1073741824 + if not libvirt_memory.comp_memlock(expr_memlock): + test.fail("Unable to get correct MEMLOCK after VM startup!") + + test.log.info("Hotplug memory device.") + mem_dict = eval(params.get('mem_dict', '{}')) + memxml = Memory() + memxml.setup_attrs(**mem_dict) + virsh.attach_device(vm_name, memxml.xml, **VIRSH_ARGS) + expr_memlock += libvirt_memory.normalize_mem_size( + mem_dict['target']['size'], mem_dict['target']['size_unit']) + if not libvirt_memory.comp_memlock(expr_memlock): + test.fail("Unable to get correct MEMLOCK after attaching a memory " + "device!") + + def test_at_iface_and_memory(): + """ + hotplug an interface and memory devices + + 1) Start vm and check the default locked memory + 2) Hotplug an interface and check the locked memory + 3) Hotplug 2 memory devices and check the locked memory + 4) Hot-unplug a memory device and check the locked memory + """ + vm.start() + vm.wait_for_serial_login(timeout=240).close() + expr_memlock = 67108864 + if not libvirt_memory.comp_memlock(expr_memlock): + test.fail("Unable to get correct default!") + + interface_base.attach_iface_device(vm_name, dev_type, params) + + new_vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) + # MEMLOCK value is guest memory + 1G(for the passthrough device) + expr_memlock = libvirt_memory.normalize_mem_size( + new_vmxml.get_current_mem(), + new_vmxml.get_current_mem_unit()) + 1073741824 + if not libvirt_memory.comp_memlock(expr_memlock): + test.fail("Unable to get correct MEMLOCK after VM startup!") + + test.log.info("Hotplug memory devices.") + for mem_attrs in ['mem_dict1', 'mem_dict2']: + mem_dict = eval(params.get(mem_attrs, '{}')) + memxml = Memory() + memxml.setup_attrs(**mem_dict) + virsh.attach_device(vm_name, memxml.xml, **VIRSH_ARGS) + expr_memlock += libvirt_memory.normalize_mem_size( + mem_dict['target']['size'], mem_dict['target']['size_unit']) + if not libvirt_memory.comp_memlock(expr_memlock): + test.fail("Unable to get correct MEMLOCK after attaching a " + "memory device!") + + test.log.info("Detach a memory device and check memlock.") + memxml = vm_xml.VMXML.new_from_dumpxml( + vm_name).get_devices('memory')[-1] + cmd_result = virsh.detach_device(vm_name, memxml.xml, + wait_for_event=True, + debug=True) + if cmd_result.exit_status: + libvirt.check_result(cmd_result, 'unplug of device was rejected') + if not libvirt_memory.comp_memlock(expr_memlock): + test.fail("Detaching mem failed, MEMLOCK should not change!") + else: + if not libvirt_memory.comp_memlock(expr_memlock): + test.fail("Unable to get correct MEMLOCK after detaching a " + "memory device!") + + def setup_at_memory_to_vm_with_iface_and_locked_mem(): + """ + Prepare a vm with max memory, locked mem, numa, and an interface + """ + return setup_at_memory_to_vm_with_iface() + + def test_at_memory_to_vm_with_iface_and_locked_mem(): + """ + hotplug memory device + + 1) Start a guest with max memory + locked + interface + 2) Hotplug a memory device and check the locked memory + """ + vm.start() + vm.wait_for_serial_login(timeout=240).close() + new_vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) + + expr_memlock = libvirt_memory.normalize_mem_size( + new_vmxml.memtune.hard_limit, new_vmxml.memtune.hard_limit_unit) + if not libvirt_memory.comp_memlock(expr_memlock): + test.fail("Unable to get correct MEMLOCK after VM startup!") + + check_environment(params) + # Variable assignment + test_scenario = params.get('test_scenario', '') + test_target = params.get('test_target', '') + dev_type = params.get('dev_type', 'vdpa') + run_test = eval("test_%s" % test_scenario) + setup_func = eval("setup_%s" % test_scenario) if "setup_%s" % \ + test_scenario in locals() else setup_test + + vm_name = params.get('main_vm') + vm = env.get_vm(vm_name) + + vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) + backup_vmxml = vmxml.copy() + + test_obj = None + try: + # Execute test + test_obj = setup_func() + run_test() + + finally: + backup_vmxml.sync() + teardown_test() diff --git a/libvirt/tests/src/virtual_network/locked_memory_vdpa/mem_lock_limit_multiple_mixed_interfaces.py b/libvirt/tests/src/virtual_network/locked_memory_vdpa/mem_lock_limit_multiple_mixed_interfaces.py index 625eb55c7cd..3ac34db0b59 100644 --- a/libvirt/tests/src/virtual_network/locked_memory_vdpa/mem_lock_limit_multiple_mixed_interfaces.py +++ b/libvirt/tests/src/virtual_network/locked_memory_vdpa/mem_lock_limit_multiple_mixed_interfaces.py @@ -40,7 +40,7 @@ def setup_test(dev_type): iface_dict = eval(params.get('iface_dict', "{'source': {'dev':'/dev/vhost-vdpa-0'}}")) iface_dev = interface_base.create_iface(dev_type, iface_dict) libvirt.add_vm_device(vm_xml.VMXML.new_from_dumpxml(vm_name), iface_dev) - test.log.debug("VM xml afater updating ifaces: %s.", + test.log.debug("VM xml after updating ifaces: %s.", vm_xml.VMXML.new_from_dumpxml(vm_name)) if test_scenario == "cold_plug": @@ -71,7 +71,7 @@ def run_test(dev_type): new_vmxml.get_current_mem(), new_vmxml.get_current_mem_unit()) * iface_no + 1073741824 if not libvirt_memory.comp_memlock(expr_memlock): - test.fail("Unalbe to get correct MEMLOCK after VM startup!") + test.fail("Unable to get correct MEMLOCK after VM startup!") if test_scenario == "cold_plug": return @@ -83,14 +83,14 @@ def run_test(dev_type): new_vmxml.get_current_mem(), new_vmxml.get_current_mem_unit()) * 2 + 1073741824 if not libvirt_memory.comp_memlock(expr_memlock): - test.fail("Unalbe to get correct MEMLOCK after attaching a hostdev " + test.fail("Unable to get correct MEMLOCK after attaching a hostdev " "interface!") test.log.info("TEST_STEP: Hotplug another hostdev interface.") virsh.attach_interface(vm.name, "hostdev --managed %s" % sriov_test_obj.vf_pci2, debug=True, ignore_status=False) if not libvirt_memory.comp_memlock(expr_memlock): - test.fail("Unalbe to get correct MEMLOCK after attaching a hostdev " + test.fail("Unable to get correct MEMLOCK after attaching a hostdev " "interface!") test.log.info("TEST_STEP: Add one more vDPA interface.") @@ -104,7 +104,7 @@ def run_test(dev_type): new_vmxml.get_current_mem(), new_vmxml.get_current_mem_unit()) * 3 + 1073741824 if not libvirt_memory.comp_memlock(expr_memlock): - test.fail("Unalbe to get correct MEMLOCK after attaching the 2nd " + test.fail("Unable to get correct MEMLOCK after attaching the 2nd " "vDPA interface device!") # Variable assignment diff --git a/libvirt/tests/src/virtual_network/locked_memory_vdpa/mem_lock_limit_multiple_vdpa_interfaces.py b/libvirt/tests/src/virtual_network/locked_memory_vdpa/mem_lock_limit_multiple_vdpa_interfaces.py new file mode 100644 index 00000000000..794b288a645 --- /dev/null +++ b/libvirt/tests/src/virtual_network/locked_memory_vdpa/mem_lock_limit_multiple_vdpa_interfaces.py @@ -0,0 +1,69 @@ +from avocado.utils import process + +from virttest import libvirt_version +from virttest import utils_vdpa + +from virttest.libvirt_xml import vm_xml +from virttest.utils_libvirt import libvirt_memory +from virttest.utils_libvirt import libvirt_vmxml +from virttest.utils_test import libvirt + +from provider.interface import interface_base + + +def run(test, params, env): + """ + Check mem_lock limit for vm with multiple vDPA interfaces. + """ + libvirt_version.is_libvirt_feature_supported(params) + # Variable assignment + dev_type = params.get('dev_type', 'vdpa') + iface_num = 3 + vm_name = params.get('main_vm') + vm = env.get_vm(vm_name) + + vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) + backup_vmxml = vmxml.copy() + + try: + pf_pci = utils_vdpa.get_vdpa_pci() + test_env_obj = utils_vdpa.VDPAOvsTest(pf_pci) + test_env_obj.setup() + qemu_log = "/var/log/libvirt/qemu/%s.log" % vm.name + process.run("echo > {}".format(qemu_log), shell=True) + + libvirt_vmxml.remove_vm_devices_by_type(vm, 'interface') + + vm_attrs = eval(params.get('vm_attrs', '{}')) + vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) + vmxml.setup_attrs(**vm_attrs) + vmxml.sync() + test.log.debug("Updated VM xml: %s.", + vm_xml.VMXML.new_from_dumpxml(vm_name)) + for idx in range(iface_num): + default_iface = {'source': {'dev': '/dev/vhost-vdpa-%s' % str(idx)}} + iface_dict = eval(params.get( + 'iface_dict%s' % str(idx+1), str(default_iface))) + if iface_dict: + iface_dev = interface_base.create_iface(dev_type, iface_dict) + libvirt.add_vm_device(vm_xml.VMXML.new_from_dumpxml(vm_name), + iface_dev) + test.log.debug("VM xml after updating ifaces: %s.", + vm_xml.VMXML.new_from_dumpxml(vm_name)) + + test.log.info("TEST_STEP: Start the vm with 3 vDPA interfaces.") + vm.start() + vm.wait_for_serial_login(timeout=240).close() + + new_vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) + expr_memlock = libvirt_memory.normalize_mem_size( + new_vmxml.get_current_mem(), + new_vmxml.get_current_mem_unit()) * 3 + 1073741824 + if not libvirt_memory.comp_memlock(expr_memlock): + test.fail("Unable to get correct MEMLOCK after VM startup!") + + test.log.info("TEST_STEP: Check qemu log.") + libvirt.check_logfile("fail|error", qemu_log, str_in_log=False) + finally: + backup_vmxml.sync() + test_env_obj.cleanup() diff --git a/libvirt/tests/src/virtual_network/mtu.py b/libvirt/tests/src/virtual_network/mtu.py index ab3a11659ab..ffa9d020a84 100644 --- a/libvirt/tests/src/virtual_network/mtu.py +++ b/libvirt/tests/src/virtual_network/mtu.py @@ -209,6 +209,10 @@ def check_mtu_in_vm(fn_login, mtu_size, timeout): if tap_cmd is None: test.error('No tap creating command provided.') tap_cmd = tap_cmd.format(tap_name=tap_name) + vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) + iface = vmxml.devices.by_device_tag('interface')[0] + if "driver queues" not in str(iface): + tap_cmd = tap_cmd.replace(' multi_queue', '') logging.debug('Tap creating command: \n %s', tap_cmd) # Create tap device process.run(tap_cmd, verbose=True, shell=True) @@ -231,8 +235,6 @@ def check_mtu_in_vm(fn_login, mtu_size, timeout): test.fail('Host mtu size check FAIL.') # Get iface mac address - vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) - iface = vmxml.devices.by_device_tag('interface')[0] iface_mac = iface.mac_address # Check mtu inside vm @@ -386,4 +388,7 @@ def check_mtu_in_vm(fn_login, mtu_size, timeout): process.run("ovs-vsctl del-br %s" % br, verbose=True) utils_package.package_remove(add_pkg) if create_tap: - process.run('ip tuntap del mode tap {}'.format(tap_name), verbose=True, shell=True) + tap_del_cmd = 'ip tuntap del mode tap {} multi_queue' + if "multi_queue" not in tap_cmd: + tap_del_cmd = tap_del_cmd.replace(' multi_queue', '') + process.run(tap_del_cmd.format(tap_name), verbose=True, shell=True) diff --git a/libvirt/tests/src/virtual_network/network/elements_and_attributes/network_static_route.py b/libvirt/tests/src/virtual_network/network/elements_and_attributes/network_static_route.py new file mode 100644 index 00000000000..741d253914b --- /dev/null +++ b/libvirt/tests/src/virtual_network/network/elements_and_attributes/network_static_route.py @@ -0,0 +1,49 @@ +import re + +from avocado.utils import process + +from virttest import virsh +from virttest.utils_libvirt import libvirt_network + + +def run(test, params, env): + """ + Test network static route. + """ + net_name = params.get("net_name") + net_attrs = eval(params.get('net_attrs', '{}')) + ipv4_associated_route = params.get("ipv4_associated_route") + ipv4_defined_route = params.get("ipv4_defined_route") + ipv6_associated_route = params.get("ipv6_associated_route") + ipv6_defined_routes = eval(params.get("ipv6_defined_routes")) + + def get_ip_route(bridge, ipv6=False): + """ + get ipv4 or ipv6 route on host for vnet bridge. + + :param ipv6: get ipv6 route or not(ipv4) + :param bridge: vnet bridge name + """ + ip_route_cmd = "ip -6 route" if ipv6 else "ip route" + ip_route_cmd += "|grep %s" % bridge + result = process.run(ip_route_cmd, shell=True, ignore_status=False) + return result + + try: + libvirt_network.create_or_del_network(net_attrs) + virsh.net_dumpxml(net_name, ignore_status=True) + net_info = virsh.net_info(net_name).stdout.strip() + bridge = re.search(r'Bridge:\s+(\S+)', net_info).group(1) + cmd_ret1 = get_ip_route(bridge) + if not re.search(ipv4_associated_route, cmd_ret1.stdout_text): + test.fail("The ip addr associated route '%s' is not in result." % ipv4_associated_route) + if not re.search(ipv4_defined_route, cmd_ret1.stdout_text): + test.fail("The defined static route '%s' is not in result." % ipv4_defined_route) + cmd_ret2 = get_ip_route(bridge, True) + if not re.search(ipv6_associated_route, cmd_ret2.stdout_text): + test.fail("The ipv6 addr associated route '%s' is not in result." % ipv6_associated_route) + for ipv6_def_route in ipv6_defined_routes: + if not re.search(ipv6_def_route, cmd_ret2.stdout_text): + test.fail("The defined ipv6 static route '%s' is not in result." % ipv6_def_route) + finally: + libvirt_network.create_or_del_network(net_attrs, is_del=True) diff --git a/libvirt/tests/src/virtual_network/network/net_update_dns.py b/libvirt/tests/src/virtual_network/network/net_update_dns.py new file mode 100644 index 00000000000..96e96333942 --- /dev/null +++ b/libvirt/tests/src/virtual_network/network/net_update_dns.py @@ -0,0 +1,100 @@ +import logging +import re + +from avocado.utils import process +from virttest import libvirt_version +from virttest import utils_net +from virttest import virsh +from virttest.libvirt_xml import vm_xml +from virttest.libvirt_xml.network_xml import DNSXML +from virttest.libvirt_xml.network_xml import NetworkXML +from virttest.utils_test import libvirt + +VIRSH_ARGS = {'ignore_status': False, 'debug': True} + +LOG = logging.getLogger('avocado.' + 'net_update_dns') + + +def check_pid_not_change(test, target_pids): + LOG.debug(f'Pids before operation: {target_pids}') + pids = process.run( + 'pidof virtnetworkd; pidof virtqemud', shell=True).stdout_text + if set(pids.split()) != set(target_pids.split()): + test.fail('Pids changed after operation') + + +def run(test, params, env): + """ + Check the actual network throughput for direct type interface + """ + vm_name = params.get('main_vm') + vm = env.get_vm(vm_name) + net_name = 'default' + host_iface = params.get('host_iface') + host_iface = host_iface if host_iface else utils_net.get_default_gateway( + iface_name=True, force_dhcp=True, json=True) + operation = params.get('operation') + dns_ele = params.get('dns_ele') + update_xml = params.get('update_xml') + update_attrs = eval(params.get('update_attrs', '{}')) + conf_val = params.get('conf_val') + post_check = params.get('post_check') + status_error = 'yes' == params.get('status_error', 'no') + err_msg = params.get('err_msg') + + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + bkxml = vmxml.copy() + + dns_attrs = eval(params.get('dns_attrs')) + default_net = NetworkXML.new_from_net_dumpxml('default') + bk_net = default_net.copy() + + try: + libvirt_version.is_libvirt_feature_supported(params) + + default_net.setup_attrs(dns=dns_attrs) + default_net.sync() + + virsh.net_dumpxml(net_name, **VIRSH_ARGS) + + if dns_ele == 'dns-txt': + cmd_ori_val = f'cat /var/lib/libvirt/dnsmasq/{net_name}.conf | grep txt' + if dns_ele == 'dns-host': + cmd_ori_val = f'cat /var/lib/libvirt/dnsmasq/{net_name}.addnhosts' + host_xml = DNSXML.HostXML() + host_xml.setup_attrs(**update_attrs) + update_xml = host_xml.xml + + ori_val = process.run(cmd_ori_val, shell=True).stdout_text + pids = process.run( + 'pidof virtnetworkd; pidof virtqemud', shell=True).stdout_text + + up_result = virsh.net_update( + net_name, operation, dns_ele, update_xml, debug=True) + libvirt.check_exit_status(up_result, status_error) + if err_msg: + libvirt.check_result(up_result, err_msg) + + virsh.net_dumpxml(net_name, **VIRSH_ARGS) + + if not status_error: + new_net = NetworkXML.new_from_net_dumpxml(net_name) + new_dns = new_net.dns.fetch_attrs() + dns_key = dns_ele.split('-')[-1] + for k in update_attrs.keys(): + msg = f'expect key [{k}] has value [{update_attrs[k]}], actually got [{new_dns[dns_key].get(k)}]' + LOG.debug(msg) + if new_dns[dns_key].get(k) != update_attrs[k]: + test.fail(f'Compare updated xml failed, {msg}') + + new_val = process.run(cmd_ori_val, shell=True).stdout_text + LOG.debug(f'Expect to find {conf_val} in conf file') + if not re.search(conf_val, new_val): + test.fail(f'Failed to find expected {conf_val} in conf file') + if post_check: + if post_check == 'check_pid_not_change': + check_pid_not_change(test, pids) + + finally: + bk_net.sync() + bkxml.sync() diff --git a/libvirt/tests/src/virtual_network/network/virsh_cmd/virsh_net_desc.py b/libvirt/tests/src/virtual_network/network/virsh_cmd/virsh_net_desc.py new file mode 100644 index 00000000000..6b139e7d417 --- /dev/null +++ b/libvirt/tests/src/virtual_network/network/virsh_cmd/virsh_net_desc.py @@ -0,0 +1,196 @@ +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Copyright Redhat +# +# SPDX-License-Identifier: GPL-2.0 + +# Author: Nannan Li +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +import aexpect +import re + +from virttest import libvirt_version +from virttest import remote +from virttest import virsh +from virttest.libvirt_xml import vm_xml +from virttest.utils_test import libvirt +from virttest.utils_libvirt import libvirt_network +from virttest.libvirt_xml.network_xml import NetworkXML + +VIRSH_ARGS = {'ignore_status': False, 'debug': True} + + +def virsh_net_desc(test, params, cmd): + """ + Edit description or title with virsh net-desc by cmdline or + edit space according to scenario. + + :params: test: test object. + :params: params: cfg parameter dict. + :params: cmd: virsh desc updating cmd, delete all content if cmd is empty. + """ + update_method = params.get("update_method") + update_options = params.get("opt") + net_name = params.get("net_name") + error_msg = params.get("error_msg") + + if update_method == "cmdline": + result = virsh.net_desc(net_name, extra=cmd+update_options, debug=True) + libvirt.check_exit_status(result, error_msg) + + elif update_method == "edit_space": + send_cmd = r"virsh net-desc %s %s --edit %s" % (net_name, cmd, update_options) + test.log.debug("Send cmd: %s", send_cmd) + session = aexpect.ShellSession("sudo -s") + try: + session.sendline(send_cmd) + session.send('\x1b') + session.send('ZZ') + remote.handle_prompts(session, None, None, r"[\#\$]\s*$") + except Exception as e: + if not error_msg: + test.fail("Error occurred: %s when virsh net-desc --edit" % str(e)) + session.close() + + +def check_net_desc_result(test, params, get_cmd, expected_string, existed=True): + """ + Get and check desc or title by virsh net-desc cmd. + + :params: test, test object. + :params: params, params object. + :params: get_cmd, the get cmd for virsh net-desc. + :params: expected_string, expected result string. + :params: existed, the flag of expected result string exist or not. + """ + net_name = params.get("net_name") + update_options = params.get("opt") + + result = virsh.net_desc(net_name, extra=get_cmd+update_options, debug=True) + if existed: + if result.stdout.strip() != expected_string: + test.fail('Expect "%s" was existed.' % expected_string) + else: + if result.stderr.strip() != expected_string: + test.fail('Expect "%s" was not existed.' % expected_string) + test.log.debug("Check '%s' PASS in virsh net-desc", expected_string) + + +def _confirm_existed(params, dumpxml_opt, check_remove): + """ + Get existed value according to the scenario. + + :params: params, params object. + :params: dumpxml_opt, virsh net-dumpxml option, '--inactive' or '' + :params: check_remove, check net-dumpxml after removing. + :return: expected xml was existed flag. + """ + opt = params.get('opt') + network_states = params.get('network_states') + + existed = True + if ((dumpxml_opt == " " and opt == ' --config' and network_states == 'active_net') + or (dumpxml_opt == " --inactive" and opt == " --live") + or (dumpxml_opt == " --inactive" and network_states == 'active_net' and opt in [' --current', ' ']) + or check_remove): + existed = False + + return existed + + +def check_net_dumpxml(test, params, expected_xml, check_remove=False): + """ + Check if expected xml in virsh net-dumpxml. + + :params: test, test object. + :params: params, params object. + :params: expected_xml, expected xml string. + :params: check_remove, check net-dumpxml after removing, default False + """ + net_name = params.get("net_name") + + dumpxml_opt = [" ", " --inactive"] + for dump in dumpxml_opt: + existed = _confirm_existed(params, dump, check_remove) + result = virsh.net_dumpxml(net_name, dump, debug=True).stdout.strip() + if existed: + if not re.findall(expected_xml, result): + test.fail('Expect %s was existed' % expected_xml) + else: + if re.findall(expected_xml, result): + test.fail('Expect %s was not existed' % expected_xml) + test.log.debug("Checked '%s' PASS in active and inactive xml" % expected_xml) + + +def run(test, params, env): + """ + Test 'virsh net-desc' with different options to show or modify network description + or title. + """ + def setup_test(): + """ + Prepare network status. + """ + test.log.info("TEST_SETUP: Prepare network status.") + libvirt_network.ensure_default_network() + if network_states == "inactive_net": + virsh.net_destroy(net_name, **VIRSH_ARGS) + + def run_test(): + """ + 1. Update and remove network description or title. + 2. Check description xml is existed or removed. + """ + test.log.info("TEST_STEP1:Set a %s xml for network." % update_item) + virsh_net_desc(test, params, execute_cmd) + if error_msg: + return + + test.log.info("TEST_STEP2: Check correct %s xml in network." % update_item) + check_net_desc_result(test, params, get_cmd, expected_str) + check_net_dumpxml(test, params, expected_xml) + + test.log.info("TEST_STEP3-4: Modify and check %s xml in network." % update_item) + virsh_net_desc(test, params, execute_update_cmd) + check_net_desc_result(test, params, get_cmd, expected_update_str) + check_net_dumpxml(test, params, expected_update_xml) + + test.log.info("TEST_STEP5-6: Remove and check %s xml in network." % update_item) + virsh_net_desc(test, params, remove_opt) + check_net_desc_result(test, params, get_cmd, removed_msg) + check_net_dumpxml(test, params, expected_update_xml, check_remove=True) + + def teardown_test(): + """ + Clean data. + """ + test.log.info("TEST_TEARDOWN: Clean up env.") + bk_net.sync() + bkxml.sync() + libvirt_network.ensure_default_network() + + libvirt_version.is_libvirt_feature_supported(params) + vm_name = params.get('main_vm') + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + bkxml = vmxml.copy() + default_net = NetworkXML.new_from_net_dumpxml('default') + bk_net = default_net.copy() + + net_name = params.get("net_name") + network_states = params.get("network_states") + update_item = params.get("update_item") + error_msg = params.get("error_msg") + remove_opt = params.get("remove_opt") + removed_msg = params.get("removed_msg") + get_cmd = params.get("get_cmd") + execute_cmd, execute_update_cmd = params.get('execute_cmd'), params.get("execute_update_cmd") + expected_str, expected_update_str = params.get("expected_str"), params.get("expected_update_str") + expected_xml, expected_update_xml = params.get("expected_xml"), params.get("expected_update_xml") + + try: + setup_test() + run_test() + + finally: + teardown_test() diff --git a/libvirt/tests/src/virtual_network/network/virsh_cmds/virsh_net_metadata.py b/libvirt/tests/src/virtual_network/network/virsh_cmds/virsh_net_metadata.py new file mode 100644 index 00000000000..59872fb4e71 --- /dev/null +++ b/libvirt/tests/src/virtual_network/network/virsh_cmds/virsh_net_metadata.py @@ -0,0 +1,181 @@ +import aexpect +import re + +from virttest import libvirt_version +from virttest import virsh +from virttest.libvirt_xml import vm_xml +from virttest.utils_test import libvirt +from virttest.utils_libvirt import libvirt_network +from virttest.libvirt_xml.network_xml import NetworkXML + +VIRSH_ARGS = {'ignore_status': False, 'debug': True} + + +def edit_metadata(test, params, metadata_cmd, **dargs): + """ + Edit metadata with cmdline or edit space according to scenario. + + :params: test: test object. + :params: params: cfg parameter dict. + :params: metadata_cmd: metadata updating cmd. + :param dargs: mutable parameter dict. + """ + update_options = params.get("opt") + update_method = params.get("update_method") + metadata_uri = params.get("metadata_uri") + net_name = params.get("net_name") + error_msg = params.get("error_msg") + + if update_method == "cmdline": + result = virsh.net_metadata(net_name, metadata_uri, + extra=metadata_cmd+update_options, debug=True) + libvirt.check_exit_status(result, error_msg) + + elif update_method == "edit_space": + prefix = re.findall("(--key.* )-", metadata_cmd)[0] + ele_name = re.findall("--set \'(.*)\' ", metadata_cmd)[0] + + send_cmd = r"virsh net-metadata %s --uri %s %s --edit %s" % ( + net_name, metadata_uri, prefix, update_options) + test.log.debug("Send updating metadate cmd: %s", send_cmd) + + session = aexpect.ShellSession("sudo -s") + try: + session.sendline(send_cmd) + if "clean_content" in dargs: + session.send('dG') + session.send('i') + session.sendline(ele_name) + session.send('\x1b') + session.send('ZZ') + session.read_until_any_line_matches( + [r"Metadata modified"], timeout=10, internal_timeout=1) + except Exception as e: + if not error_msg: + test.fail("Error occurred: %s when virsh net-metadata --edit" % str(e)) + session.close() + + +def check_net_metadata_result(test, params, expected_string, existed=True): + """ + Check expected result in virsh net-metadata. + + :params: test, test object. + :params: params, params object. + :params: expected_string, expected result string. + :params: existed, the flag of expected result string exist or not. + """ + update_options = params.get("opt") + metadata_uri = params.get("metadata_uri") + net_name = params.get("net_name") + + result = virsh.net_metadata(net_name, metadata_uri, + extra=update_options, debug=True) + if existed: + if result.stdout.strip() != expected_string: + test.fail('Expect "%s" was existed.' % expected_string) + else: + if result.stderr.strip() != expected_string: + test.fail('Expect "%s" was existed.' % expected_string) + test.log.debug("Check %s PASS in virsh net-metadata", expected_string) + + +def check_net_dumpxml(test, params, expected_xml, exist): + """ + Check if expected xml in virsh net-dumpxml. + + :params: test, test object. + :params: params, params object. + :params: expected_xml, expected xml string. + :params: exist, exist or not. + """ + net_name = params.get("net_name") + dumpxml_opt = params.get("dumpxml_opt") + + result = virsh.net_dumpxml(net_name, dumpxml_opt).stdout.strip() + if exist: + if not re.findall(expected_xml, result): + test.fail('Expect %s was existed but got %s.' % (expected_xml, result)) + else: + if re.findall(expected_xml, result): + test.fail('Expect %s was not existed but got %s.' % (expected_xml, result)) + + test.log.debug("Checked %s PASS" % expected_xml) + + +def run(test, params, env): + """ + Test 'virsh net-metadata' with different options to show or + modify the XML metadata of a network. + """ + def setup_test(): + """ + Prepare network status. + """ + test.log.info("TEST_SETUP: Prepare network status.") + libvirt_network.ensure_default_network() + if network_states == "inactive_net": + virsh.net_destroy(net_name, **VIRSH_ARGS) + + def run_test(): + """ + 1. Update and remove network metadata. + 2. Check metadata xml is existed or removed. + """ + test.log.info("TEST_STEP1:Set a xml metadata for network.") + edit_metadata(test, params, metadata_cmd=metadata_extra) + if error_msg: + return + + test.log.info("TEST_STEP2: Check correct metadata xml in network.") + check_net_metadata_result(test, params, expected_xml) + check_net_dumpxml(test, params, expected_metadata_xml, exist) + + test.log.info("TEST_STEP3-4: Modify and check metadata xml in network.") + edit_metadata(test, params, metadata_cmd=metadata_extra_update, clean_content=True) + check_net_metadata_result(test, params, expected_update_xml) + check_net_dumpxml(test, params, expected_update_metadata_xml, exist) + + test.log.info("TEST_STEP5-6: Remove and check metadata xml in network.") + virsh.net_metadata(net_name, metadata_uri, + extra=update_options+remove_opt, **VIRSH_ARGS) + check_net_metadata_result(test, params, removed_msg, existed=False) + check_net_dumpxml(test, params, expected_update_metadata_xml, exist=False) + + def teardown_test(): + """ + Clean data. + """ + test.log.info("TEST_TEARDOWN: Clean up env.") + bk_net.sync() + bkxml.sync() + libvirt_network.ensure_default_network() + + libvirt_version.is_libvirt_feature_supported(params) + vm_name = params.get('main_vm') + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + bkxml = vmxml.copy() + default_net = NetworkXML.new_from_net_dumpxml('default') + bk_net = default_net.copy() + + net_name = params.get("net_name") + network_states = params.get("network_states") + metadata_extra = params.get('metadata_extra') + metadata_extra_update = params.get("metadata_extra_update") + metadata_uri = params.get("metadata_uri") + update_options = params.get("opt") + error_msg = params.get("error_msg") + remove_opt = params.get("remove_opt") + expected_xml = params.get("expected_xml") + expected_metadata_xml = params.get("expected_metadata_xml") + expected_update_xml = params.get("expected_update_xml") + expected_update_metadata_xml = params.get("expected_update_metadata_xml") + exist = params.get("exist", "no") == "yes" + removed_msg = params.get("removed_msg") + + try: + setup_test() + run_test() + + finally: + teardown_test() diff --git a/libvirt/tests/src/virtual_network/network_misc.py b/libvirt/tests/src/virtual_network/network_misc.py index 35e14960f80..a21df2a9f00 100644 --- a/libvirt/tests/src/virtual_network/network_misc.py +++ b/libvirt/tests/src/virtual_network/network_misc.py @@ -1,18 +1,17 @@ import logging as log import re -from avocado.utils.software_manager.backends import rpm from avocado.utils import process from avocado.utils import service - +from avocado.utils.software_manager.backends import rpm from virttest import libvirt_version from virttest import utils_misc from virttest import utils_net from virttest import virsh - from virttest.libvirt_xml import vm_xml from virttest.libvirt_xml.devices import interface from virttest.libvirt_xml.network_xml import NetworkXML +from virttest.utils_libvirt import libvirt_network from virttest.utils_test import libvirt DEFAULT_NET = 'default' @@ -44,9 +43,12 @@ def run(test, params, env): vm = env.get_vm(vm_name) machine_type = params.get('machine_type') net = params.get('net', DEFAULT_NET) + ran_id = utils_misc.generate_random_string(3) + net_name = 'net_' + ran_id + net_attrs = eval(params.get('net_attrs', '{}')) status_error = 'yes' == params.get('status_error', 'no') expect_str = params.get('expect_str') - bridge_name = 'br_' + utils_misc.generate_random_string(3) + bridge_name = 'br_' + ran_id test_group = params.get('test_group', 'default') case = params.get('case', '') @@ -86,17 +88,29 @@ def setup_test_zone(case): setup_firewalld() - # Setup zone for bridge - netxml = NetworkXML.new_from_net_dumpxml(net) - if case == 'public': - netxml.bridge = {'name': bridge_name, 'zone': 'public'} - elif case == 'info': - netxml.bridge = {'name': bridge_name} - else: - test.error('Test "%s" is not supported.' % case) - netxml.forward = {'mode': 'nat'} - netxml.sync() - logging.debug('Updated net:\n%s', virsh.net_dumpxml(net).stdout_text) + def setup_test_zone_default(): + # Setup zone for bridge + netxml = NetworkXML.new_from_net_dumpxml(net) + if case == 'info': + netxml.bridge = {'name': bridge_name} + else: + test.error('Test "%s" is not supported.' % case) + netxml.forward = {'mode': 'nat'} + netxml.sync() + logging.debug('Updated net:\n%s', + virsh.net_dumpxml(net).stdout_text) + + def setup_test_zone_libvirt_managed(): + if params.get('forward_mode') == 'isolated': + net_attrs.pop('forward') + libvirt_network.create_or_del_network(net_attrs) + + def setup_test_zone_public(): + libvirt_network.create_or_del_network(net_attrs) + + setup_zone = eval('setup_test_zone_%s' % case) if \ + 'setup_test_zone_%s' % case in locals() else setup_test_zone_default + setup_zone() def run_test_zone(case): """ @@ -104,31 +118,76 @@ def run_test_zone(case): :param case: test case """ - - def run_test_zone_public(): + def check_zone(iface, expect_zone): """ - Check zone of interface with firewalld-cmd + Check whether zone info meets expectation """ - check_cmd = 'firewall-cmd --get-zone-of-interface=%s' % bridge_name - output = process.run(check_cmd, verbose=True).stdout_text.strip() - if output == 'public': + check_cmd = 'firewall-cmd --get-zone-of-interface=%s' % iface + cmd_result = process.run(check_cmd, ignore_status=True) + output = cmd_result.stdout_text.strip() + cmd_result.stderr_text.strip() + if output == expect_zone: logging.info('Zone check of interface PASSED') + return output else: - test.fail('Zone check of interface FAILED, should be public, but got %s' % output) + test.fail( + f'Zone check of interface FAILED, should be {expect_zone}, but got %s' % output) - def run_test_zone_info(): + def check_zone_info(br, zone): """ Check zone info with firewalld-cmd """ - check_cmd = 'firewall-cmd --info-zone=libvirt' + check_cmd = f'firewall-cmd --info-zone={zone}' output = process.run(check_cmd, verbose=True).stdout_text.strip() - br = bridge_name for item in eval(expect_str): if item in output or re.search(item, output): logging.debug('Found "%s" in firewalld-cmd output' % item) else: test.fail('Not found "%s" in firewalld-cmd output' % item) + def run_test_zone_public(): + """ + Check zone of interface with firewalld-cmd + """ + net_attrs = NetworkXML.new_from_net_dumpxml(net_name).fetch_attrs() + net_br_attrs = net_attrs['bridge'] + if net_attrs['bridge']['zone'] != 'public': + test.fail(f"Network {net_name} zone should be 'public'," + f"not {net_attrs['bridge']['zone']}") + + check_zone(net_br_attrs['name'], 'public') + process.run('firewall-cmd --reload') + utils_misc.wait_for( + lambda: check_zone(net_br_attrs['name'], 'public'), + timeout=10, ignore_errors=True) + + def run_test_zone_info(): + """ + Check zone info with firewalld-cmd + """ + check_zone_info(bridge_name, 'libvirt') + + def run_test_zone_libvirt_managed(): + br_attrs = eval(params.get('br_attrs', {})) + default_zone = params.get('default_zone') + + virsh.net_dumpxml(net_name, **VIRSH_ARGS) + net_attrs = NetworkXML.new_from_net_dumpxml(net_name).fetch_attrs() + net_br_attrs = net_attrs['bridge'] + if not set(br_attrs.items()).issubset(set(net_br_attrs.items())): + test.fail( + f'libvirt should create a linux bridge named ' + f'{net_br_attrs["name"]}, with stp=on, delay=0') + + check_zone(net_br_attrs['name'], default_zone) + if default_zone in ('no zone', 'libvirt-routed'): + logging.info(f'Skip checking zone info for "{default_zone}"') + else: + check_zone_info(net_br_attrs['name'], default_zone) + process.run('firewall-cmd --reload') + utils_misc.wait_for( + lambda: check_zone(net_br_attrs['name'], default_zone), + timeout=10, ignore_errors=True) + test_zone = eval('run_test_zone_%s' % case) test_zone() @@ -235,4 +294,6 @@ def run_test_iface_acpi(case): finally: bk_netxml.sync() + if net_attrs: + libvirt_network.create_or_del_network(net_attrs, is_del=True) bk_xml.sync() diff --git a/libvirt/tests/src/virtual_network/passt/passt_attach_detach.py b/libvirt/tests/src/virtual_network/passt/passt_attach_detach.py index 153e644084c..9a96e0cdd19 100644 --- a/libvirt/tests/src/virtual_network/passt/passt_attach_detach.py +++ b/libvirt/tests/src/virtual_network/passt/passt_attach_detach.py @@ -1,6 +1,7 @@ import logging import os import shutil +import time import aexpect from virttest import libvirt_version @@ -10,6 +11,7 @@ from virttest import virsh from virttest.libvirt_xml import vm_xml from virttest.staging import service +from virttest.staging import utils_memory from virttest.utils_libvirt import libvirt_unprivileged from virttest.utils_libvirt import libvirt_vmxml @@ -56,7 +58,7 @@ def run(test, params, env): test_passwd, **unpr_vm_args) uri = f'qemu+ssh://{test_user}@localhost/session' - virsh_ins = virsh.VirshPersistent(uri=uri) + virsh_ins = virsh.Virsh(uri=uri) host_session = aexpect.ShellSession('su') remote.VMManager.set_ssh_auth(host_session, 'localhost', test_user, test_passwd) @@ -65,24 +67,26 @@ def run(test, params, env): scenario = params.get('scenario') virsh_uri = params.get('virsh_uri') add_iface = 'yes' == params.get('add_iface', 'no') - host_ip = utils_net.get_host_ip_address(ip_ver='ipv4') - host_ip_v6 = utils_net.get_host_ip_address(ip_ver='ipv6') + host_iface = params.get('host_iface') + host_iface = host_iface if host_iface else utils_net.get_default_gateway( + iface_name=True, force_dhcp=True, json=True) + host_ip = utils_net.get_ip_address_by_interface(host_iface, ip_ver='ipv4') + host_ip_v6 = utils_net.get_ip_address_by_interface(host_iface, ip_ver='ipv6') iface_attrs = eval(params.get('iface_attrs')) params['socket_dir'] = socket_dir = eval(params.get('socket_dir')) params['proc_checks'] = proc_checks = eval(params.get('proc_checks', '{}')) - vm_iface = params.get('vm_iface', 'eno1') mtu = params.get('mtu') outside_ip = params.get('outside_ip') - host_iface = params.get('host_iface') - host_iface = host_iface if host_iface else utils_net.get_net_if( - state="UP")[0] log_file = f'/run/user/{user_id}/passt.log' iface_attrs['backend']['logFile'] = log_file iface_attrs['source']['dev'] = host_iface + vhostuser = 'yes' == params.get('vhostuser', 'no') + multiple_nexthops = 'yes' == params.get('multiple_nexthops', 'no') vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name, virsh_instance=virsh_ins) bkxml = vmxml.copy() + shp_orig_num = utils_memory.get_num_huge_pages() selinux_status = passt.ensure_selinux_enforcing() passt.check_socat_installed() @@ -93,6 +97,10 @@ def run(test, params, env): passt.make_log_dir(user_id, log_dir) vmxml.del_device('interface', by_tag=True) + if vhostuser: + # update vm xml with shared memory and vhostuser interface + vm_xml.VMXML.set_memoryBacking_tag(vm_name, access_mode="shared", hpgs=False, memfd=True, vmxml=vmxml) + iface_attrs['type_name'] = 'vhostuser' iface_device = libvirt_vmxml.create_vm_device_by_type('interface', iface_attrs) LOG.debug(f'iface_device: {iface_device}') @@ -123,10 +131,13 @@ def run(test, params, env): if not os.path.exists(log_file): test.fail(f'Logfile of passt "{log_file}" not created') + # wait for the vm boot before first time to try serial login + time.sleep(5) session = vm.wait_for_serial_login(timeout=60) - passt.check_vm_ip(iface_attrs, session, host_iface) + vm_iface = utils_net.get_linux_ifname(session, mac) + passt.check_vm_ip(iface_attrs, session, host_iface, vm_iface) passt.check_vm_mtu(session, vm_iface, mtu) - passt.check_default_gw(session) + passt.check_default_gw(session, host_iface, multiple_nexthops) passt.check_nameserver(session) ips = { @@ -138,7 +149,8 @@ def run(test, params, env): firewalld.stop() LOG.debug(f'Service status of firewalld: {firewalld.status()}') passt.check_connection(vm, vm_iface, - ['TCP4', 'TCP6', 'UDP4', 'UDP6']) + ['TCP4', 'TCP6', 'UDP4', 'UDP6'], + host_iface) if 'portForwards' in iface_attrs: passt.check_portforward(vm, host_ip, params) @@ -146,14 +158,14 @@ def run(test, params, env): if 'detach' not in scenario: vm.destroy() passt.check_passt_pid_not_exist() - if os.listdir(socket_dir): - test.fail(f'Socket dir is not empty: {os.listdir(socket_dir)}') else: vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name, virsh_instance=virsh_ins) LOG.debug(f'vmxml before detach:\n{vmxml}') iface_to_detach = vmxml.get_devices('interface')[0] mac = iface_to_detach.mac_address + # Wait for guest os to boot completely before detaching interface + vm.wait_for_serial_login(timeout=60).close() virsh.detach_device(vm_name, iface_to_detach.xml, wait_for_event=True, event_timeout=15, @@ -176,6 +188,4 @@ def run(test, params, env): bkxml.sync(virsh_instance=virsh_ins) if root: shutil.rmtree(log_dir) - else: - del virsh_ins utils_selinux.set_status(selinux_status) diff --git a/libvirt/tests/src/virtual_network/passt/passt_connectivity_between_2vms.py b/libvirt/tests/src/virtual_network/passt/passt_connectivity_between_2vms.py index d4ea9a86d38..e88cebdc5aa 100644 --- a/libvirt/tests/src/virtual_network/passt/passt_connectivity_between_2vms.py +++ b/libvirt/tests/src/virtual_network/passt/passt_connectivity_between_2vms.py @@ -1,5 +1,6 @@ import logging import shutil +import time import aexpect from virttest import libvirt_version @@ -51,7 +52,7 @@ def run(test, params, env): test_passwd, **unpr_vm_args) uri = f'qemu+ssh://{test_user}@localhost/session' - virsh_ins = virsh.VirshPersistent(uri=uri) + virsh_ins = virsh.Virsh(uri=uri) host_session = aexpect.ShellSession('su') remote.VMManager.set_ssh_auth(host_session, 'localhost', test_user, test_passwd) @@ -64,10 +65,9 @@ def run(test, params, env): iface_c_attrs = eval(params.get('iface_c_attrs')) params['socket_dir'] = socket_dir = eval(params.get('socket_dir')) params['proc_checks'] = proc_checks = eval(params.get('proc_checks', '{}')) - vm_c_iface = params.get('vm_c_iface', 'eno1') host_iface = params.get('host_iface') - host_iface = host_iface if host_iface else utils_net.get_net_if( - state="UP")[0] + host_iface = host_iface if host_iface else utils_net.get_default_gateway( + iface_name=True, force_dhcp=True, json=True) iface_attrs['backend']['logFile'] = log_file iface_c_attrs['backend']['logFile'] = log_file_c iface_attrs['source']['dev'] = host_iface @@ -95,16 +95,20 @@ def run(test, params, env): [LOG.debug(virsh.dumpxml(vm_name, uri=virsh_uri).stdout_text) for vm_name in (vm_name, vm_c.name)] + # wait for the vm boot before first time to try serial login + time.sleep(5) server_session = vm.wait_for_serial_login(60) client_session = vm_c.wait_for_serial_login(60) + mac = vm_c.get_virsh_mac_address() + vm_c_iface = utils_net.get_linux_ifname(client_session, mac) [LOG.debug(session.cmd_output('ip a')) for session in (server_session, client_session)] server_default_gw = utils_net.get_default_gateway( - session=server_session, force_dhcp=True) + session=server_session, force_dhcp=True, json=True) server_default_gw_v6 = utils_net.get_default_gateway( - session=server_session, ip_ver='ipv6') + session=server_session, ip_ver='ipv6', json=True) firewalld.stop() server_session.cmd('systemctl stop firewalld') @@ -128,6 +132,4 @@ def run(test, params, env): bkxml_c.sync(virsh_instance=virsh_ins) if root: shutil.rmtree(log_dir) - else: - del virsh_ins utils_selinux.set_status(selinux_status) diff --git a/libvirt/tests/src/virtual_network/passt/passt_function.py b/libvirt/tests/src/virtual_network/passt/passt_function.py index 97c1425f413..903f8e2d71e 100644 --- a/libvirt/tests/src/virtual_network/passt/passt_function.py +++ b/libvirt/tests/src/virtual_network/passt/passt_function.py @@ -10,6 +10,7 @@ from virttest import virsh from virttest.libvirt_xml import vm_xml from virttest.staging import service +from virttest.staging import utils_memory from virttest.utils_libvirt import libvirt_unprivileged from virttest.utils_libvirt import libvirt_vmxml @@ -46,31 +47,32 @@ def run(test, params, env): test_passwd, **unpr_vm_args) uri = f'qemu+ssh://{test_user}@localhost/session' - virsh_ins = virsh.VirshPersistent(uri=uri) + virsh_ins = virsh.Virsh(uri=uri) host_session = aexpect.ShellSession('su') remote.VMManager.set_ssh_auth(host_session, 'localhost', test_user, test_passwd) host_session.close() - host_ip = utils_net.get_host_ip_address(ip_ver='ipv4') - params['host_ip_v6'] = host_ip_v6 = utils_net.get_host_ip_address( - ip_ver='ipv6') - iface_attrs = eval(params.get('iface_attrs')) + host_iface = params.get('host_iface') + host_iface = host_iface if host_iface else utils_net.get_default_gateway( + iface_name=True, force_dhcp=True, json=True) + host_ip = utils_net.get_ip_address_by_interface(host_iface, ip_ver='ipv4') + host_ip_v6 = utils_net.get_ip_address_by_interface(host_iface, ip_ver='ipv6') + params['host_ip_v6'] = host_ip_v6 params['socket_dir'] = socket_dir = eval(params.get('socket_dir')) params['proc_checks'] = proc_checks = eval(params.get('proc_checks', '{}')) - vm_iface = params.get('vm_iface', 'eno1') mtu = params.get('mtu') outside_ip = params.get('outside_ip') - host_iface = params.get('host_iface') - host_iface = host_iface if host_iface else utils_net.get_net_if( - state="UP")[0] log_file = f'/run/user/{user_id}/passt.log' + iface_attrs = eval(params.get('iface_attrs')) iface_attrs['backend']['logFile'] = log_file - iface_attrs['source']['dev'] = host_iface + vhostuser = 'yes' == params.get('vhostuser', 'no') + multiple_nexthops = 'yes' == params.get('multiple_nexthops', 'no') vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name, virsh_instance=virsh_ins) bkxml = vmxml.copy() + shp_orig_num = utils_memory.get_num_huge_pages() selinux_status = passt.ensure_selinux_enforcing() passt.check_socat_installed() @@ -85,6 +87,10 @@ def run(test, params, env): vmxml.del_device('interface', by_tag=True) vmxml.sync(virsh_instance=virsh_ins) + if vhostuser: + # update vm xml with shared memory and vhostuser interface + vm_xml.VMXML.set_memoryBacking_tag(vm_name, access_mode="shared", hpgs=False, memfd=True, vmxml=vmxml) + iface_attrs['type_name'] = 'vhostuser' libvirt_vmxml.modify_vm_device(vmxml, 'interface', iface_attrs, virsh_instance=virsh_ins) LOG.debug(virsh_ins.dumpxml(vm_name).stdout_text) @@ -94,13 +100,15 @@ def run(test, params, env): passt.check_proc_info(params, log_file, mac) # check the passt log + LOG.debug(virsh.dumpxml(vm_name)) if not os.path.exists(log_file): test.fail(f'Logfile of passt "{log_file}" not created') session = vm.wait_for_serial_login(timeout=60) - passt.check_vm_ip(iface_attrs, session, host_iface) + vm_iface = utils_net.get_linux_ifname(session, mac) + passt.check_vm_ip(iface_attrs, session, host_iface, vm_iface) passt.check_vm_mtu(session, vm_iface, mtu) - passt.check_default_gw(session) + passt.check_default_gw(session, host_iface, multiple_nexthops) passt.check_nameserver(session) ips = { @@ -112,24 +120,22 @@ def run(test, params, env): firewalld.stop() LOG.debug(f'Status of firewalld: {firewalld.status()}') - passt.check_connection(vm, vm_iface, ['TCP4', 'TCP6', 'UDP4', 'UDP6']) + passt.check_connection(vm, vm_iface, + ['TCP4', 'TCP6', 'UDP4', 'UDP6'], + host_iface) if 'portForwards' in iface_attrs: - passt.check_portforward(vm, host_ip, params) + passt.check_portforward(vm, host_ip, params, host_iface) vm_sess = vm.wait_for_serial_login(timeout=60) vm_sess.cmd('systemctl start firewalld') vm.destroy() passt.check_passt_pid_not_exist() - if os.listdir(socket_dir): - test.fail(f'Socket dir is not empty: {os.listdir(socket_dir)}') finally: firewalld.start() bkxml.sync(virsh_instance=virsh_ins) if root: shutil.rmtree(log_dir) - else: - del virsh_ins utils_selinux.set_status(selinux_status) diff --git a/libvirt/tests/src/virtual_network/passt/passt_lifecycle.py b/libvirt/tests/src/virtual_network/passt/passt_lifecycle.py new file mode 100644 index 00000000000..0a4d9fb59a1 --- /dev/null +++ b/libvirt/tests/src/virtual_network/passt/passt_lifecycle.py @@ -0,0 +1,168 @@ +import logging +import os +import shutil + +import aexpect +from virttest import libvirt_version +from virttest import remote +from virttest import utils_misc +from virttest import utils_net +from virttest import utils_selinux +from virttest import virsh +from virttest.libvirt_xml import vm_xml +from virttest.staging import service +from virttest.staging import utils_memory +from virttest.utils_libvirt import libvirt_unprivileged +from virttest.utils_libvirt import libvirt_vmxml + +from provider.virtual_network import network_base +from provider.virtual_network import passt + +LOG = logging.getLogger('avocado.' + __name__) + +IPV6_LENGTH = 128 +VIRSH_ARGS = {'ignore_status': False, 'debug': True} + + +def run(test, params, env): + """ + Test passt lifecycle + """ + libvirt_version.is_libvirt_feature_supported(params) + root = 'root_user' == params.get('user_type', '') + test_user = params.get('test_user') + if root: + vm_name = params.get('main_vm') + vm = env.get_vm(vm_name) + virsh_ins = virsh + log_dir = params.get('log_dir') + user_id = params.get('user_id') + else: + vm_name = params.get('unpr_vm_name') + test_user = params.get('test_user', '') + test_passwd = params.get('test_passwd', '') + user_id = passt.get_user_id(test_user) + unpr_vm_args = { + 'username': params.get('username'), + 'password': params.get('password'), + } + vm = libvirt_unprivileged.get_unprivileged_vm(vm_name, test_user, + test_passwd, + **unpr_vm_args) + uri = f'qemu+ssh://{test_user}@localhost/session' + virsh_ins = virsh.Virsh(uri=uri) + host_session = aexpect.ShellSession('su') + remote.VMManager.set_ssh_auth(host_session, 'localhost', test_user, + test_passwd) + host_session.close() + + host_iface = params.get('host_iface') + host_iface = host_iface if host_iface else utils_net.get_net_if( + state="UP")[0] + host_ip = utils_net.get_ip_address_by_interface(host_iface, ip_ver='ipv4') + host_ip_v6 = utils_net.get_ip_address_by_interface( + host_iface, ip_ver='ipv6') + params['host_ip_v6'] = host_ip_v6 + params['socket_dir'] = socket_dir = eval(params.get('socket_dir')) + params['proc_checks'] = proc_checks = eval(params.get('proc_checks', '{}')) + mtu = params.get('mtu') + outside_ip = params.get('outside_ip') + log_file = f'/run/user/{user_id}/passt.log' + iface_attrs = eval(params.get('iface_attrs')) + iface_attrs['backend']['logFile'] = log_file + operation_a = params.get('operation_a') + operation_b = params.get('operation_b') + save_path = f'/tmp/save_{utils_misc.generate_random_string(3)}' + options_a = eval(params.get('options_a', '{}')) + options_b = eval(params.get('options_b', '{}')) + passt_running = 'yes' == params.get('passt_running', 'no') + vhostuser = 'yes' == params.get('vhostuser', 'no') + multiple_nexthops = 'yes' == params.get('multiple_nexthops', 'no') + + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name, + virsh_instance=virsh_ins) + bkxml = vmxml.copy() + shp_orig_num = utils_memory.get_num_huge_pages() + + selinux_status = passt.ensure_selinux_enforcing() + passt.check_socat_installed() + + firewalld = service.Factory.create_service("firewalld") + try: + operation_a = eval(f'virsh_ins.{operation_a}') + operation_b = eval(f'virsh_ins.{operation_b}') + + if root: + passt.make_log_dir(user_id, log_dir) + + default_gw = utils_net.get_default_gateway() + default_gw_v6 = utils_net.get_default_gateway(ip_ver='ipv6') + + vmxml.del_device('interface', by_tag=True) + vmxml.sync(virsh_instance=virsh_ins) + libvirt_vmxml.modify_vm_device(vmxml, 'interface', iface_attrs, + virsh_instance=virsh_ins) + if vhostuser: + # update vm xml with shared memory and vhostuser interface + vm_xml.VMXML.set_memoryBacking_tag(vm_name, access_mode="shared", hpgs=False, memfd=True, vmxml=vmxml) + iface_attrs['type_name'] = 'vhostuser' + LOG.debug(virsh_ins.dumpxml(vm_name).stdout_text) + mac = vm.get_virsh_mac_address() + + vm.start() + passt.check_proc_info(params, log_file, mac) + + options_a = {'name': vm_name} if not options_a else options_a + options_b = {'name': vm_name} if not options_b else options_b + operation_a(**options_a, **VIRSH_ARGS) + if passt_running: + passt.check_proc_info(params, log_file, mac) + else: + passt.check_passt_pid_not_exist() + operation_b(**options_b, **VIRSH_ARGS) + + # Check the passt log + if not os.path.exists(log_file): + test.fail(f'Logfile of passt "{log_file}" not created') + + # Re-create console since vm has been restored/resumed + vm.cleanup_serial_console() + vm.create_serial_console() + session = vm.wait_for_serial_login(timeout=60) + + vm_iface = utils_net.get_linux_ifname(session, mac) + passt.check_vm_ip(iface_attrs, session, host_iface, vm_iface) + passt.check_vm_mtu(session, vm_iface, mtu) + passt.check_default_gw(session, host_iface, multiple_nexthops) + passt.check_nameserver(session) + + ips = { + 'outside_ip': outside_ip, + 'host_public_ip': host_ip, + } + network_base.ping_check(params, ips, session, force_ipv4=True) + session.close() + + firewalld.stop() + LOG.debug(f'Status of firewalld: {firewalld.status()}') + passt.check_connection(vm, vm_iface, + ['TCP4', 'TCP6', 'UDP4', 'UDP6'], + host_iface) + + if 'portForwards' in iface_attrs: + passt.check_portforward(vm, host_ip, params, host_iface) + + vm_sess = vm.wait_for_serial_login(timeout=60) + vm_sess.cmd('systemctl start firewalld') + vm.destroy() + + passt.check_passt_pid_not_exist() + + finally: + firewalld.start() + bkxml.sync(virsh_instance=virsh_ins) + if root: + shutil.rmtree(log_dir) + utils_selinux.set_status(selinux_status) + if os.path.exists(save_path): + os.remove(save_path) diff --git a/libvirt/tests/src/virtual_network/passt/passt_negative_setting.py b/libvirt/tests/src/virtual_network/passt/passt_negative_setting.py index 136f114019a..a97aa0d082c 100644 --- a/libvirt/tests/src/virtual_network/passt/passt_negative_setting.py +++ b/libvirt/tests/src/virtual_network/passt/passt_negative_setting.py @@ -17,7 +17,9 @@ from provider.virtual_network import passt +VIRSH_ARGS = {'ignore_status': False, 'debug': True} LOG = logging.getLogger('avocado.' + __name__) +DOWN_IFACE_NAME = "br1234" def run(test, params, env): @@ -41,7 +43,7 @@ def run(test, params, env): remote.VMManager.set_ssh_auth(host_session, 'localhost', test_user, test_passwd) host_session.close() - virsh_ins = virsh.VirshPersistent(uri=virsh_uri) + virsh_ins = virsh.Virsh(uri=virsh_uri) scenario = params.get('scenario') operation = params.get('operation') @@ -49,8 +51,8 @@ def run(test, params, env): error_msg = params.get('error_msg') iface_attrs = eval(params.get('iface_attrs')) host_iface = params.get('host_iface') - host_iface = host_iface if host_iface else utils_net.get_net_if( - state="UP")[0] + host_iface = host_iface if host_iface else utils_net.get_default_gateway( + iface_name=True, force_dhcp=True, json=True) log_file = f'/run/user/{user_id}/passt.log' \ if not params.get('log_file') else params['log_file'] iface_attrs['backend']['logFile'] = log_file @@ -73,12 +75,9 @@ def run(test, params, env): if scenario == 'rm_passt_pgk': utils_package.package_remove('passt') elif scenario == 'inactive_host_iface': - inactive_iface_list = [iface for iface in host_iface_list - if iface['operstate'] == 'DOWN'] - if not inactive_iface_list: - test.error('No inactive interface on host') - host_iface = inactive_iface_list[0]['ifname'] - iface_attrs['source']['dev'] = host_iface + process.run(f'ip link add name {DOWN_IFACE_NAME} type bridge', + shell=True, ignore_status=False) + iface_attrs['source']['dev'] = DOWN_IFACE_NAME elif scenario == 'non_exist_bind_ip': bind_ip = '' @@ -121,12 +120,24 @@ def _get_test_ip(): if operation == 'start_vm': vmxml.add_device(iface_device) vmxml.sync(virsh_instance=virsh_ins) + LOG.debug( + f'VMXML: {virsh.dumpxml(vm_name, uri=virsh_uri).stdout_text}') result = virsh.start(vm_name, uri=virsh_uri, debug=True) if operation == 'hotplug': - virsh.start(vm_name, uri=virsh_uri) + vmxml.sync(virsh_instance=virsh_ins) + LOG.debug( + f'VMXML: {virsh.dumpxml(vm_name, uri=virsh_uri).stdout_text}') + virsh.start(vm_name, uri=virsh_uri, **VIRSH_ARGS) result = virsh.attach_device(vm_name, iface_device.xml, uri=virsh_uri, debug=True) - + if scenario == 'inactive_host_iface': + passt_ver_cmp = params.get("passt_version") + passt_ver = process.run("rpm -q passt", shell=True, + ignore_status=True).stdout_text.strip().split('-')[1] + # With newer passt version, vm can start successfully + # with inactive interface + if passt_ver >= passt_ver_cmp: + status_error, error_msg = False, '' libvirt.check_exit_status(result, status_error) if error_msg: libvirt.check_result(result, error_msg) @@ -139,6 +150,6 @@ def _get_test_ip(): bkxml.sync(virsh_instance=virsh_ins) if root: shutil.rmtree(log_dir) - else: - del virsh_ins utils_selinux.set_status(selinux_status) + process.run(f'ip link del {DOWN_IFACE_NAME}', + shell=True, ignore_status=True) diff --git a/libvirt/tests/src/virtual_network/passt/passt_reconnect.py b/libvirt/tests/src/virtual_network/passt/passt_reconnect.py index 0531d8806ba..28a0e86d809 100644 --- a/libvirt/tests/src/virtual_network/passt/passt_reconnect.py +++ b/libvirt/tests/src/virtual_network/passt/passt_reconnect.py @@ -1,6 +1,7 @@ import logging import os import shutil +import time import aexpect from avocado.utils import process @@ -12,8 +13,8 @@ from virttest import virsh from virttest.libvirt_xml import vm_xml from virttest.staging import service +from virttest.staging import utils_memory from virttest.utils_libvirt import libvirt_unprivileged -from virttest.utils_test import libvirt from provider.virtual_network import network_base from provider.virtual_network import passt @@ -49,7 +50,7 @@ def run(test, params, env): test_passwd, **unpr_vm_args) uri = f'qemu+ssh://{test_user}@localhost/session' - virsh_ins = virsh.VirshPersistent(uri=uri) + virsh_ins = virsh.Virsh(uri=uri) host_session = aexpect.ShellSession('su') remote.VMManager.set_ssh_auth(host_session, 'localhost', test_user, test_passwd) @@ -59,20 +60,21 @@ def run(test, params, env): iface_attrs = eval(params.get('iface_attrs')) params['socket_dir'] = socket_dir = eval(params.get('socket_dir')) params['proc_checks'] = proc_checks = eval(params.get('proc_checks', '{}')) - vm_iface = params.get('vm_iface', 'eno1') mtu = params.get('mtu') - qemu_cmd_check = params.get('qemu_cmd_check') outside_ip = params.get('outside_ip') host_iface = params.get('host_iface') - host_iface = host_iface if host_iface else utils_net.get_net_if( - state="UP")[0] + host_iface = host_iface if host_iface else utils_net.get_default_gateway( + iface_name=True, force_dhcp=True, json=True) log_file = f'/run/user/{user_id}/passt.log' iface_attrs['backend']['logFile'] = log_file iface_attrs['source']['dev'] = host_iface + vhostuser = 'yes' == params.get('vhostuser', 'no') + multiple_nexthops = 'yes' == params.get('multiple_nexthops', 'no') vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name, virsh_instance=virsh_ins) bkxml = vmxml.copy() + shp_orig_num = utils_memory.get_num_huge_pages() selinux_status = passt.ensure_selinux_enforcing() passt.check_socat_installed() @@ -82,11 +84,13 @@ def run(test, params, env): if root: passt.make_log_dir(user_id, log_dir) + if vhostuser: + iface_attrs['type_name'] = 'vhostuser' + # update vm xml with shared memory and vhostuser interface + vm_xml.VMXML.set_memoryBacking_tag(vm_name, access_mode="shared", hpgs=False, memfd=True, vmxml=vmxml) passt.vm_add_iface(vmxml, iface_attrs, virsh_ins) vm.start() - libvirt.check_qemu_cmd_line(qemu_cmd_check) - passt_proc = passt.get_proc_info('passt') LOG.debug(f'passt process info: {passt_proc}') @@ -94,7 +98,7 @@ def run(test, params, env): ignore_status=True).stdout_text.strip() process.run(f'kill -9 {pid_passt}', shell=True) - utils_misc.wait_for(lambda: passt.get_proc_info('passt'), 10, + utils_misc.wait_for(lambda: passt.get_proc_info('passt'), 30, ignore_errors=True) passt_proc_r = passt.get_proc_info('passt') LOG.debug(f'passt process info after reconnect: {passt_proc_r}') @@ -108,10 +112,13 @@ def run(test, params, env): if not os.path.exists(log_file): test.fail(f'Logfile of passt "{log_file}" not created') + # wait for the vm boot before first time to try serial login + time.sleep(5) session = vm.wait_for_serial_login(timeout=60) - passt.check_vm_ip(iface_attrs, session, host_iface) + vm_iface = utils_net.get_linux_ifname(session, mac) + passt.check_vm_ip(iface_attrs, session, host_iface, vm_iface) passt.check_vm_mtu(session, vm_iface, mtu) - passt.check_default_gw(session) + passt.check_default_gw(session, host_iface, multiple_nexthops) passt.check_nameserver(session) ips = { @@ -124,7 +131,8 @@ def run(test, params, env): LOG.debug(f'Service status of firewalld: {firewalld.status()}') passt.check_connection(vm, vm_iface, - ['TCP4', 'TCP6', 'UDP4', 'UDP6']) + ['TCP4', 'TCP6', 'UDP4', 'UDP6'], + host_iface) if 'portForwards' in iface_attrs: passt.check_portforward(vm, host_ip, params) @@ -137,6 +145,4 @@ def run(test, params, env): bkxml.sync(virsh_instance=virsh_ins) if root: shutil.rmtree(log_dir) - else: - del virsh_ins utils_selinux.set_status(selinux_status) diff --git a/libvirt/tests/src/virtual_network/passt/passt_transfer_file.py b/libvirt/tests/src/virtual_network/passt/passt_transfer_file.py index 9d4e82bc50c..f8ecb83ad7d 100644 --- a/libvirt/tests/src/virtual_network/passt/passt_transfer_file.py +++ b/libvirt/tests/src/virtual_network/passt/passt_transfer_file.py @@ -48,7 +48,7 @@ def transfer_host_to_vm(session, prot, ip_ver, params, test): cmd_transfer = eval(params.get('cmd_transfer')) process.run(cmd_transfer, shell=True) - if session.cmd_status(f'test -a {rec_file}') != 0: + if session.cmd_status(f'test -e {rec_file}') != 0: test.fail(f'VM did not recieve {rec_file}') vm_file_md5 = session.cmd_output(f'md5sum {rec_file}') vm_file_md5 = vm_file_md5.split()[0] @@ -79,9 +79,9 @@ def transfer_vm_to_host(session, prot, ip_ver, vm_iface, firewalld, rec_file = params.get('rec_file') cmd_create_file = params.get('cmd_create_file') force_dhcp = True if ip_ver == 'ipv4' else False - vm_default_gw = utils_net.get_default_gateway(session=session, - ip_ver=ip_ver, - force_dhcp=force_dhcp) + vm_default_gw = utils_net.get_default_gateway_json(session=session, + ip_ver=ip_ver, + force_dhcp=force_dhcp) addr = vm_default_gw if ip_ver == 'ipv4' \ else f'[{vm_default_gw}%{vm_iface}]' firewalld.stop() @@ -95,6 +95,8 @@ def transfer_vm_to_host(session, prot, ip_ver, vm_iface, firewalld, LOG.debug(f'MD5 of sent file: {md5}') host_session = aexpect.ShellSession('su') host_session.sendline(cmd_listen) + # Wait 2 seconds for the host listen cmd to be prepared + time.sleep(2) session.cmd(cmd_transfer) host_session.close() if not os.path.exists(rec_file): @@ -116,6 +118,11 @@ def run(test, params, env): Test file transfer between host and vm with passt backend interface """ libvirt_version.is_libvirt_feature_supported(params) + # Since passt can not handle the multipath route on the host, skip the ipv6 + # related test if host has multipath route. When there is multipath route, + # the utils_net.get_default_gateway() will return none. + ip_ver = params.get('ip_ver') + root = 'root_user' == params.get('user_type', '') if root: vm_name = params.get('main_vm') @@ -136,7 +143,7 @@ def run(test, params, env): test_passwd, **unpr_vm_args) uri = f'qemu+ssh://{test_user}@localhost/session' - virsh_ins = virsh.VirshPersistent(uri=uri) + virsh_ins = virsh.Virsh(uri=uri) host_session = aexpect.ShellSession('su') remote.VMManager.set_ssh_auth(host_session, 'localhost', test_user, test_passwd) @@ -145,15 +152,14 @@ def run(test, params, env): iface_attrs = eval(params.get('iface_attrs')) params['socket_dir'] = socket_dir = eval(params.get('socket_dir')) params['proc_checks'] = proc_checks = eval(params.get('proc_checks', '{}')) - vm_iface = params.get('vm_iface', 'eno1') host_iface = params.get('host_iface') - host_iface = host_iface if host_iface else utils_net.get_net_if( - state="UP")[0] + host_iface = host_iface if host_iface else utils_net.get_default_gateway( + iface_name=True, force_dhcp=True, json=True) log_file = f'/run/user/{user_id}/passt.log' iface_attrs['backend']['logFile'] = log_file iface_attrs['source']['dev'] = host_iface direction = params.get('direction') - ip_ver = params.get('ip_ver') + multiple_nexthops = 'yes' == params.get('multiple_nexthops', 'no') vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name, virsh_instance=virsh_ins) @@ -172,12 +178,14 @@ def run(test, params, env): LOG.debug(virsh_ins.dumpxml(vm_name).stdout_text) session = vm.wait_for_serial_login(timeout=60) - passt.check_default_gw(session) + passt.check_default_gw(session, host_iface, multiple_nexthops) prot = 'TCP' if ip_ver == 'ipv4' else 'TCP6' if direction == 'host_to_vm': transfer_host_to_vm(session, prot, ip_ver, params, test) if direction == 'vm_to_host': + mac = vm.get_virsh_mac_address() + vm_iface = utils_net.get_linux_ifname(session, mac) transfer_vm_to_host(session, prot, ip_ver, vm_iface, firewalld, params, test) finally: @@ -186,6 +194,4 @@ def run(test, params, env): bkxml.sync(virsh_instance=virsh_ins) if root: shutil.rmtree(log_dir) - else: - del virsh_ins utils_selinux.set_status(selinux_status) diff --git a/libvirt/tests/src/virtual_network/qos/check_actual_network_throughput.py b/libvirt/tests/src/virtual_network/qos/check_actual_network_throughput.py new file mode 100644 index 00000000000..bb446730b92 --- /dev/null +++ b/libvirt/tests/src/virtual_network/qos/check_actual_network_throughput.py @@ -0,0 +1,137 @@ +import logging + +from avocado.utils import process +from virttest import utils_misc +from virttest import utils_net +from virttest import utils_package +from virttest import virsh +from virttest.libvirt_xml import vm_xml +from virttest.libvirt_xml.network_xml import NetworkXML +from virttest.staging import service +from virttest.utils_libvirt import libvirt_network +from virttest.utils_libvirt import libvirt_vmxml +from virttest.utils_test import libvirt + +from provider.virtual_network import network_base + +VIRSH_ARGS = {'ignore_status': False, 'debug': True} + +LOG = logging.getLogger('avocado.' + __name__) + + +def run(test, params, env): + """ + Check the actual network throughput + per bandwidth settings in network/interface + + """ + vm_name = params.get('main_vm') + vm = env.get_vm(vm_name) + br_type = params.get('br_type', '') + rand_id = utils_misc.generate_random_string(3) + br_name = br_type + '_' + rand_id + net_name = 'net_' + rand_id + host_iface = params.get('host_iface') + host_iface = host_iface if host_iface else utils_net.get_net_if( + state='UP')[0] + iface_attrs = eval(params.get('iface_attrs', '{}')) + net_attrs = eval(params.get('net_attrs', '{}')) + inbound = eval(params.get('inbound')) + outbound = eval(params.get('outbound')) + throuput_bw = params.get('throuput_bw') + expect_msg = params.get('expect_msg') + + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + bkxml = vmxml.copy() + net_xml = NetworkXML.new_from_net_dumpxml('default') + bk_net_xml = net_xml.copy() + firewalld = service.Factory.create_service("firewalld") + + try: + if br_type == 'linux_br': + utils_net.create_linux_bridge_tmux(br_name, host_iface) + process.run(f'ip l show type bridge {br_name}', shell=True) + elif br_type == 'ovs_br': + utils_net.create_ovs_bridge(br_name) + + if 'name' in net_attrs: + libvirt_network.create_or_del_network(net_attrs) + else: + net_xml.setup_attrs(**net_attrs) + net_xml.sync() + LOG.debug(f'Network xml of default: {net_xml}') + + vmxml.del_device('interface', by_tag=True) + libvirt_vmxml.modify_vm_device(vmxml, 'interface', iface_attrs) + LOG.debug(f'VMXML of {vm_name}:\n{virsh.dumpxml(vm_name).stdout_text}') + + vm.start() + vm_sess = vm.wait_for_serial_login() + if expect_msg: + libvirt.check_logfile(expect_msg, + params.get("libvirtd_debug_file")) + + iface = network_base.get_iface_xml_inst(vm_name, 'on vm') + mac = iface.mac_address + tap_device = libvirt.get_ifname_host(vm_name, mac) + LOG.debug(f'tap device on host with mac {mac} is: {tap_device}.') + source_br = iface.source['bridge'] + LOG.debug(f'source bridge of interface is: {source_br}.') + + if 'bandwidth' in iface_attrs: + tc_args = [tap_device, '1:1', iface_attrs['bandwidth']['inbound']] + filter_bw = iface_attrs['bandwidth']['outbound'] + else: + tc_args = [source_br, '1:2', net_attrs['bandwidth_inbound']] + filter_bw = net_attrs['bandwidth_outbound'] + + if not utils_net.check_class_rules(*tc_args): + test.fail('Class rule check failed. Please check log.') + LOG.debug('Class rule check: PASS') + + if not utils_net.check_filter_rules(tc_args[0], filter_bw): + test.fail('Filter rule check failed. Please check log.') + LOG.debug('Filter rule check: PASS') + + if not utils_package.package_install('netperf', session=vm_sess): + test.error('Failed to install netperf on VM.') + + vm_sess.close() + vm_sess = vm.wait_for_serial_login() + + host_ip = utils_net.get_linux_iface_info( + iface=source_br)['addr_info'][0]['local'] + vm_ip = network_base.get_vm_ip(vm_sess, mac) + LOG.debug(f'Host ip address with br {source_br}: {host_ip}\n' + f'Vm ip address: {vm_ip}') + + firewalld.stop() + vm_sess.cmd('systemctl stop firewalld') + + network_base.check_throughput( + vm_sess.cmd, lambda x: process.run(x).stdout_text, + vm_ip, throuput_bw if throuput_bw else inbound["average"], 'inbound' + ) + + network_base.check_throughput( + lambda x: process.run(x).stdout_text, + vm_sess.cmd, host_ip, outbound["average"], 'outbound' + ) + vm_sess.close() + vm.destroy() + ovs_list_cmd = 'ovs-vsctl list qos' + ovs_list_output = process.run(ovs_list_cmd).stdout_text + if ovs_list_output: + test.fail(f'There should be no output of command {ovs_list_cmd}.' + f'But we got {ovs_list_output}') + + finally: + bkxml.sync() + bk_net_xml.sync() + if 'name' in net_attrs: + libvirt_network.create_or_del_network(net_attrs, is_del=True) + if br_type == 'linux_br': + utils_net.delete_linux_bridge_tmux(br_name, host_iface) + if br_type == 'ovs_br': + utils_net.delete_ovs_bridge(br_name) + firewalld.start() diff --git a/libvirt/tests/src/virtual_network/qos/check_actual_network_throughput_direct.py b/libvirt/tests/src/virtual_network/qos/check_actual_network_throughput_direct.py new file mode 100644 index 00000000000..fc4d9af6a6e --- /dev/null +++ b/libvirt/tests/src/virtual_network/qos/check_actual_network_throughput_direct.py @@ -0,0 +1,127 @@ +import logging + +from virttest import utils_misc +from virttest import utils_net +from virttest import utils_package +from virttest import virsh +from virttest.libvirt_xml import vm_xml +from virttest.staging import service +from virttest.utils_libvirt import libvirt_network +from virttest.utils_libvirt import libvirt_vmxml +from virttest.utils_test import libvirt + +from provider.virtual_network import network_base + +VIRSH_ARGS = {'ignore_status': False, 'debug': True} + +LOG = logging.getLogger('avocado.' + __name__) + + +def run(test, params, env): + """ + Check the actual network throughput for direct type interface + + """ + vm_name = params.get('main_vm') + vm2_name = params.get('vm2_name') + vm = env.get_vm(vm_name) + vm2 = env.get_vm(vm2_name) + rand_id = utils_misc.generate_random_string(3) + net_name = 'net_' + rand_id + host_iface = params.get('host_iface') + host_iface = host_iface if host_iface else utils_net.get_default_gateway( + iface_name=True, force_dhcp=True, json=True) + iface_attrs = eval(params.get('iface_attrs', '{}')) + iface_attrs_2 = eval(params.get('iface_attrs_2', '{}')) + net_attrs = eval(params.get('net_attrs', '{}')) + inbound = eval(params.get('inbound')) + outbound = eval(params.get('outbound')) + + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + bkxml = vmxml.copy() + vmxml_2 = vm_xml.VMXML.new_from_inactive_dumpxml(vm2_name) + bkxml_2 = vmxml_2.copy() + firewalld = service.Factory.create_service("firewalld") + + try: + + if 'name' in net_attrs: + libvirt_network.create_or_del_network(net_attrs) + virsh.net_dumpxml(net_attrs['name'], **VIRSH_ARGS) + + mac = network_base.get_iface_xml_inst( + vm_name, f'on VM:{vm_name}').mac_address + mac_2 = network_base.get_iface_xml_inst( + vm2_name, f'on VM:{vm2_name}').mac_address + iface_attrs.update({'mac_address': mac}) + iface_attrs_2.update({'mac_address': mac_2}) + + vmxml.del_device('interface', by_tag=True) + libvirt_vmxml.modify_vm_device(vmxml, 'interface', iface_attrs) + LOG.debug(f'VMXML of {vm_name}:\n{virsh.dumpxml(vm_name).stdout_text}') + + vmxml_2.del_device('interface', by_tag=True) + libvirt_vmxml.modify_vm_device(vmxml_2, 'interface', iface_attrs_2) + LOG.debug( + f'VMXML of {vm2_name}:\n{virsh.dumpxml(vm2_name).stdout_text}') + + vm.start() + vm_sess = vm.wait_for_serial_login() + + vm2.start() + vm_sess_2 = vm2.wait_for_serial_login() + + network_base.get_iface_xml_inst(vm_name, f'on VM:{vm_name}') + network_base.get_iface_xml_inst(vm2_name, f'on VM:{vm2_name}') + + tap_device = libvirt.get_ifname_host(vm_name, mac) + LOG.debug(f'tap device on host with mac {mac} is: {tap_device}.') + + tc_args = [tap_device, '1:1', iface_attrs['bandwidth']['outbound']] + filter_bw = iface_attrs['bandwidth']['inbound'] + + if not utils_net.check_class_rules(*tc_args): + test.fail('Class rule check failed. Please check log.') + LOG.debug('Class rule check: PASS') + + if not utils_net.check_filter_rules(tc_args[0], filter_bw): + test.fail('Filter rule check failed. Please check log.') + LOG.debug('Filter rule check: PASS') + + if not utils_package.package_install('netperf', session=vm_sess): + test.error(f'Failed to install netperf on VM:{vm_name}.') + if not utils_package.package_install('netperf', session=vm_sess_2): + test.error(f'Failed to install netperf on VM:{vm2_name}.') + + vm_sess.close() + vm_sess = vm.wait_for_serial_login() + vm_sess_2.close() + vm_sess_2 = vm2.wait_for_serial_login() + + vm_ip = network_base.get_vm_ip(vm_sess, mac) + vm_ip_2 = network_base.get_vm_ip(vm_sess_2, mac_2) + LOG.debug(f'Vm {vm_name} ip address: {vm_ip}\n' + f'Vm {vm2_name} ip address: {vm_ip_2}') + + firewalld.stop() + vm_sess.cmd('systemctl stop firewalld') + vm_sess_2.cmd('systemctl stop firewalld') + + network_base.check_throughput( + vm_sess.cmd, vm_sess_2.cmd, + vm_ip, outbound["average"], 'outbound' + ) + + network_base.check_throughput( + vm_sess_2.cmd, + vm_sess.cmd, vm_ip_2, inbound["average"], 'inbound' + ) + vm_sess.close() + vm_sess_2.close() + + finally: + bkxml.sync() + bkxml_2.sync() + if 'name' in net_attrs: + libvirt_network.create_or_del_network(net_attrs, is_del=True) + firewalld.start() diff --git a/libvirt/tests/src/virtual_network/qos/check_bandwidth_by_domiftune.py b/libvirt/tests/src/virtual_network/qos/check_bandwidth_by_domiftune.py new file mode 100644 index 00000000000..4b446091858 --- /dev/null +++ b/libvirt/tests/src/virtual_network/qos/check_bandwidth_by_domiftune.py @@ -0,0 +1,144 @@ +import logging + +from avocado.utils import process +from virttest import utils_misc +from virttest import utils_net +from virttest import virsh +from virttest.libvirt_xml import vm_xml +from virttest.libvirt_xml.network_xml import NetworkXML +from virttest.utils_libvirt import libvirt_misc +from virttest.utils_libvirt import libvirt_vmxml +from virttest.utils_test import libvirt + +from provider.virtual_network import network_base + +VIRSH_ARGS = {'ignore_status': False, 'debug': True} + +LOG = logging.getLogger('avocado.' + __name__) + + +def run(test, params, env): + """ + Check and tune the bandwidth of a interface via domiftune + + """ + vm_name = params.get('main_vm') + vm = env.get_vm(vm_name) + br_type = params.get('br_type', '') + rand_id = utils_misc.generate_random_string(3) + br_name = br_type + '_' + rand_id + host_iface = params.get('host_iface') + host_iface = host_iface if host_iface else utils_net.get_default_gateway( + iface_name=True, force_dhcp=True, json=True) + iface_attrs = eval(params.get('iface_attrs', '{}')) + net_attrs = eval(params.get('net_attrs', '{}')) + update_bw = eval(params.get('update_bw', '{}')) + + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + bkxml = vmxml.copy() + net_xml = NetworkXML.new_from_net_dumpxml('default') + bk_net_xml = net_xml.copy() + + try: + if br_type == 'linux_br': + utils_net.create_linux_bridge_tmux(br_name, host_iface) + process.run(f'ip l show type bridge {br_name}', shell=True) + + net_xml.setup_attrs(**net_attrs) + net_xml.sync() + LOG.debug(f'Network xml of default: {net_xml}') + + vmxml.del_device('interface', by_tag=True) + + libvirt_vmxml.modify_vm_device(vmxml, 'interface', iface_attrs) + LOG.debug(f'VMXML of {vm_name}:\n{virsh.dumpxml(vm_name).stdout_text}') + + vm.start() + session = vm.wait_for_serial_login() + + iface = network_base.get_iface_xml_inst(vm_name, 'on vm') + mac = iface.mac_address + tap_device = libvirt.get_ifname_host(vm_name, mac) + LOG.debug(f'tap device on host with mac {mac} is: {tap_device}.') + + domiftune_out = virsh.domiftune( + vm_name, tap_device, debug=True).stdout_text + domiftune_ori = libvirt_misc.convert_to_dict( + domiftune_out, '(\S+)\s*:\s*(\d+)') + if not all([v == '0' for v in domiftune_ori.values()]): + test.fail('All value of domiftune output should be "0"') + + domiftune_args = {} + bw_in = update_bw['inbound'] + inbound = f'{bw_in["average"]},{bw_in["peak"]},{bw_in["burst"]}' + if 'floor' in bw_in: + inbound = inbound + f',{bw_in["floor"]}' + domiftune_args.update({'inbound': inbound}) + bw_out = update_bw['outbound'] + outbound = f'{bw_out["average"]},{bw_out["peak"]},{bw_out["burst"]}' + domiftune_args.update({'outbound': outbound}) + virsh.domiftune(vm_name, tap_device, **domiftune_args, **VIRSH_ARGS) + + iface_update = network_base.get_iface_xml_inst(vm_name, 'after update') + LOG.debug(iface_update.bandwidth) + for key in ['inbound', 'outbound']: + if iface_update.fetch_attrs()['bandwidth'][key] != update_bw[key]: + test.fail( + f'Bandwidth of interface xml not correctly updated:\n' + f'{iface_update.fetch_attrs()["bandwidth"][key]} != ' + f'{update_bw[key]}') + LOG.debug(f'{key} bandwidth check in xml: PASS') + + # For direct interface type, "tc class show dev" will show the outbound + # instead of the inbound setting, and "tc filter show dev" will show + # the inbound instead of the outbound setting + iface_type = iface_attrs['type_name'] + class_key = 'outbound' if iface_type == 'direct' else 'inbound' + filter_key = 'inbound' if iface_type == 'direct' else 'outbound' + + if iface_type == 'network': + source_br = iface.source['bridge'] + bw_floor = update_bw['inbound']['floor'] + update_bw['inbound'].pop('floor') + if not utils_net.check_class_rules( + source_br, '1:3', {'floor': bw_floor}): + test.fail('Class rule check (floor) after domiftune failed') + if not utils_net.check_class_rules( + tap_device, '1:1', update_bw[class_key]): + test.fail( + 'Class rule check after domiftune failed. Please check log.') + LOG.debug('Class rule check after domiftune: PASS') + if not utils_net.check_filter_rules( + tap_device, update_bw[filter_key]): + test.fail( + 'Filter rule check after domiftune failed. Please check log.') + LOG.debug('Filter rule check after domiftune: PASS') + + virsh.domiftune(vm_name, tap_device, inbound='0', + outbound='0', **VIRSH_ARGS) + iface_del_bw = network_base.get_iface_xml_inst( + vm_name, 'after delete bandwidth') + + if 'bandwidth' in iface_del_bw.fetch_attrs(): + test.fail('Bandwidth of interface xml not deleted') + out_c = utils_net.check_class_rules( + tap_device, "1:1", update_bw["inbound"], expect_none=True + ) + out_f = utils_net.check_filter_rules( + tap_device, update_bw["outbound"], expect_none=True + ) + if not all([out_c, out_f]): + test.fail( + "There should not be output of tc class/filter " + "command when bandwidth settings is deleted." + ) + LOG.debug('Class and Filter rule check with "tc" ' + 'after delete bandwidth with domiftune: PASS') + + finally: + if 'session' in locals(): + session.close() + bkxml.sync() + bk_net_xml.sync() + if br_type == 'linux_br': + utils_net.delete_linux_bridge_tmux(br_name, host_iface) diff --git a/libvirt/tests/src/virtual_network/qos/check_qos_floor.py b/libvirt/tests/src/virtual_network/qos/check_qos_floor.py new file mode 100644 index 00000000000..4ff3d1d6110 --- /dev/null +++ b/libvirt/tests/src/virtual_network/qos/check_qos_floor.py @@ -0,0 +1,78 @@ +import logging + +from virttest import utils_misc +from virttest import utils_net +from virttest import virsh +from virttest.libvirt_xml import vm_xml +from virttest.utils_libvirt import libvirt_network +from virttest.utils_libvirt import libvirt_vmxml +from virttest.utils_test import libvirt + +from provider.virtual_network import network_base + +VIRSH_ARGS = {'ignore_status': False, 'debug': True} + +LOG = logging.getLogger('avocado.' + __name__) + + +def run(test, params, env): + """ + Check the floor setting in bandwidth setting + + """ + vm_name = params.get('main_vm') + vm = env.get_vm(vm_name) + status_error = 'yes' == params.get('status_error', 'no') + err_msg = params.get('err_msg') + + rand_id = utils_misc.generate_random_string(3) + net_name = params.get('net_type') + '_' + rand_id + net_attrs = eval(params.get('net_attrs', '{}')) + iface_attrs = eval(params.get('iface_attrs', '{}')) + + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + bkxml = vmxml.copy() + + try: + if net_attrs: + libvirt_network.create_or_del_network(net_attrs) + LOG.debug(f'Network xml:\n' + f'{virsh.net_dumpxml(net_attrs["name"]).stdout_text}') + + vmxml.del_device('interface', by_tag=True) + iface = libvirt_vmxml.create_vm_device_by_type( + 'interface', iface_attrs) + libvirt.add_vm_device(vmxml, iface) + LOG.debug(f'VMXMLof {vm_name}:\n{virsh.dumpxml(vm_name).stdout_text}') + + start_result = virsh.start(vm_name, debug=True) + libvirt.check_exit_status(start_result, status_error) + if err_msg: + libvirt.check_result(start_result, err_msg) + if status_error: + return + + iface = network_base.get_iface_xml_inst(vm_name, '1st on vm') + mac = iface.mac_address + source_br = iface.source['bridge'] + + tap_device = libvirt.get_ifname_host(vm_name, mac) + LOG.debug(f'tap device on host with mac {mac} is: {tap_device}.') + + bw_floor = iface_attrs['bandwidth']['inbound']['floor'] + iface_attrs['bandwidth']['inbound'].pop('floor') + + if not utils_net.check_class_rules( + source_br, '1:3', {'floor': bw_floor}): + test.fail('Class rule check (floor) failed') + if not utils_net.check_class_rules( + tap_device, '1:1', iface_attrs['bandwidth']['inbound']): + test.fail('Class rule check failed') + if not utils_net.check_filter_rules( + tap_device, iface_attrs['bandwidth']['outbound']): + test.fail('Filter rule check failed') + + finally: + bkxml.sync() + if net_attrs: + libvirt_network.create_or_del_network(net_attrs, is_del=True) diff --git a/libvirt/tests/src/virtual_network/qos/test_bandwidth_boundry.py b/libvirt/tests/src/virtual_network/qos/test_bandwidth_boundry.py new file mode 100644 index 00000000000..ac0fc815d1b --- /dev/null +++ b/libvirt/tests/src/virtual_network/qos/test_bandwidth_boundry.py @@ -0,0 +1,60 @@ +import logging + +from virttest import virsh +from virttest.libvirt_xml import vm_xml +from virttest.utils_libvirt import libvirt_misc +from virttest.utils_test import libvirt + +from provider.virtual_network import network_base + +VIRSH_ARGS = {'ignore_status': False, 'debug': True} + +LOG = logging.getLogger('avocado.' + __name__) + + +def run(test, params, env): + """ + Test bandwidth boundary of an interface via domiftune + + """ + vm_name = params.get('main_vm') + vm = env.get_vm(vm_name) + bw_type = params.get('bw_type', '') + bw_args = params.get('bw_args', '') + status_error = 'yes' == params.get("status_error", 'no') + err_msg = params.get('err_msg') + + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + bkxml = vmxml.copy() + + try: + iface = network_base.get_iface_xml_inst(vm_name, 'on vm') + mac = iface.mac_address + domiftune_args = {bw_type: bw_args} + virsh_result = virsh.domiftune( + vm_name, mac, **domiftune_args, debug=True) + libvirt.check_exit_status(virsh_result, status_error) + if status_error: + libvirt.check_result(virsh_result, err_msg) + return + + out = virsh.domiftune(vm_name, mac, **VIRSH_ARGS).stdout_text + + bw_out = libvirt_misc.convert_to_dict( + out, '(\S+)\s*:\s*(\d+)') + bw_values = bw_out[f'{bw_type}.average'], \ + bw_out[f'{bw_type}.peak'], bw_out[f'{bw_type}.burst'] + if ','.join(bw_values) != bw_args: + test.fail(f'Bandwidth from domiftune is {",".join(bw_values)}, ' + f'but it should be {bw_args}') + + iface = network_base.get_iface_xml_inst(vm_name, 'after domiftune') + iface_attrs = iface.fetch_attrs() + bw_attrs = iface_attrs['bandwidth'][bw_type] + bw_xml_values = ','.join([bw_attrs['average'], bw_attrs['peak'], + bw_attrs['burst']]) + if bw_xml_values != bw_args: + test.fail(f'Bandwidth from interface xml is {bw_xml_values}, ' + f'but it should be {bw_args}') + finally: + bkxml.sync() diff --git a/libvirt/tests/src/virtual_network/resolve_vm_hostname_by_resolvectl.py b/libvirt/tests/src/virtual_network/resolve_vm_hostname_by_resolvectl.py new file mode 100644 index 00000000000..c46e12703c3 --- /dev/null +++ b/libvirt/tests/src/virtual_network/resolve_vm_hostname_by_resolvectl.py @@ -0,0 +1,112 @@ +import logging +import re + +from avocado.utils import process +from virttest import libvirt_version +from virttest import utils_misc +from virttest import virsh +from virttest.libvirt_xml import vm_xml +from virttest.libvirt_xml.network_xml import NetworkXML +from virttest.staging import service +from virttest.utils_test import libvirt + +from provider.virtual_network import network_base + +VIRSH_ARGS = {'ignore_status': False, 'debug': True} + +LOG = logging.getLogger('avocado.' + __name__) + + +def run(test, params, env): + """ + Test resolve guest hostname from host by resolvectl + + """ + libvirt_version.is_libvirt_feature_supported(params) + vm_name = params.get('main_vm') + vm = env.get_vm(vm_name) + vm_b = env.get_vm(params.get('vms').split()[-1]) + status_error = 'yes' == params.get('status_error', 'no') + err_msg = params.get('err_msg', '') + rand_id = utils_misc.generate_random_string(3) + register = 'yes' == params.get('register', 'no') + net_attrs = eval(params.get('net_attrs', '{}')) + ips = eval(params.get('ips', '{}')) + + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + bkxml = vmxml.copy() + net_xml = NetworkXML.new_from_net_dumpxml('default') + bk_net_xml = net_xml.copy() + sys_resolved = service.Factory.create_service("systemd-resolved") + conf_path = '/etc/resolv.conf' + conf_path_bk = f'{conf_path}.bk_{rand_id}' + + try: + sys_resolved.start() + iface_a = network_base.get_iface_xml_inst(vm_name, 'on vm') + mac_a = iface_a.mac_address + + ip_attrs = eval(params.get('ip_attrs', '{}')) + net_ips = net_xml.ips + net_ips[0].update(**ip_attrs) + net_xml.ips = net_ips + + net_xml.setup_attrs(**net_attrs) + if status_error: + net_xml.xmltreefile.write() + LOG.debug(net_xml) + def_result = virsh.net_define(net_xml.xml, debug=True) + libvirt.check_exit_status(def_result, status_error) + libvirt.check_result(def_result, err_msg) + return + + net_xml.sync() + LOG.debug(virsh.net_dumpxml('default').stdout_text) + + LOG.debug(f'VMXML of {vm_name}:\n{virsh.dumpxml(vm_name).stdout_text}') + + br = net_xml.bridge['name'] + domain_output = process.run(f'resolvectl domain {br}').stdout_text + dns_output = process.run(f'resolvectl dns {br}').stdout_text + if register: + dom_pattern = re.compile(rf'Link \d+ \({br}\): ~example.com\s*$') + dns_pattern = re.compile( + rf'Link \d+ \({br}\): {net_ips[0].address}\s*$') + else: + dom_pattern = re.compile(r'Link \d+ \(.*\):\s*$') + dns_pattern = dom_pattern + + if not dom_pattern.search(domain_output): + test.fail(f'Unexpected output of resolvectl:\n{domain_output}') + if not dns_pattern.search(dns_output): + test.fail(f'Unexpected output of resolvectl:\n{dns_output}') + + # Backup the /etc/resolv.conf file + process.run(f'cp {conf_path} {conf_path_bk}') + # Make /etc/resolve.conf as symbolic file + process.run( + f'ln -f -r -s /run/systemd/resolve/stub-resolv.conf {conf_path}') + process.run(f'file {conf_path}') + name_serv_output = process.run(f'cat {conf_path}').stdout_text + if not re.search(r'nameserver\s+127.0.0.53', name_serv_output): + test.fail('Nameserver output check failed') + + vm.start() + vm_b.start() + # Wait for vm to get dhcp lease + vm.wait_for_serial_login().close() + + session_b = vm_b.wait_for_serial_login() + session_b.cmd('hostnamectl set-hostname vmtest') + session_b.cmd('systemctl restart NetworkManager') + session_b.close() + + virsh.net_dhcp_leases('default', **VIRSH_ARGS) + network_base.ping_check(params, ips) + + finally: + vm.destroy() + vm_b.destroy() + bkxml.sync() + bk_net_xml.sync() + process.run(f'mv {conf_path_bk} {conf_path}', ignore_status=True) diff --git a/libvirt/tests/src/virtual_network/update_device/unsupported_live_update.py b/libvirt/tests/src/virtual_network/update_device/unsupported_live_update.py new file mode 100644 index 00000000000..1211a3fb75f --- /dev/null +++ b/libvirt/tests/src/virtual_network/update_device/unsupported_live_update.py @@ -0,0 +1,76 @@ +import logging + +from virttest import utils_net +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.virtual_network import network_base + +VIRSH_ARGS = {'ignore_status': False, 'debug': True} + +LOG = logging.getLogger('avocado.' + __name__) + + +def run(test, params, env): + """ + Test update-device command to update coalesce of interface + """ + vm_name = params.get('main_vm') + vm = env.get_vm(vm_name) + status_error = 'yes' == params.get('status_error', 'no') + err_msg = params.get('err_msg') + set_boot = 'yes' == params.get('set_boot', 'no') + + mac = utils_net.generate_mac_address_simple() + base_iface_attrs = eval(params.get('base_iface_attrs', '{}')) + extra_attrs = eval(params.get('extra_attrs', '{}')) + iface_attrs = {**base_iface_attrs, **extra_attrs} + + update_attrs = eval(params.get('update_attrs', '{}')) + tmp_attrs = eval(params.get('tmp_attrs', '{}')) + del_attr = params.get('del_attr') + + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + bkxml = vmxml.copy() + + try: + if set_boot: + osxml = vmxml.os + osxml.del_boots() + vmxml.os = osxml + libvirt_vmxml.modify_vm_device(vmxml, 'disk', {'boot': '1'}) + + libvirt_vmxml.modify_vm_device(vmxml, 'interface', iface_attrs) + LOG.debug(f'VMXML of {vm_name}:\n{virsh.dumpxml(vm_name).stdout_text}') + + vm.start() + vm.wait_for_serial_login().close() + + iface = network_base.get_iface_xml_inst(vm_name, 'on VM') + iface_original = iface.copy() + if del_attr: + if del_attr == 'boot': + iface.xmltreefile.remove_by_xpath('/boot') + else: + eval(f'iface.del_{del_attr}')() + else: + if tmp_attrs: + iface.setup_attrs(**tmp_attrs) + iface.setup_attrs(**update_attrs) + LOG.debug(f'Interface xml to update with:\n{iface}') + + up_result = virsh.update_device(vm_name, iface.xml, debug=True) + libvirt.check_exit_status(up_result, status_error) + if err_msg: + libvirt.check_result(up_result, err_msg) + + iface_update = network_base.get_iface_xml_inst(vm_name, + 'after update-device') + if iface_update != iface_original: + test.fail(f'Interface xml changed after unsuccessful update.\n' + f'Should be:\n{iface_original}\n' + f'Actually is:\n{iface_update}') + finally: + bkxml.sync() diff --git a/libvirt/tests/src/virtual_network/update_device/update_device_coalesce.py b/libvirt/tests/src/virtual_network/update_device/update_device_coalesce.py new file mode 100644 index 00000000000..e89f35e7bbe --- /dev/null +++ b/libvirt/tests/src/virtual_network/update_device/update_device_coalesce.py @@ -0,0 +1,114 @@ +import logging + +from avocado.utils import process +from virttest import utils_misc +from virttest import utils_net +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.virtual_network import network_base + +VIRSH_ARGS = {'ignore_status': False, 'debug': True} + +LOG = logging.getLogger('avocado.' + __name__) + + +def check_coalesce_rx_frames(tap_device, rx_frames, test): + """ + Check whether coalesce rx-frames meets expectation + + :param tap_device: tap device to be checked + :param rx_frames: expected rx-frames + :param test: test instance + """ + coal_params = network_base.get_ethtool_coalesce(tap_device) + LOG.debug(f'coalesce parameters from ethtool: {coal_params}') + coal_rx_frames = str(coal_params.get('rx-frames')).strip() + if coal_rx_frames != rx_frames: + if rx_frames == '0' and coal_rx_frames == 'n/a': + LOG.debug("The expected value is 0, but got n/a, which is " + "also acceptable.") + else: + test.fail(f'rx-frames of {tap_device} should be {rx_frames}, ' + f'not {coal_rx_frames}') + + +def run(test, params, env): + """ + Test update-device command to update coalesce of interface + """ + vm_name = params.get('main_vm') + vm = env.get_vm(vm_name) + rand_id = utils_misc.generate_random_string(3) + br_type = params.get('br_type', '') + br_name = br_type + '_' + rand_id + mac = utils_net.generate_mac_address_simple() + iface_attrs = eval(params.get('iface_attrs', '{}')) + host_iface = params.get('host_iface') + host_iface = host_iface if host_iface else utils_net.get_default_gateway( + iface_name=True, force_dhcp=True, json=True) + rx_frames = params.get('rx_frames', '0') + updated_rx_frames = params.get('updated_rx_frames', '0') + updated_coalesce = eval(params.get('updated_coalesce', '{}')) + + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + bkxml = vmxml.copy() + + try: + LOG.info('Create bridge for test.') + if br_type == 'linux_br': + utils_net.create_linux_bridge_tmux(br_name, host_iface) + process.run(f'ip l show type bridge {br_name}', shell=True) + elif br_type == 'ovs_br': + utils_net.create_ovs_bridge(br_name) + + LOG.info('Setup interface on vm.') + mac = vm_xml.VMXML.get_first_mac_by_name(vm_name) + vmxml.del_device('interface', by_tag=True) + libvirt_vmxml.modify_vm_device( + vmxml, 'interface', {**iface_attrs, **{'mac_address': mac}}) + LOG.debug(f'VMXML of {vm_name}:\n{virsh.dumpxml(vm_name).stdout_text}') + + vm.start() + session = vm.wait_for_serial_login() + + LOG.info('Check the rx-frames value for the tap device on the host.') + iflist = libvirt.get_interface_details(vm_name) + tap_device = iflist[0]['interface'] + check_coalesce_rx_frames(tap_device, rx_frames, test) + + LOG.info('Prepare interface xml to be updated with.') + iface = network_base.get_iface_xml_inst(vm_name, 'on VM') + if not updated_coalesce: + iface.del_coalesce() + else: + iface.setup_attrs(**updated_coalesce) + + virsh.update_device(vm_name, iface.xml, **VIRSH_ARGS) + + LOG.info('Check the live xml is updated.') + iface_update = network_base.get_iface_xml_inst( + vm_name, 'after update-device') + expect_coalesce = updated_coalesce.get('coalesce') + network_base.check_iface_attrs(iface_update, 'coalesce', + expect_coalesce) + + LOG.info('Check the rx-frames value for the tap device on the host.') + check_coalesce_rx_frames(tap_device, updated_rx_frames, test) + + LOG.info('Login vm to check whether the network works well via ping.') + ips = {'outside_ip': params.get('outside_ip')} + network_base.ping_check(params, ips, session, force_ipv4=True) + + finally: + if 'session' in locals(): + session.close() + bkxml.sync() + if br_type == 'linux_br': + LOG.debug(f'Delete linux bridge: {br_name}') + utils_net.delete_linux_bridge_tmux(br_name, host_iface) + if br_type == 'ovs_br': + LOG.debug(f'Delete ovs bridge: {br_name}') + utils_net.delete_ovs_bridge(br_name) diff --git a/libvirt/tests/src/virtual_network/update_device/update_driver_non_virtio.py b/libvirt/tests/src/virtual_network/update_device/update_driver_non_virtio.py new file mode 100644 index 00000000000..805cff2dd16 --- /dev/null +++ b/libvirt/tests/src/virtual_network/update_device/update_driver_non_virtio.py @@ -0,0 +1,88 @@ +import re + +from virttest import libvirt_version +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.interface import interface_base +from provider.virtual_network import network_base + +VIRSH_ARGS = {"ignore_status": False, "debug": True} + + +def run(test, params, env): + """ + Test update-device for interface link state, live update the link state from up to down + There are invalid driver attribute defined in the original xml or the update xml. + The test is to ensure the update can succeed and get expected result. + """ + libvirt_version.is_libvirt_feature_supported(params) + + outside_ip = params.get("outside_ip") + exist_attrs = eval(params.get('exist_attrs', '{}')) + iface_attrs_ = eval(params.get("iface_attrs", "{}")) + iface_attrs = {**iface_attrs_, **exist_attrs} + update_setting = eval(params.get("update_setting", "{}")) + + vm_name = params.get("main_vm") + vm = env.get_vm(vm_name) + + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + bkxml = vmxml.copy() + + def check_link_state(exp_link_state, exp_domiflik_state): + """ + check the link state on vm and in xml should be consistent and expected + """ + # get the link state in the live xml + link_info = virsh.domif_getlink(vm_name, iface_mac, **VIRSH_ARGS).stdout_text + test.log.debug("Get the interface info by domif-getlink: %s", link_info) + # get "Link detected" value from ethtool outputs on vm + output = session.cmd_output("ethtool %s" % vm_iface) + test.log.debug(output) + match = re.search(r"Link detected:\s*(\w+)", output) + if match: + link_status = match.group(1) + else: + test.cancel("Can not get expected Link status on vm!") + # make sure the result is expected + if exp_link_state == 'yes': + ips = {'outside_ip': outside_ip} + network_base.ping_check(params, ips, session, force_ipv4=True) + test.log.debug("link_info is %s, link-status is %s" % (link_info, link_status)) + if link_info.split()[-1] != exp_domiflik_state: + test.fail("The link states in vm xml is not expected") + if link_status != exp_link_state: + test.fail("The link status on vm is not expected") + + try: + vmxml.del_device('interface', by_tag=True) + libvirt_vmxml.modify_vm_device( + vmxml, 'interface', {**iface_attrs}) + test.log.debug(f'VMXML of {vm_name}:\n{virsh.dumpxml(vm_name).stdout_text}') + vm.start() + session = vm.wait_for_serial_login() + vm_iface = interface_base.get_vm_iface(session) + + test.log.info("TEST_STEP1: Check the original link state in vm should be up") + ifaces = libvirt.get_interface_details(vm_name) + test.log.debug(f'ifaces of vm: {ifaces}') + iface_info = ifaces[0] + iface_mac = iface_info['mac'] + check_link_state("yes", "up") + + test.log.info("TEST_STEP2: Update the link state to be down") + iface = network_base.get_iface_xml_inst(vm_name, f'on VM:{vm_name}') + iface.setup_attrs(**update_setting) + test.log.debug(f"iface xml to be updated: {iface}") + ret = virsh.update_device(vm_name, iface.xml, **VIRSH_ARGS) + libvirt.check_result(ret) + + test.log.info("TEST_STEP3: Check the interface status in xml and on vm") + check_link_state("no", "down") + session.close() + finally: + bkxml.sync() diff --git a/libvirt/tests/src/virtual_network/update_device/update_iface_link_state.py b/libvirt/tests/src/virtual_network/update_device/update_iface_link_state.py new file mode 100644 index 00000000000..478cb1742f4 --- /dev/null +++ b/libvirt/tests/src/virtual_network/update_device/update_iface_link_state.py @@ -0,0 +1,112 @@ +from virttest import libvirt_version +from virttest import virsh +from virttest import utils_misc +from virttest import utils_net + +from virttest.libvirt_xml import vm_xml +from virttest.utils_libvirt import libvirt_vmxml +from virttest.utils_test import libvirt + +from provider.interface import interface_base +from provider.virtual_network import network_base + +VIRSH_ARGS = {"ignore_status": False, "debug": True} + + +def run(test, params, env): + """ + Test update-device for interface link state + """ + libvirt_version.is_libvirt_feature_supported(params) + + outside_ip = params.get("outside_ip") + host_iface = params.get("host_iface") + host_iface = host_iface if host_iface else utils_net.get_default_gateway( + iface_name=True, force_dhcp=True, json=True) + rand_id = utils_misc.generate_random_string(3) + bridge_name = "br_" + rand_id + tap_name = "tap_" + rand_id + interface_type = params.get("interface_type") + iface_attrs = eval(params.get("iface_attrs", "{}")) + initial_link_state = params.get("initial_link_state", "") + if initial_link_state: + iface_attrs.update({"link_state": initial_link_state}) + test_states = [("yes", "up"), ("no", "down")] + if initial_link_state == "down": + test_states.reverse() + updated_link_state = params.get("updated_link_state") + + vm_name = params.get("main_vm") + vm = env.get_vm(vm_name) + + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + bkxml = vmxml.copy() + + try: + if interface_type == "ethernet": + utils_net.create_linux_bridge_tmux(bridge_name, host_iface) + network_base.create_tap(tap_name, bridge_name, "root") + + mac = vm_xml.VMXML.get_first_mac_by_name(vm_name) + vmxml.del_device('interface', by_tag=True) + libvirt_vmxml.modify_vm_device( + vmxml, 'interface', {**iface_attrs, **{'mac_address': mac}}) + test.log.debug(f'VMXML of {vm_name}:\n{virsh.dumpxml(vm_name).stdout_text}') + vm.start() + session = vm.wait_for_serial_login() + vm_iface = interface_base.get_vm_iface(session) + + test.log.info("TEST_STEP: Check the link state in vm.") + iflist = libvirt.get_interface_details(vm_name) + test.log.debug(f'iflist of vm: {iflist}') + iface_info = iflist[0] + iface_mac = iface_info['mac'] + for exp_link_state, exp_domiflik_state in test_states: + if exp_link_state == test_states[-1][0]: + iface = vm_xml.VMXML.new_from_dumpxml( + vm.name).devices.by_device_tag("interface")[0] + if updated_link_state: + iface.setup_attrs(**{"link_state": updated_link_state}) + else: + iface.del_link_state() + test.log.debug(f"iface xml to be updated: {iface}") + test.log.info("TEST_STEP: Update interface device.") + virsh.update_device(vm_name, iface.xml, **VIRSH_ARGS) + + link_info = virsh.domif_getlink( + vm_name, iface_mac, **VIRSH_ARGS).stdout_text + if exp_domiflik_state not in link_info: + test.fail("Failed to get expected interface link state '%s'!" + % exp_domiflik_state) + + if exp_link_state == "yes": + if exp_link_state == test_states[-1][0]: + utils_net.restart_guest_network(session) + ips = {'outside_ip': outside_ip} + network_base.ping_check(params, ips, session, force_ipv4=True) + + output = session.cmd_output("ethtool %s" % vm_iface) + test.log.debug(output) + if "Link detected: %s" % exp_link_state not in output: + test.fail("Failed to get expected link state '%s' in ethtool " + "cmd!" % exp_link_state) + vm_iface = vm_xml.VMXML.new_from_dumpxml(vm.name)\ + .devices.by_device_tag("interface")[0] + + test.log.info("TEST_STEP: Check the live xml for the current link state.") + iface_attrs = vm_iface.fetch_attrs() + test.log.debug(f"iface attrs: {iface_attrs}") + if iface_attrs.get("link_state"): + if iface_attrs.get("link_state") != exp_domiflik_state: + test.fail("Failed to get expected link state '%s' in live xml." + % exp_domiflik_state) + else: + if updated_link_state: + test.fail("There should be no link state in live xml.") + session.close() + + finally: + bkxml.sync() + if interface_type == "ethernet": + network_base.delete_tap(tap_name) + utils_net.delete_linux_bridge_tmux(bridge_name, host_iface) diff --git a/libvirt/tests/src/virtual_network/update_device/update_iface_portgroup.py b/libvirt/tests/src/virtual_network/update_device/update_iface_portgroup.py new file mode 100644 index 00000000000..fc05f9089bf --- /dev/null +++ b/libvirt/tests/src/virtual_network/update_device/update_iface_portgroup.py @@ -0,0 +1,117 @@ +import logging + +from avocado.utils import process +from virttest import utils_misc +from virttest import utils_net +from virttest import virsh +from virttest.libvirt_xml import vm_xml +from virttest.libvirt_xml.network_xml import NetworkXML +from virttest.utils_libvirt import libvirt_network +from virttest.utils_libvirt import libvirt_vmxml +from virttest.utils_test import libvirt + +from provider.virtual_network import network_base + +VIRSH_ARGS = {'ignore_status': False, 'debug': True} + +LOG = logging.getLogger('avocado.' + __name__) + + +def run(test, params, env): + """ + Update interface portgroup for nat and bridge network(Qos) + + """ + vm_name = params.get('main_vm') + vm = env.get_vm(vm_name) + + rand_id = utils_misc.generate_random_string(3) + net_type = params.get('net_type', '') + br_name = net_type + '_' + rand_id + net_name = params.get('net_type') + '_' + rand_id + net_attrs = eval(params.get('net_attrs', '{}')) + pg_a = eval(params.get('pg_a', '{}')) + pg_b = eval(params.get('pg_b', '{}')) + update_attrs = eval(params.get('update_attrs', '{}')) + + net_name = 'default' if 'name' not in net_attrs else net_name + iface_attrs = eval(params.get('iface_attrs', '{}')) + + host_iface = params.get('host_iface') + host_iface = host_iface if host_iface else utils_net.get_net_if( + state="UP")[0] + + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + bkxml = vmxml.copy() + net_xml = NetworkXML.new_from_net_dumpxml('default') + bk_net_xml = net_xml.copy() + + try: + LOG.info('Create bridge for test.') + if net_type == 'linux_br': + utils_net.create_linux_bridge_tmux(br_name, host_iface) + process.run(f'ip l show type bridge {br_name}', shell=True) + elif net_type == 'ovs_br': + utils_net.create_ovs_bridge(br_name) + + if 'name' in net_attrs: + libvirt_network.create_or_del_network(net_attrs) + virsh.net_dumpxml(net_attrs['name'], **VIRSH_ARGS) + else: + net_xml.setup_attrs(**net_attrs) + net_xml.sync() + LOG.debug(f'Network xml of default: {net_xml}') + + vmxml.del_device('interface', by_tag=True) + iface = libvirt_vmxml.create_vm_device_by_type( + 'interface', iface_attrs) + libvirt.add_vm_device(vmxml, iface) + LOG.debug(f'VMXMLof {vm_name}:\n{virsh.dumpxml(vm_name).stdout_text}') + + iface = network_base.get_iface_xml_inst(vm_name, '1st on vm') + mac = iface.mac_address + + vm.start() + network_base.get_iface_xml_inst(vm_name, 'on vm after vm start') + tap_device = libvirt.get_ifname_host(vm_name, mac) + LOG.debug(f'tap device on host with mac {mac} is: {tap_device}.') + + if not utils_net.check_class_rules( + tap_device, '1:1', pg_a['bandwidth_inbound']): + test.fail('class rule check failed') + if not utils_net.check_filter_rules( + tap_device, pg_a['bandwidth_outbound']): + test.fail('filter rule check failed') + + # Update device + update_attrs = {'source': {**iface_attrs['source'], **update_attrs}} + LOG.debug(f'Update iface with attrs: {update_attrs}') + iface.setup_attrs(**update_attrs) + iface.xmltreefile.write() + + LOG.debug(f'Update iface with xml: {iface}') + virsh.update_device(vm_name, iface.xml, **VIRSH_ARGS) + + # Check updated iface xml + iface_update = network_base.get_iface_xml_inst(vm_name, 'after update') + if iface_update.source.get( + 'portgroup') != update_attrs['source']['portgroup']: + test.fail('Update iface xml portgroup failed') + + # Check rules + if not utils_net.check_class_rules( + tap_device, '1:1', pg_b['bandwidth_inbound']): + test.fail('class rule check failed-') + if not utils_net.check_filter_rules( + tap_device, pg_b['bandwidth_outbound']): + test.fail('filter rule check failed-') + + finally: + bkxml.sync() + bk_net_xml.sync() + if 'name' in net_attrs: + libvirt_network.create_or_del_network(net_attrs, is_del=True) + if net_type == 'linux_br': + utils_net.delete_linux_bridge_tmux(br_name, host_iface) + if net_type == 'ovs_br': + utils_net.delete_ovs_bridge(br_name) diff --git a/libvirt/tests/src/virtual_network/update_device/update_iface_qos.py b/libvirt/tests/src/virtual_network/update_device/update_iface_qos.py new file mode 100644 index 00000000000..dbe9c2a3109 --- /dev/null +++ b/libvirt/tests/src/virtual_network/update_device/update_iface_qos.py @@ -0,0 +1,173 @@ +import logging + +from avocado.utils import process +from virttest import utils_misc +from virttest import utils_net +from virttest import virsh +from virttest.libvirt_xml import vm_xml +from virttest.utils_libvirt import libvirt_misc +from virttest.utils_libvirt import libvirt_vmxml +from virttest.utils_test import libvirt + +from provider.virtual_network import network_base + +VIRSH_ARGS = {'ignore_status': False, 'debug': True} + +LOG = logging.getLogger('avocado.' + __name__) + + +def domiftune_to_dict(output): + """ + Convert domiftune output to dict + + :param output: domiftune output + :return: converted dict + """ + tmp_dict = libvirt_misc.convert_to_dict(output, '(\S+)\s*:\s*(\d+)') + final = {} + final['inbound'] = {k.split('.')[-1]: v for k, v in tmp_dict.items() + if k.startswith('inbound')} + final['outbound'] = {k.split('.')[-1]: v for k, v in tmp_dict.items() + if k.startswith('outbound')} + return final + + +def run(test, params, env): + """ + Test live update interface bandwidth setting by update-device or domiftune + """ + vm_name = params.get('main_vm') + vm = env.get_vm(vm_name) + br_type = params.get('br_type', '') + rand_id = utils_misc.generate_random_string(3) + br_name = br_type + '_' + rand_id + host_iface = params.get('host_iface') + host_iface = host_iface if host_iface else utils_net.get_default_gateway( + iface_name=True, force_dhcp=True, json=True) + iface_attrs = eval(params.get('iface_attrs', '{}')) + extra_attrs = eval(params.get('extra_attrs', '{}')) + net_attrs = eval(params.get('net_attrs', '{}')) + + scope = eval(params.get('scope', '[]')) + method = params.get('method', '') + operation = params.get('operation', '') + + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + bkxml = vmxml.copy() + + try: + if br_type == 'linux_br': + utils_net.create_linux_bridge_tmux(br_name, host_iface) + process.run(f'ip l show type bridge {br_name}', shell=True) + elif br_type == 'ovs_br': + utils_net.create_ovs_bridge(br_name) + + vmxml.del_device('interface', by_tag=True) + + # Update iface_attrs with certain bandwidth settings + extra_attrs = {'bandwidth': {k: extra_attrs['bandwidth'][k] + for k in scope} + } if extra_attrs else extra_attrs + iface_attrs.update(extra_attrs) + libvirt_vmxml.modify_vm_device(vmxml, 'interface', iface_attrs) + LOG.debug(f'VMXML of {vm_name}:\n{virsh.dumpxml(vm_name).stdout_text}') + + # For direct interface type, "tc class show dev" will show the outbound + # instead of the inbound setting, and "tc filter show dev" will show + # the inbound instead of the outbound setting + iface_type = iface_attrs['type_name'] + class_key = 'outbound' if iface_type == 'direct' else 'inbound' + filter_key = 'inbound' if iface_type == 'direct' else 'outbound' + + vm.start() + session = vm.wait_for_serial_login() + + iface = network_base.get_iface_xml_inst(vm_name, 'on vm') + mac = iface.mac_address + tap_device = libvirt.get_ifname_host(vm_name, mac) + LOG.debug(f'tap device on host with mac {mac} is: {tap_device}.') + + if 'bandwidth' in iface_attrs: + if class_key in scope and not utils_net.check_class_rules( + tap_device, '1:1', iface_attrs['bandwidth'][class_key]): + test.fail( + 'Class rule check before update failed. Please check log.') + if filter_key in scope and not utils_net.check_filter_rules( + tap_device, iface_attrs['bandwidth'][filter_key]): + test.fail( + 'Filter rule check before update failed. Please check log.') + + # Remove out-of-scope settings + update_attrs = eval(params.get('update_attrs', '{}')) + update_attrs['bandwidth'] = {k: update_attrs['bandwidth'][k] + for k in scope} + LOG.debug(f'Update iface with attrs: {update_attrs}') + if method == 'update-device': + if operation == 'delete': + iface.del_bandwidth() + else: + iface.setup_attrs(**update_attrs) + LOG.debug(f'Update iface with xml:\n{iface}') + virsh.update_device(vm_name, iface.xml, **VIRSH_ARGS) + + elif method == 'domiftune': + domiftune_args = {} + if 'inbound' in scope: + bw_in = update_attrs['bandwidth']['inbound'] + inbound = f'{bw_in["average"]},{bw_in["peak"]},{bw_in["burst"]}' + domiftune_args.update({'inbound': inbound}) + if 'outbound' in scope: + bw_out = update_attrs['bandwidth']['outbound'] + outbound = f'{bw_out["average"]},{bw_out["peak"]},{bw_out["burst"]}' + domiftune_args.update({'outbound': outbound}) + virsh.domiftune(vm_name, tap_device, ** + domiftune_args, **VIRSH_ARGS) + else: + test.error(f'Unsupported method: {method}.') + + iface_update = network_base.get_iface_xml_inst(vm_name, 'after update') + if operation == 'delete': + if 'bandwidth' in iface_update.fetch_attrs(): + test.fail('Bandwidth of interface xml not deleted') + else: + LOG.debug(iface_update.bandwidth) + for key in scope: + if iface_update.fetch_attrs()['bandwidth'][key] != update_attrs['bandwidth'][key]: + test.fail( + 'Bandwidth of interface xml not correctly updated') + + if operation == 'delete': + out_c = process.run(f'tc class show dev {tap_device}' + ).stdout_text.strip() + out_f = process.run(f'tc filter show dev {tap_device} parent ffff:' + ).stdout_text.strip() + if any([out_c, out_f]): + test.fail('There should not be output of tc class/filter ' + 'command when bandwidth settings is deleted.') + else: + if class_key in scope and not utils_net.check_class_rules( + tap_device, '1:1', update_attrs['bandwidth'][class_key]): + test.fail( + 'Class rule check after update failed. Please check log.') + if filter_key in scope and not utils_net.check_filter_rules( + tap_device, update_attrs['bandwidth'][filter_key]): + test.fail( + 'Filter rule check after update failed. Please check log.') + + domiftune_output = virsh.domiftune(vm_name, tap_device, + **VIRSH_ARGS).stdout_text + domiftune_dict = domiftune_to_dict(domiftune_output) + LOG.debug(f'domiftune to dict: {domiftune_dict}') + for key in scope: + if not update_attrs['bandwidth'][key].items() <= \ + domiftune_dict[key].items(): + test.fail(f'domiftune {key} check fail.') + + finally: + if 'session' in locals(): + session.close() + bkxml.sync() + if br_type == 'linux_br': + utils_net.delete_linux_bridge_tmux(br_name, host_iface) + if br_type == 'ovs_br': + utils_net.delete_ovs_bridge(br_name) diff --git a/libvirt/tests/src/virtual_network/update_device/update_iface_qos_invalid.py b/libvirt/tests/src/virtual_network/update_device/update_iface_qos_invalid.py new file mode 100644 index 00000000000..6ef2be49db7 --- /dev/null +++ b/libvirt/tests/src/virtual_network/update_device/update_iface_qos_invalid.py @@ -0,0 +1,49 @@ +import logging + +from virttest import libvirt_version +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.virtual_network import network_base + +VIRSH_ARGS = {'ignore_status': False, 'debug': True} + +LOG = logging.getLogger('avocado.' + __name__) + + +def run(test, params, env): + """ + Test live update interface bandwidth setting by update-device or domiftune + """ + libvirt_version.is_libvirt_feature_supported(params) + vm_name = params.get('main_vm') + vm = env.get_vm(vm_name) + status_error = 'yes' == params.get('status_error', 'no') + err_msg = params.get('err_msg') + iface_attrs = eval(params.get('iface_attrs', '{}')) + update_attrs = eval(params.get('update_attrs', '{}')) + + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + bkxml = vmxml.copy() + + try: + vmxml.del_device('interface', by_tag=True) + libvirt_vmxml.modify_vm_device(vmxml, 'interface', iface_attrs) + LOG.debug(f'VMXML of {vm_name}:\n{virsh.dumpxml(vm_name).stdout_text}') + + vm.start() + vm.wait_for_serial_login().close() + + iface = network_base.get_iface_xml_inst(vm_name, 'on vm') + LOG.debug(f'Update iface with attrs: {update_attrs}') + iface.setup_attrs(**update_attrs) + + LOG.debug(f'Update iface with xml:\n{iface}') + up_result = virsh.update_device(vm_name, iface.xml, debug=True) + libvirt.check_exit_status(up_result, status_error) + if err_msg: + libvirt.check_result(up_result, err_msg) + finally: + bkxml.sync() diff --git a/libvirt/tests/src/virtual_network/update_device/update_iface_source.py b/libvirt/tests/src/virtual_network/update_device/update_iface_source.py new file mode 100644 index 00000000000..240a0311a9a --- /dev/null +++ b/libvirt/tests/src/virtual_network/update_device/update_iface_source.py @@ -0,0 +1,93 @@ +import logging + +from virttest import utils_misc +from virttest import utils_net +from virttest import virsh +from virttest.libvirt_xml import network_xml +from virttest.libvirt_xml import vm_xml +from virttest.utils_libvirt import libvirt_network +from virttest.utils_libvirt import libvirt_vmxml +from virttest.utils_test import libvirt + +from provider.virtual_network import network_base + +VIRSH_ARGS = {'ignore_status': False, 'debug': True} + +LOG = logging.getLogger('avocado.' + __name__) + + +def run(test, params, env): + """ + Test live update interface source setting + """ + vm_name = params.get('main_vm') + vm = env.get_vm(vm_name) + rand_id = utils_misc.generate_random_string(3) + net_name = 'net_' + rand_id + host_iface = params.get('host_iface') + host_iface = host_iface if host_iface else utils_net.get_default_gateway( + iface_name=True, force_dhcp=True, json=True) + iface_attrs = eval(params.get('iface_attrs', '{}')) + net_attrs = eval(params.get('net_attrs', '{}')) + status_error = 'yes' == params.get('status_error', 'no') + err_msg = params.get('err_msg') + ips = {'outside_ip': params.get('outside_ip')} + + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + bkxml = vmxml.copy() + + try: + mac = vm_xml.VMXML.get_first_mac_by_name(vm_name) + vmxml.del_device('interface', by_tag=True) + libvirt_vmxml.modify_vm_device( + vmxml, 'interface', {**iface_attrs, **{'mac_address': mac}}) + LOG.debug(f'VMXML of {vm_name}:\n{virsh.dumpxml(vm_name).stdout_text}') + + if net_attrs: + libvirt_network.create_or_del_network(net_attrs) + net_xml = network_xml.NetworkXML.new_from_net_dumpxml( + net_attrs["name"]) + net_xml.debug_xml() + if net_xml.forward['mode'] == 'nat': + net_br = net_xml.bridge['name'] + + vm.start() + session = vm.wait_for_serial_login() + network_base.ping_check(params, ips, session, force_ipv4=True) + + iface = network_base.get_iface_xml_inst(vm_name, 'on vm') + update_attrs = eval(params.get('update_attrs', '{}')) + LOG.debug(f'Update iface with attrs: {update_attrs}') + iface.setup_attrs(**update_attrs) + LOG.debug(f'Update iface with xml:\n{iface}') + + up_result = virsh.update_device(vm_name, iface.xml, debug=True) + libvirt.check_exit_status(up_result, status_error) + if err_msg: + libvirt.check_result(up_result, err_msg) + return + + iface_update = network_base.get_iface_xml_inst(vm_name, 'after update') + LOG.debug(f'iface source after update: {iface_update.source}') + if not iface_update.source.items() >= update_attrs['source'].items(): + test.fail('Source of interface xml not correctly updated') + + mac = iface.mac_address + vm_iface = utils_net.get_linux_ifname(session, mac) + LOG.debug(f'Interface inside vm: {vm_iface}') + + LOG.info('Run command to refresh network.') + utils_net.restart_guest_network(session, mac) + + vm_iface_info = utils_net.get_linux_iface_info( + vm_iface, session=session) + LOG.debug(f'iface info inside vm:\n{vm_iface_info}') + + network_base.ping_check(params, ips, session, force_ipv4=True) + + finally: + bkxml.sync() + if 'session' in locals(): + session.close() + if net_attrs: + libvirt_network.create_or_del_network(net_attrs, is_del=True) diff --git a/libvirt/tests/src/virtual_network/update_device/update_iface_trustGuestRxFilters.py b/libvirt/tests/src/virtual_network/update_device/update_iface_trustGuestRxFilters.py new file mode 100644 index 00000000000..8f3b085bc91 --- /dev/null +++ b/libvirt/tests/src/virtual_network/update_device/update_iface_trustGuestRxFilters.py @@ -0,0 +1,93 @@ +import logging + +from avocado.utils import process +from virttest import libvirt_version +from virttest import utils_net +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.virtual_network import network_base + +VIRSH_ARGS = {'ignore_status': False, 'debug': True} + +LOG = logging.getLogger('avocado.' + __name__) + + +def run(test, params, env): + """ + Test live update trustGuestRxFilters for direct type interface + """ + libvirt_version.is_libvirt_feature_supported(params) + vm_name = params.get('main_vm') + vm = env.get_vm(vm_name) + host_iface = params.get('host_iface') + host_iface = host_iface if host_iface else utils_net.get_default_gateway( + iface_name=True, force_dhcp=True, json=True) + iface_attrs = eval(params.get('iface_attrs', '{}')) + ips = {'outside_ip': params.get('outside_ip')} + + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + bkxml = vmxml.copy() + + try: + mac = vm_xml.VMXML.get_first_mac_by_name(vm_name) + vmxml.del_device('interface', by_tag=True) + libvirt_vmxml.modify_vm_device( + vmxml, 'interface', {**iface_attrs, **{'mac_address': mac}}) + LOG.debug(f'VMXML of {vm_name}:\n{virsh.dumpxml(vm_name).stdout_text}') + + vm.start() + + iface = network_base.get_iface_xml_inst(vm_name, 'on vm') + target_dev = iface.target['dev'] + update_attrs = eval(params.get('update_attrs', '{}')) + LOG.debug(f'Update iface with attrs: {update_attrs}') + iface.setup_attrs(**update_attrs) + LOG.debug(f'Update iface with xml:\n{iface}') + + virsh.update_device(vm_name, iface.xml, **VIRSH_ARGS) + + iface_update = network_base.get_iface_xml_inst(vm_name, 'after update') + LOG.debug(f'iface trustGuestRxFilters after update: ' + f'{iface_update.trustGuestRxFilters}') + if iface_update.trustGuestRxFilters != update_attrs[ + 'trustGuestRxFilters']: + test.fail(f'Interface trustGuestRxFilters not successfully updated ' + f'to {update_attrs["trustGuestRxFilters"]}') + + mac_host = utils_net.get_linux_iface_info(iface=target_dev)['address'] + + session = vm.wait_for_serial_login() + mac = iface.mac_address + vm_iface = utils_net.get_linux_ifname(session, mac) + LOG.debug(f'Interface inside vm: {vm_iface}') + + vm_iface_info = utils_net.get_linux_iface_info( + vm_iface, session=session) + LOG.debug(f'iface info inside vm:\n{vm_iface_info}') + new_mac = utils_net.generate_mac_address_simple() + session.cmd(f'ip l set dev {vm_iface} address {new_mac}') + + network_base.ping_check(params, ips, session, force_ipv4=True) + session.close() + mac_host_after = utils_net.get_linux_iface_info( + iface=target_dev)['address'] + + expect_mac = mac_host if update_attrs[ + 'trustGuestRxFilters'] == 'no' else new_mac + if mac_host_after != expect_mac: + test.fail(eval(params.get('err_msg'))) + + virsh.shutdown(vm_name, **VIRSH_ARGS) + if not vm.wait_for_shutdown(): + test.error('VM failed to shutdown in 60s') + + output = process.run(f' ip addr show {target_dev}', + shell=True, ignore_status=True) + libvirt.check_exit_status(output, expect_error=True) + libvirt.check_result(output, 'does not exist') + + finally: + bkxml.sync() diff --git a/libvirt/tests/src/virtual_network/update_device/update_iface_type_live.py b/libvirt/tests/src/virtual_network/update_device/update_iface_type_live.py index bc3ce6bf7f1..06c82a4668f 100644 --- a/libvirt/tests/src/virtual_network/update_device/update_iface_type_live.py +++ b/libvirt/tests/src/virtual_network/update_device/update_iface_type_live.py @@ -8,6 +8,8 @@ from virttest.utils_libvirt import libvirt_network from virttest.utils_libvirt import libvirt_vmxml +from provider.virtual_network import network_base + VIRSH_ARGS = {'ignore_status': False, 'debug': True} LOG = logging.getLogger('avocado.' + __name__) @@ -21,14 +23,17 @@ def run(test, params, env): vm = env.get_vm(vm_name) rand_id = utils_misc.generate_random_string(3) create_linux_br = 'yes' == params.get('create_linux_br', 'no') - linux_br = 'linux_br_' + rand_id + create_ovs_br = 'yes' == params.get('create_ovs_br', 'no') + check_link = 'yes' == params.get('check_link', 'yes') + linux_br = 'br_' + rand_id + operation = params.get('operation', 'attach_device') net_name = 'net_' + rand_id mac = utils_net.generate_mac_address_simple() iface_attrs = eval(params.get('iface_attrs', '{}')) iface_type = params.get('iface_type') host_iface = params.get('host_iface') - host_iface = host_iface if host_iface else utils_net.get_net_if( - state='UP')[0] + host_iface = host_iface if host_iface else utils_net.get_default_gateway( + iface_name=True, force_dhcp=True, json=True) net_attrs = eval(params.get('net_attrs', '{}')) vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) @@ -42,35 +47,52 @@ def run(test, params, env): if create_linux_br: LOG.debug(f'Create linux bridge: {linux_br}') utils_net.create_linux_bridge_tmux(linux_br, host_iface) + if create_ovs_br: + LOG.debug(f'Create ovs bridge: {linux_br}') + utils_net.create_ovs_bridge(linux_br) libvirt_network.create_or_del_network(net_attrs) LOG.debug(f'Network xml:\n' f'{virsh.net_dumpxml(net_attrs["name"]).stdout_text}') - vm.start() - session = vm.wait_for_serial_login() - iface = libvirt_vmxml.create_vm_device_by_type( 'interface', iface_attrs) - LOG.debug(f'Interface to attach:\n{iface}') + LOG.debug(f'Interface to attach/add:\n{iface.xmltreefile.__str__()}') - virsh.attach_device(vm_name, iface.xml, **VIRSH_ARGS) + if operation == 'default': + vmxml.add_device(iface) + vmxml.sync() + + vm.start() + session = vm.wait_for_serial_login() + + if operation == 'attach_device': + virsh.attach_device(vm_name, iface.xml, + flagstr='--persistent', **VIRSH_ARGS) + elif operation == 'attach_interface': + virsh.attach_interface( + vm_name, f'--source {net_name} --model virtio --type network --persistent', **VIRSH_ARGS) vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) - iface_at = vmxml.get_devices('interface')[0] - LOG.debug(f'Interface xml after attached to vm:\n{iface_at}') - LOG.debug(f'Interface type after attached to vm:\n' - f'{iface_at.type_name}') + iface_at = network_base.get_iface_xml_inst(vm_name, 'after attach') + LOG.debug(f'Interface type after attached to vm: {iface_at.type_name}') if iface_at.type_name != iface_type: test.fail(f'Interface type should change to {iface_type}') LOG.debug('Update interface link state') link_state = 'down' iface.setup_attrs(**{'link_state': link_state}) - LOG.debug(iface) + if params.get('with_iface_xml') == 'yes': + xml_opt = params.get('xml_opt', '') + iface = network_base.get_iface_xml_inst( + vm_name, f'on vm ({xml_opt})', options=f'{xml_opt}') + LOG.debug(f'Update iface with xml:\n{iface}') virsh.update_device(vm_name, iface.xml, **VIRSH_ARGS) vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) - iface_update = vmxml.get_devices('interface')[0] + iface_update = network_base.get_iface_xml_inst(vm_name, 'after update') + if not check_link: + return + LOG.debug(f'Link state of interface after update: ' f'{iface_update.link_state}') if iface_update.link_state != link_state: @@ -95,3 +117,5 @@ def run(test, params, env): if create_linux_br: LOG.debug(f'Delete linux bridge: {linux_br}') utils_net.delete_linux_bridge_tmux(linux_br, host_iface) + if create_ovs_br: + utils_net.delete_ovs_bridge(linux_br) diff --git a/libvirt/tests/src/virtual_network/update_device/update_iface_with_identifier.py b/libvirt/tests/src/virtual_network/update_device/update_iface_with_identifier.py new file mode 100644 index 00000000000..24e305d55ba --- /dev/null +++ b/libvirt/tests/src/virtual_network/update_device/update_iface_with_identifier.py @@ -0,0 +1,115 @@ +import logging + +from virttest import utils_misc +from virttest import utils_net +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.virtual_network import network_base + +VIRSH_ARGS = {'ignore_status': False, 'debug': True} + +LOG = logging.getLogger('avocado.' + __name__) + + +def check_cmd_result(cmd_result, status_error, err_msg=None): + """ + Check command result including exit status and error message + + :param cmd_result: command result instance + :param status_error: expect error of command + :param err_msg: error message of command, defaults to None + """ + libvirt.check_exit_status(cmd_result, status_error) + if err_msg: + libvirt.check_result(cmd_result, err_msg) + + +def run(test, params, env): + """ + Verify updating interface can identify by each of the mac/alias/PCI address, + and also by them together. + """ + vm_name = params.get('main_vm') + vm = env.get_vm(vm_name) + status_error = 'yes' == params.get('status_error', 'no') + err_msg = params.get('err_msg') + alias_a = 'ua-' + utils_misc.generate_random_string(6) + alias_b = 'ua-' + utils_misc.generate_random_string(6) + rand_mac = utils_net.generate_mac_address_simple() + rand_alias = 'randa-' + utils_misc.generate_random_string(6) + iface_a_attrs = eval(params.get('iface_a_attrs', '{}')) + iface_b_attrs = eval(params.get('iface_b_attrs', '{}')) + update_attrs = eval(params.get('update_attrs', '{}')) + update_pci = 'yes' == params.get('update_pci', 'no') + del_tags = eval(params.get('del_tags', '[]')) + operation = params.get('operation') + + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + bkxml = vmxml.copy() + + try: + vmxml.del_device('interface', by_tag=True) + for attrs in (iface_a_attrs, iface_b_attrs): + iface_x = libvirt_vmxml.create_vm_device_by_type( + 'interface', attrs) + libvirt.add_vm_device(vmxml, iface_x) + LOG.debug(f'VMXMLof {vm_name}:\n{virsh.dumpxml(vm_name).stdout_text}') + + vm.start() + + # Get target iface + iface = network_base.get_iface_xml_inst(vm_name, '1st on vm') + mac = iface.mac_address + + LOG.debug(f'Update iface with attrs: {update_attrs}') + iface.setup_attrs(**update_attrs) + + if update_pci: + LOG.debug('Update iface xml pci address') + pci_addr_attrs = iface.address['attrs'] + pci_addr_attrs['slot'] = str(hex(int(pci_addr_attrs['slot'], + 16) + 3)) + iface.setup_attrs(address={'attrs': pci_addr_attrs}) + LOG.debug(f'Update iface pci address to: {iface.address}') + + for tag in del_tags: + LOG.debug(f'Remove <{tag}> from iface xml.') + iface.xmltreefile.remove_by_xpath(tag) + iface.xmltreefile.write() + LOG.debug(f'Update iface with xml:\n{iface}') + + if operation == 'update': + up_result = virsh.update_device(vm_name, iface.xml, debug=True) + check_cmd_result(up_result, status_error, err_msg) + if status_error: + return + iface_update = network_base.get_iface_xml_inst(vm_name, + 'after update') + if iface_update.link_state == update_attrs['link_state']: + LOG.info('link_state of interface after update check PASS') + else: + test.fail(f'Interface link_state after update should be ' + f'{update_attrs["link_state"]}') + + elif operation == 'hotunplug': + vm.wait_for_serial_login().close() + dt_result = virsh.detach_device(vm_name, iface.xml, + wait_for_event=True, + event_timeout=120, + debug=True) + check_cmd_result(dt_result, status_error, err_msg) + if status_error: + return + iflist = virsh.domiflist(vm_name, debug=True).stdout_text + if mac not in iflist: + LOG.info('Interface successfully detached:checked by domiflist') + else: + test.fail(f'Interface with mac {mac} not detached') + else: + test.error(f'Unknown operation: {operation}') + + finally: + bkxml.sync() diff --git a/libvirt/tests/src/virtual_network/update_device/update_iface_with_options.py b/libvirt/tests/src/virtual_network/update_device/update_iface_with_options.py new file mode 100644 index 00000000000..0dfea8f2ada --- /dev/null +++ b/libvirt/tests/src/virtual_network/update_device/update_iface_with_options.py @@ -0,0 +1,90 @@ +import logging + +from virttest import utils_net +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.virtual_network import network_base + +VIRSH_ARGS = {'ignore_status': False, 'debug': True} + +LOG = logging.getLogger('avocado.' + __name__) + + +def run(test, params, env): + """ + Test Update an interface by update-device + with --live/--config/--current/--persistent on active/inactive domain + """ + vm_name = params.get('main_vm') + vm = env.get_vm(vm_name) + status_error = 'yes' == params.get('status_error', 'no') + err_msg = params.get('err_msg') + iface_attrs = eval(params.get('iface_attrs', '{}')) + update_attrs = eval(params.get('update_attrs', '{}')) + update_expect = eval(params.get('update_expect', '{}')) + options = params.get('options') + vm_active = eval(params.get('vm_active')) + + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + bkxml = vmxml.copy() + + try: + libvirt_vmxml.modify_vm_device(vmxml, 'interface', iface_attrs) + LOG.debug(f'VMXML of {vm_name}:\n{virsh.dumpxml(vm_name).stdout_text}') + + if vm_active: + vm.start() + vm.wait_for_serial_login().close() + + iface = network_base.get_iface_xml_inst(vm_name, 'on vm') + mac = iface.mac_address + LOG.debug(f'Mac address of iface: {mac}') + LOG.debug(f'Update iface with attrs: {update_attrs}') + iface.setup_attrs(**update_attrs) + + # Generate options for update-device command + options = options.split('_') if 'none' not in options else [] + options = ' '.join([f'--{opt}' for opt in options]) + LOG.debug(f'Update iface with xml:\n{iface}') + up_result = virsh.update_device(vm_name, iface.xml, flagstr=options, + debug=True) + libvirt.check_exit_status(up_result, status_error) + if err_msg: + libvirt.check_result(up_result, err_msg) + + if vm_active: + iface_active = network_base.get_iface_xml_inst( + vm_name, 'on active vm after update') + LOG.debug(f'link state on active xml should be ' + f'{"down" if update_expect["active"] else "up"}') + if (iface_active.link_state == 'down') is not update_expect['active']: + test.fail('update result of iface xml on active vm ' + 'not met expectation.') + + iface_inactive = network_base.get_iface_xml_inst( + vm_name, 'on inactive vm after update', options='--inactive') + LOG.debug(f'link state on inactive xml should be ' + f'{"down" if update_expect["inactive"] else "up"}') + if (iface_inactive.link_state == 'down') is not update_expect['inactive']: + test.fail('update result of iface xml on inactive vm ' + 'not met expectation.') + + # Check update result on vm with ethtool + if vm_active: + session = vm.wait_for_serial_login() + vm_iface_info = utils_net.get_linux_iface_info( + mac=mac, session=session) + LOG.debug(f'iface info on vm: {vm_iface_info}') + ethtool_output = session.cmd_output( + f'ethtool {vm_iface_info["ifname"]}') + LOG.debug(f'ethtool output:\n{ethtool_output}') + LOG.debug(f'"Link detected" should be ' + f'{"no" if update_expect["active"] else "yes"}') + if ('Link detected: no' in ethtool_output) is not \ + update_expect['active']: + test.fail('ethtool check inside vm failed.') + finally: + bkxml.sync() diff --git a/libvirt/tests/src/virtual_network/update_device/update_iface_with_unchangable.py b/libvirt/tests/src/virtual_network/update_device/update_iface_with_unchangable.py new file mode 100644 index 00000000000..6aa0bec5099 --- /dev/null +++ b/libvirt/tests/src/virtual_network/update_device/update_iface_with_unchangable.py @@ -0,0 +1,73 @@ +import logging + +from virttest import utils_net +from virttest import virsh +from virttest.libvirt_xml import vm_xml +from virttest.utils_libvirt import libvirt_vmxml + +from provider.virtual_network import network_base + +VIRSH_ARGS = {'ignore_status': False, 'debug': True} + +LOG = logging.getLogger('avocado.' + __name__) + + +def run(test, params, env): + """ + To test that libvirt can compare current xml and the xml to be updated correctly. + keep all the attributes which do not support live update in the xml unchanged, + also with that can be live updated changed, try to update it. It should succeed. + """ + vm_name = params.get('main_vm') + vm = env.get_vm(vm_name) + + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + bkxml = vmxml.copy() + + try: + # Setup boot config of vmxml + osxml = vmxml.os + osxml.del_boots() + vmxml.os = osxml + libvirt_vmxml.modify_vm_device(vmxml, 'disk', {'boot': '1'}) + + vmxml.del_device('interface', by_tag=True) + + iface_attrs = {k.replace('iface_attrs_', ''): v + if v[0].isalnum() else eval(v) + for k, v in params.items() + if k.startswith('iface_attrs_')} + + libvirt_vmxml.modify_vm_device(vmxml, 'interface', iface_attrs) + LOG.debug(f'VMXML of {vm_name}:\n{virsh.dumpxml(vm_name).stdout_text}') + + vm.start() + + iface = network_base.get_iface_xml_inst(vm_name, 'on vm') + mac = iface.mac_address + update_attrs = eval(params.get('update_attrs', '{}')) + LOG.debug(f'Update iface with attrs: {update_attrs}') + iface.setup_attrs(**update_attrs) + LOG.debug(f'Update iface with xml:\n{iface}') + + virsh.update_device(vm_name, iface.xml, **VIRSH_ARGS) + + iface_update = network_base.get_iface_xml_inst(vm_name, 'after update') + LOG.debug(f'link state after update: {iface_update.link_state}') + if iface_update.link_state != 'down': + test.fail('Link state of interface should be down after update') + + # Check update result on vm with ethtool + session = vm.wait_for_serial_login() + vm_iface_info = utils_net.get_linux_iface_info( + mac=mac, session=session) + LOG.debug(f'iface info on vm: {vm_iface_info}') + ethtool_output = session.cmd_output( + f'ethtool {vm_iface_info["ifname"]}') + LOG.debug(f'ethtool output:\n{ethtool_output}') + LOG.debug(f'"Link detected" should be no') + if 'Link detected: no' not in ethtool_output: + test.fail('ethtool check inside vm failed.') + + finally: + bkxml.sync() diff --git a/libvirt/tests/src/virtual_network/update_device/update_port_isolated.py b/libvirt/tests/src/virtual_network/update_device/update_port_isolated.py new file mode 100644 index 00000000000..a0f387d490b --- /dev/null +++ b/libvirt/tests/src/virtual_network/update_device/update_port_isolated.py @@ -0,0 +1,148 @@ +import logging + +from virttest import libvirt_version +from virttest import utils_misc +from virttest import utils_net +from virttest import virsh +from virttest.libvirt_xml import vm_xml +from virttest.utils_libvirt import libvirt_network +from virttest.utils_libvirt import libvirt_vmxml + +from provider.virtual_network import network_base + +VIRSH_ARGS = {'ignore_status': False, 'debug': True} + +LOG = logging.getLogger('avocado.' + __name__) + + +def run(test, params, env): + """ + Test update of port isolated on interface with update-device command + """ + def setup_vms_ifaces(vmxml, cli_vmxml): + """ + Setup interface of vm xmls + + :param vmxml: vmxml instance + :param cli_vmxml: client vm xml instance + """ + for vmxml_i in [vmxml, cli_vmxml]: + vmxml_i.del_device('interface', by_tag=True) + + mac, cli_mac = list(map(vm_xml.VMXML.get_first_mac_by_name, vms)) + iface_attrs.update({'mac_address': mac}) + cli_iface_attrs.update({'mac_address': cli_mac}) + + for vmxml_i, attrs in [(vmxml, iface_attrs), + (cli_vmxml, cli_iface_attrs)]: + libvirt_vmxml.modify_vm_device(vmxml_i, 'interface', attrs) + + for vm_x in vms: + LOG.debug(f'VMXML of {vm_x}:\n{virsh.dumpxml(vm_x).stdout_text}') + + for vm_i in [vm, cli_vm]: + vm_i.start() + + def get_ips(session, cli_session): + """ + Get test ips + + :param session: vm session + :param cli_session: client vm session + :return: test ips + """ + mac, cli_mac = list(map(vm_xml.VMXML.get_first_mac_by_name, vms)) + ips = network_base.get_test_ips(session, mac, cli_session, cli_mac, + ip_ver='ipv4') + ips['outside_ip'] = outside_ip + + return ips + + def test_ping(msg, ips=None): + """ + Test ping function + + :param msg: message to log + :param ips: test ips, defaults to None + :return: test ips if not given + """ + session, cli_session = (vm_inst.wait_for_serial_login() + for vm_inst in [vm, cli_vm]) + if ips is None: + ips = get_ips(session, cli_session) + + LOG.info(f'Ping check {msg}') + network_base.ping_check(params, ips, session, force_ipv4=True) + + session.close() + cli_session.close() + + if ips: + return ips + + def test_update_iface(): + """ + Test update interface + """ + vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) + iface = vmxml.get_devices('interface')[0] + LOG.debug(f'Interface xml on vm:\n{iface}') + + iface.del_port() + iface.setup_attrs(**update_port_attrs) + LOG.debug(f'Interface xml to update:\n{iface}') + + virsh.update_device(vm_name, iface.xml, **VIRSH_ARGS) + vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) + iface_update = vmxml.get_devices('interface')[0] + LOG.debug(f'Interface after update:\n{iface_update}') + if iface_update.fetch_attrs().get('port') == update_port_attrs.get('port'): + LOG.debug('port isolated value check in xml after update: PASS') + else: + test.fail('port isolated value not updated in vmxml') + + vm_name = params.get('main_vm') + vms = params.get('vms').split() + vm, cli_vm = (env.get_vm(vm_i) for vm_i in vms) + rand_id = utils_misc.generate_random_string(3) + create_linux_br = 'yes' == params.get('create_linux_br', 'no') + linux_br = 'linux_br_' + rand_id + net_br = 'net_br_' + rand_id + outside_ip = params.get('outside_ip') + iface_source = eval(params.get('iface_source')) + iface_attrs = eval(params.get('iface_attrs', '{}')) + cli_iface_attrs = eval(params.get('cli_iface_attrs', '{}')) + net_attrs = eval(params.get('net_attrs', '{}')) + update_port_attrs = eval(params.get('update_port_attrs', '{}')) + host_iface = params.get('host_iface') + host_iface = host_iface if host_iface else utils_net.get_default_gateway( + iface_name=True, force_dhcp=True, json=True) + + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + bkxmls = list(map(vm_xml.VMXML.new_from_inactive_dumpxml, vms)) + + try: + libvirt_version.is_libvirt_feature_supported(params) + if create_linux_br: + LOG.info(f'Create linux bridge: {linux_br}') + utils_net.create_linux_bridge_tmux(linux_br, host_iface) + if net_attrs: + libvirt_network.create_or_del_network(net_attrs) + LOG.debug(f'Network xml:\n' + f'{virsh.net_dumpxml(net_attrs["name"]).stdout_text}') + + vmxml, cli_vmxml = list(map(vm_xml.VMXML.new_from_inactive_dumpxml, vms)) + + setup_vms_ifaces(vmxml, cli_vmxml) + ips = test_ping('before update', ips=None) + test_update_iface() + params['vm_ping_ep_vm'] = params.get('ping_after_update') + test_ping('After update', ips) + + finally: + for backup_xml in bkxmls: + backup_xml.sync() + if net_attrs: + libvirt_network.create_or_del_network(net_attrs, is_del=True) + if create_linux_br: + utils_net.delete_linux_bridge_tmux(linux_br, host_iface) diff --git a/libvirt/tests/src/virtual_network/virtual_network_multivms.py b/libvirt/tests/src/virtual_network/virtual_network_multivms.py index 2ebbd27a299..6713d2dab83 100644 --- a/libvirt/tests/src/virtual_network/virtual_network_multivms.py +++ b/libvirt/tests/src/virtual_network/virtual_network_multivms.py @@ -15,32 +15,14 @@ from virttest.libvirt_xml import vm_xml from virttest.libvirt_xml.devices import interface +from provider.virtual_network import network_base + # Using as lower capital is not the best way to do, but this is just a # workaround to avoid changing the entire file. logging = log.getLogger('avocado.' + __name__) -def create_bridge(br_name, iface_name): - """ - Create bridge attached to physical interface - - :param br_name: bridge to be created - :param iface_name: physical interface name - :return: - """ - # Make sure the bridge not exist - if libvirt.check_iface(br_name, "exists", "--all"): - return - - # Create bridge using commands - utils_package.package_install('tmux') - cmd = 'tmux -c "ip link add name {0} type bridge; ip link set {1} up;' \ - ' ip link set {1} master {0}; ip link set {0} up; pkill dhclient; ' \ - 'sleep 6; dhclient {0}; ifconfig {1} 0"'.format(br_name, iface_name) - process.run(cmd, shell=True, verbose=True) - - def ping_func(session, **expect): """ Check whether ping result meet expectation @@ -368,7 +350,7 @@ def pause_resume_vm(vm_name): for vm_i in vm_list: mac = vm_xml.VMXML.get_first_mac_by_name(vm_i.name) sess = vm_i.wait_for_serial_login() - vm_ip = utils_net.get_guest_ip_addr(sess, mac) + vm_ip = network_base.get_vm_ip(sess, mac, timeout=5) session_n_ip[sess] = vm_ip logging.debug('Vm %s ip: %s', vm_i.name, vm_ip) if not vm_ip: @@ -422,7 +404,4 @@ def pause_resume_vm(vm_name): # Remove test bridge if bridge_created: - cmd = 'tmux -c "ip link set {1} nomaster; ip link delete {0};' \ - 'pkill dhclient; sleep 6; dhclient {1}"'.format( - bridge_name, iface_name) - process.run(cmd, shell=True, verbose=True, ignore_status=True) + utils_net.delete_linux_bridge_tmux(bridge_name, iface_name) diff --git a/libvirt/tests/src/vm_boot_with_kernel_param.py b/libvirt/tests/src/vm_boot_with_kernel_param.py index 1c79775ebf6..1d8fb68c038 100644 --- a/libvirt/tests/src/vm_boot_with_kernel_param.py +++ b/libvirt/tests/src/vm_boot_with_kernel_param.py @@ -53,7 +53,7 @@ def run(test, params, env): cpu_model = cpu.get_cpu_info()['Model name'].upper() if cpu_check not in cpu_model: logging.info("This test will work for %s", cpu_check) - test.skip("Test is not applicable for %s" % cpu_model) + test.cancel("Test is not applicable for %s" % cpu_model) # back up vmxml for vm_name in vms: vm_dict[vm_name] = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) @@ -78,7 +78,7 @@ def run(test, params, env): test.error("couldn't get cpu information from guest " "%s" % vm.name) if cpu_check not in output.upper() and "radix" in boot_log: - test.skip("radix MMU not supported in %s" % output) + test.cancel("radix MMU not supported in %s" % output) status, output = session.cmd_status_output("dmesg") if status: logging.error(output) diff --git a/libvirt/tests/src/vm_create_destroy_concurrently.py b/libvirt/tests/src/vm_create_destroy_concurrently.py new file mode 100644 index 00000000000..6794665c340 --- /dev/null +++ b/libvirt/tests/src/vm_create_destroy_concurrently.py @@ -0,0 +1,141 @@ +from virttest.libvirt_xml import vm_xml +from virttest import data_dir, utils_libvirtd, utils_sys + +import logging +import subprocess + + +def create_scripts(vmxml, num_scripts, timeout): + """ + Create scripts for creating and destroying + VMs. We create separate scripts so we can + execute them concurrently, and overcome + python's GIL + + :param vmxml: Base xml for the VMs + that will be created + + :param num_scripts: number of scripts to + create + + :param timeout: amount of time to spend creating + and destroying VMs + """ + tmp_dir = data_dir.get_tmp_dir(public=False) + vm_name = vmxml.vm_name + script_names = [] + + for i in range(num_scripts): + xml_path = tmp_dir + "/xml_" + str(i) + ".xml" + sh_path = tmp_dir + "/script_" + str(i) + ".sh" + + # SELinux does not allow multiple VM operations the same qcow2 files + vmxml.remove_all_disk() + + for item in ["loader", "nvram"]: + if item in str(vmxml): + vmxml.xmltreefile.remove_by_xpath("/os/%s" % item, remove_all=True) + + with open(xml_path, "w") as outfile: + outfile.write(str(vmxml)) + + logging.debug("Written vm xml file to {}".format(xml_path)) + logging.info("VM XML Contents: \n{}".format(str(vmxml))) + + with open(sh_path, "w") as outfile: + script = """ + end=$((SECONDS+{})); + while [ $SECONDS -lt $end ] ; do + virsh create {} || continue ; + virsh destroy {} ; + done ; + """.format(timeout, xml_path, vm_name) + outfile.write(script) + logging.debug("Script file contents {}".format(script)) + + logging.debug("Written script file to {}".format(sh_path)) + + script_names.append(sh_path) + + return script_names + + +def get_pids_for(names): + """ + Given a list of names, retrieve the + PIDs for matching processes + + Sort of equivalent to: 'ps aux | grep name' + + :param names: List of process names to look for + """ + + pids = utils_sys.get_pids_for(names) + logging.info("Processes and Pids matching {}: {}".format(names, pids)) + + return pids + + +def get_libvirt_pids(test, daemon): + """ + Given a Libvirtd daemon object, retrieve the + pids relevant to the libvirt services + + :param test: Avocado test object + :param daemon: Avocado-vt libvirtd daemon + object. Provides list of libvirt services + """ + if not daemon.is_running(): + test.fail("No libvirt daemon running") + + return get_pids_for(daemon.service_list) + + +def run(test, params, env): + """ + This test ensures that VMs can be created concurrently. + Test Process: + 1) Create bash scripts to create and destroy transient VMs + 2) Execute the scripts simultaneously for a given number of seconds + 3) Check that libvirt daemon(s) have not changed PID + 4) Check to ensure there are no orphan VMs + """ + + daemon = utils_libvirtd.Libvirtd() + pids_before_test = get_libvirt_pids(test, daemon) + + vm_name = params.get("main_vm") + vm = env.get_vm(vm_name) + + num_threads = int(params.get("num_threads", 3)) + wait_time = int(params.get("run_time", 60)) + + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + scripts = create_scripts(vmxml, num_threads, wait_time) + + processes = [] + for i in range(num_threads): + process = subprocess.Popen(["/bin/bash", scripts[i]], stdout=subprocess.PIPE, stderr=subprocess.PIPE) + processes.append(process) + + exit_codes = [p.wait() for p in processes] + + for i in range(len(exit_codes)): + if exit_codes[i] != 0: + fail = processes[i] + logging.debug("Script did not exit cleanly") + logging.debug("\tstderr: {}".format(fail.stderr.read())) + logging.debug("\tstdout: {}".format(fail.stdout.read())) + + if [x for x in exit_codes if x != 0] != []: + test.fail("Test Failed with script errors") + + pids_after_test = get_libvirt_pids(test, daemon) + if pids_before_test != pids_after_test: + logging.debug("Pids Before Test: {}".format(pids_before_test)) + logging.debug("Pids After Test: {}".format(pids_after_test)) + test.fail("Libvirt pids changed") + + vm_pids = get_pids_for([vm_name]) + if vm_pids != []: + test.fail("Orphan VM(s): PID(s) {} belonging to {}".format(vm_pids, vm_name)) diff --git a/libvirt/tests/src/vm_start_destroy_repeatedly.py b/libvirt/tests/src/vm_start_destroy_repeatedly.py new file mode 100644 index 00000000000..603e292c104 --- /dev/null +++ b/libvirt/tests/src/vm_start_destroy_repeatedly.py @@ -0,0 +1,134 @@ +import logging +from virttest import test_setup +from virttest import virsh +from virttest import utils_misc +from virttest.staging import utils_memory +from virttest.libvirt_xml import vm_xml + + +def power_cycle_vm(test, vm, vm_name, login_timeout, startup_wait, resume_wait): + """ + Cycle vm through start-login-shutdown loop + + :param vm: vm object + :param vm_name: vm name + :param login_timeout: timeout given to vm.wait_for_login + :param startup_wait: how long to wait after the vm has been started + :param resume_wait: how long to wait after the paused vm is resumed + + This tests the vm startup and destroy sequences by: + 1) Starting the vm + 2) Verifying the vm is alive + 3) Logging into vm + 4) Logging out of the vm + 5) Destroying the vm + """ + + virsh.start(vm_name, options="--paused", ignore_status=False) + utils_misc.wait_for(lambda: vm.state() == "paused", startup_wait) + + virsh.resume(vm_name, ignore_status=False) + utils_misc.wait_for(lambda: vm.state() == "running", resume_wait) + + session = vm.wait_for_login(timeout=login_timeout) + session.close() + + virsh.shutdown(vm_name, ignore_status=False) + + utils_misc.wait_for(lambda: vm.state() == "shut off", 360) + if vm.state() != "shut off": + test.fail("Failed to shutdown VM") + + +def setup_hugepage(vm, params): + vm_attrs = eval(params.get("vm_attrs", "{}")) + memory_amount = int(vm_attrs["memory"]) + + #Reserve memory for hugepages + hugepage_size = utils_memory.get_huge_page_size() + hugepage_nr = int(memory_amount) / hugepage_size + + config_params = params.copy() + config_params["mem"] = memory_amount + config_params["target_hugepages"] = hugepage_nr + hpc = test_setup.HugePageConfig(config_params) + hpc.setup() + + #Prepare VM XML + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm.name) + backup_xml = vmxml.copy() + + #Remove old memory tags + vmxml.xmltreefile.remove_by_xpath("/memory") + vmxml.xmltreefile.remove_by_xpath("/currentMemory") + + #Include memory backing + mb_xml = vm_xml.VMMemBackingXML() + mb_params = eval(params.get("mb_params", "{}")) + mb_xml.setup_attrs(**mb_params) + vmxml.setup_attrs(**vm_attrs) + vmxml.mb = mb_xml + + #The relevant bug only appears if disk cache='none' + xmltreefile = vmxml.__dict_get__('xml') + disk_nodes = xmltreefile.find("devices").findall("disk") + qcow_disk = [disk for disk in disk_nodes if disk.find("driver").get("type") == "qcow2"][0] + if qcow_disk.find("driver").get("cache") != "none": + qcow_disk.find("driver").set("cache", "none") + + vmxml.xmltreefile.write() + vmxml.sync() + logging.info("New XML for Hugepage testing: {}".format(vmxml)) + + return hugepage_nr, backup_xml, hpc + + +def check_hugepage_status(test, hugepage_nr): + if hugepage_nr != utils_memory.get_num_huge_pages(): + test.fail("Total number of hugepages does not match. Expected: {}. Actual: {}" + .format(hugepage_nr, utils_memory.get_num_huge_pages())) + if hugepage_nr != utils_memory.get_num_huge_pages_free(): + test.fail("Number of free huge pages does not match. Expected: {}. Actual: {}" + .format(hugepage_nr, utils_memory.get_num_huge_pages_free())) + if utils_memory.get_num_huge_pages_rsvd() != 0: + test.fail("Huge pages still reserved. Expected: 0. Actual: {}" + .format(utils_memory.get_num_huge_pages_rsvd())) + + +def run(test, params, env): + """ + Test qemu-kvm startup reliability + + :param test: test object + :param params: Dictionary with the test parameters + :param env: Dictionary with test environment. + """ + + vm_name = params.get("main_vm") + vm = env.get_vm(vm_name) + num_cycles = int(params.get("num_cycles")) # Parameter to control the number of times to start/restart the vm + login_timeout = float(params.get("login_timeout", 240)) # Controls vm.wait_for_login() timeout + startup_wait = float(params.get("startup_wait", 240)) # Controls wait time for virsh.start() + resume_wait = float(params.get("resume_wait", 240)) # Controls wait for virsh.resume() + hugepage_check = bool(params.get("check_hugepage_status", False)) + vm_memory = int(params.get("vm_memory", 8388608)) + + backup_xml = None + hugepage_nr = None + hpc = None + if hugepage_check: + hugepage_nr, backup_xml, hpc = setup_hugepage(vm, params) + logging.info("hugepage_nr: {}".format(hugepage_nr)) + + try: + for i in range(num_cycles): + logging.info("Starting vm '%s' -- attempt #%d", vm_name, i+1) + + power_cycle_vm(test, vm, vm_name, login_timeout, startup_wait, resume_wait) + + logging.info("Completed vm '%s' power cycle #%d", vm_name, i+1) + finally: + if hugepage_check: + check_hugepage_status(test, hugepage_nr) + backup_xml.sync() + hpc.cleanup() diff --git a/provider/backingchain/check_functions.py b/provider/backingchain/check_functions.py index c7e20b84a37..ed90223517b 100644 --- a/provider/backingchain/check_functions.py +++ b/provider/backingchain/check_functions.py @@ -37,12 +37,12 @@ def check_backingchain_from_vmxml(self, disk_type, target_dev, expected_chain): vmxml = vm_xml.VMXML.new_from_dumpxml(self.vm.name) LOG.debug("Current vmxml is:\n%s", vmxml) source_list = DiskBase.get_source_list(vmxml, disk_type, target_dev) - if source_list != expected_chain: self.test.fail('Expect source file to be %s, ' 'but got %s' % (expected_chain, source_list)) else: LOG.debug('Get correct backingchin') + return True def check_block_operation_result(self, vmxml, blockcommand, target_dev, bc_chain): diff --git a/provider/bootc_image_builder/aws_utils.py b/provider/bootc_image_builder/aws_utils.py new file mode 100644 index 00000000000..9e306e75c84 --- /dev/null +++ b/provider/bootc_image_builder/aws_utils.py @@ -0,0 +1,197 @@ +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Copyright Red Hat +# +# SPDX-License-Identifier: GPL-2.0 +# +# Author: chwen@redhat.com +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +"""Helper functions for aws management""" + +import logging +import os +import shutil +import textwrap +import pathlib + +from avocado.utils import process +from avocado.core import exceptions + +LOG = logging.getLogger('avocado.' + __name__) + + +def install_aws_cli_tool(params): + """ + Download AWS command line tool and install it + + :param params: wrap up all parameters + """ + vm_arch_name = params.get("vm_arch_name", "x86_64") + aws_install_cmd = f"curl https://awscli.amazonaws.com/awscli-exe-linux-{vm_arch_name}.zip -o awscliv2.zip " \ + f" && unzip awscliv2.zip -d ./ && ./aws/install " + if not os.path.exists("/usr/local/bin/aws"): + if os.path.exists("/usr/local/aws-cli"): + shutil.rmtree("/usr/local/aws-cli") + if os.path.exists("/usr/local/bin/aws_completer"): + shutil.rmtree("/usr/local/bin/aws_completer") + if os.path.exists("aws"): + shutil.rmtree("aws") + if os.path.exists("awscliv2.zip"): + os.remove("awscliv2.zip") + process.run(aws_install_cmd, shell=True, ignore_status=False) + + +def create_aws_credentials_file(aws_access_key_id, aws_access_key): + """ + Create AWS credentials file + + :param aws_access_key_id: AWS access key id + :param aws_access_key: AWS access key + """ + folder = os.path.expanduser("~/.aws") + if not os.path.exists(folder): + os.mkdir(folder) + secret_path = pathlib.Path(folder) / "credentials" + secret_path.write_text(textwrap.dedent(f""" + [default] + AWS_ACCESS_KEY_ID={aws_access_key_id} + AWS_SECRET_ACCESS_KEY={aws_access_key} + """), encoding="utf8") + + return os.path.join(folder, "credentials") + + +def create_aws_config_file(aws_region): + """ + Create AWS configuration file + + :param aws_region: AWS region + """ + folder = os.path.expanduser("~/.aws") + if not os.path.exists(folder): + os.mkdir(folder) + secret_path = pathlib.Path(folder) / "config" + secret_path.write_text(textwrap.dedent(f""" + [default] + region={aws_region} + """), encoding="utf8") + + return os.path.join(folder, "config") + + +def delete_aws_ami_id(params): + """ + delete AWS AMI id + + @param params: one dictionary wrapping various parameter + """ + ami_id = params.get("aws_ami_id") + if ami_id: + delete_cmd = "aws ec2 deregister-image --image-id %s" % ami_id + process.run(delete_cmd, shell=True, verbose=True, ignore_status=True) + + +def delete_aws_ami_snapshot_id(params): + """ + delete AWS AMI snapshot id + + @param params: one dictionary wrapping various parameter + """ + aws_ami_snapshot_id = params.get("aws_ami_snapshot_id") + if aws_ami_snapshot_id: + delete_cmd = "aws ec2 delete-snapshot --snapshot-id %s" % aws_ami_snapshot_id + process.run(delete_cmd, shell=True, verbose=True, ignore_status=True) + + +def delete_aws_key_pair(params): + """ + delete AWS key pair + + @param params: one dictionary wrapping various parameter + """ + aws_key_name = params.get("aws_key_name") + delete_key_pair_cmd = f"aws ec2 delete-key-pair --key-name {aws_key_name}" + process.run(delete_key_pair_cmd, shell=True, ignore_status=True).exit_status + + +def import_aws_key_pair(params): + """ + Import key into AWS key pair + + @param params: one dictionary wrapping various parameter + """ + aws_key_name = params.get("aws_key_name") + check_key_pair_cmd = f"aws ec2 describe-key-pairs --key-name {aws_key_name}" + status = process.run(check_key_pair_cmd, shell=True, ignore_status=True).exit_status + if status != 0: + public_key_path = os.path.join(os.path.expanduser("~/.ssh/"), "id_rsa.pub") + import_cmd = "aws ec2 import-key-pair --key-name {aws_key_name}--public-key-material fileb://{public_key_path}" + process.run(import_cmd, shell=True, verbose=True, ignore_status=True) + + +def create_aws_instance(params): + """ + create AWS instance + + @param params: one dictionary wrapping various parameter + """ + import_aws_key_pair(params) + vm_name = params.get("vm_name_bootc") + aws_key_name = params.get("aws_key_name") + aws_ami_id = params.get("aws_ami_id") + aws_subnet_id = params.get("aws_subnet_id") + aws_security_group = params.get("aws_security_group") + aws_instance_type = params.get("aws_instance_type") + create_aws_instance_cmd = "aws ec2 run-instances --image-id %s --count 1" \ + " --security-group-ids %s" \ + " --instance-type %s --key-name %s --subnet-id %s" \ + " --associate-public-ip-address --tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=%s}]'" \ + " --block-device-mappings '[{\"DeviceName\":\"/dev/xvda\",\"Ebs\":{\"VolumeSize\":20,\"VolumeType\":\"gp2\"}}]'" \ + " --query 'Instances[0].InstanceId' --output text" % (aws_ami_id, aws_security_group, aws_instance_type, aws_key_name, aws_subnet_id, vm_name) + instance_id = process.run(create_aws_instance_cmd, shell=True, ignore_status=True).stdout_text.strip() + params.update({"aws_instance_id": "%s" % instance_id}) + return instance_id + + +def wait_aws_instance_running(params): + """ + wait for AWS instance running + + @param params: one dictionary wrapping various parameter + """ + aws_instance_id = params.get("aws_instance_id") + if aws_instance_id: + wait_aws_instance_cmd = f"timeout 30 aws ec2 wait instance-running --instance-ids {aws_instance_id}" + process.run(wait_aws_instance_cmd, shell=True, ignore_status=True) + + +def get_aws_instance_privateip(params): + """ + Get AWS instance private ip + + @param params: one dictionary wrapping various parameter + """ + wait_aws_instance_running(params) + aws_instance_id = params.get("aws_instance_id") + if aws_instance_id: + get_aws_instance_privateip_cmd = f"aws ec2 describe-instances --instance-ids {aws_instance_id}" \ + f" --query 'Reservations[*].Instances[*].PrivateIpAddress' --output text" + private_ip = process.run(get_aws_instance_privateip_cmd, shell=True, ignore_status=True).stdout_text.strip() + return private_ip + else: + raise exceptions.TestFail(f"AWS instance not existed yet") + + +def terminate_aws_instance(params): + """ + terminate AWS instance + + @param params: one dictionary wrapping various parameter + """ + aws_instance_id = params.get("aws_instance_id") + if aws_instance_id: + terminate_aws_instance_cmd = f"aws ec2 terminate-instances --instance-ids {aws_instance_id}" + process.run(terminate_aws_instance_cmd, shell=True, ignore_status=True) + wait_instance_terminated = f"timeout 20 aws ec2 wait instance-terminated --instance-ids {aws_instance_id}" + process.run(wait_instance_terminated, shell=True, ignore_status=True) diff --git a/provider/bootc_image_builder/bootc_image_build_utils.py b/provider/bootc_image_builder/bootc_image_build_utils.py new file mode 100644 index 00000000000..ad1b3c54923 --- /dev/null +++ b/provider/bootc_image_builder/bootc_image_build_utils.py @@ -0,0 +1,1395 @@ +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Copyright Red Hat +# +# SPDX-License-Identifier: GPL-2.0 +# +# Author: chwen@redhat.com +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +"""Helper functions for bootc image builder""" + +import logging +import json +import os +import random +import shutil +import subprocess +import time +import textwrap +import pathlib + +from avocado.utils import path, process +from avocado.core import exceptions +from virttest import utils_package +from virttest import remote + +from provider.bootc_image_builder import aws_utils + +LOG = logging.getLogger('avocado.' + __name__) + + +def install_bib_packages(): + """ + install necessary bootc image builder necessary packages + + """ + package_list = ["podman", "skopeo", "virt-install", "curl"] + for pkg in package_list: + try: + path.find_command(pkg) + except path.CmdNotFoundError: + utils_package.package_install(pkg) + + +def podman_command_build(bib_image_url, disk_image_type, image_ref, config=None, local_container=False, tls_verify="true", chownership=None, + key_store_mounted=None, target_arch=None, rootfs=None, options=None, **dargs): + """ + Use podman run command to launch bootc image builder + + :param bib_image_url: bootc image builder url + :param disk_image_type: image type to build [qcow2, ami] (default "qcow2") + :param image_ref: image reference + :param config: config file + :param local_container: whether use local container image + :param tls_verify: whether verify tls connection + :param local_container: whether use local container image + :param chownership: whether change output ownership + :param key_store_mounted: whether mount keystore folder + :param target_arch: whether specify architecture + :param rootfs: whether specify rootfs type + :param options: additional options if needed + :param dargs: standardized function API keywords + :return: CmdResult object + """ + if not os.path.exists("/var/lib/libvirt/images/output"): + os.makedirs("/var/lib/libvirt/images/output") + cmd = "sudo podman run --rm -it --privileged --pull=newer --security-opt label=type:unconfined_t -v /var/lib/libvirt/images/output:/output" + if config: + if "toml" in config: + cmd += " -v %s:/config.toml " % config + else: + cmd += " -v %s:/config.json " % config + + cmd += " -v /var/lib/containers/storage:/var/lib/containers/storage " + + if options is not None: + cmd += " %s " % options + + if key_store_mounted: + cmd += " -v %s " % key_store_mounted + + if dargs.get('aws.secrets'): + cmd += " --env-file=%s " % dargs.get('aws.secrets') + + cmd += " %s " \ + " --type %s --tls-verify=%s " % (bib_image_url, disk_image_type, tls_verify) + + if type in ['anaconda-iso'] and "9.4" not in bib_image_url and "9.5" not in bib_image_url: + cmd += " --use-librepo " + + if config: + if "toml" in config: + cmd += " --config /config.toml " + else: + cmd += " --config /config.json " + + if target_arch: + cmd += " --target-arch=%s " % target_arch + + aws_ami_name = dargs.get('aws_ami_name') + if aws_ami_name: + random_int = random.randint(1, 1000) + vm_arch_name = dargs.get("vm_arch_name", "x86_64") + LOG.debug(f"vm_arch_name value in podman build is : {vm_arch_name}") + aws_ami_name = f"{aws_ami_name}_{vm_arch_name}_{random_int}" + cmd += f" --aws-ami-name {aws_ami_name} --aws-bucket {dargs.get('aws_bucket')} --aws-region {dargs.get('aws_region')} " + + if local_container: + cmd += " --local %s " % image_ref + else: + cmd += " %s " % image_ref + + if chownership: + cmd += " --chown %s " % chownership + + if rootfs: + cmd += " --rootfs %s " % rootfs + + debug = dargs.get("debug", True) + + ignore_status = dargs.get("ignore_status", False) + timeout = int(dargs.get("timeout", "1800")) + LOG.debug("the whole podman command: %s\n" % cmd) + + ret = process.run( + cmd, timeout=timeout, verbose=debug, ignore_status=ignore_status, shell=True) + + return ret + + +def podman_login(podman_username, podman_password, registry): + """ + Use podman to login in registry + + :param podman_username: podman username + :param podman_password: podman password + :param registry: registry to login + :return: CmdResult object + """ + command = "sudo podman login -u='%s' -p='%s' %s " % (podman_username, podman_password, registry) + process.run( + command, timeout=60, verbose=True, ignore_status=False, shell=True) + + +def podman_login_with_auth(auth_file, registry): + """ + Use podman to login in registry with auth file + + :param auth_file: auth file + :param registry: registry to login + :return: CmdResult object + """ + command = "sudo podman login --authfile=%s %s " % (auth_file, registry) + process.run( + command, timeout=60, verbose=True, ignore_status=False, shell=True) + + +def podman_push(podman_username, podman_password, registry, container_url): + """ + Use podman image to registry + + :param podman_username: podman username + :param podman_password: podman password + :param registry: registry to login + :param container_url: image url + :return: CmdResult object + """ + podman_login(podman_username, podman_password, registry) + command = "sudo podman push %s " % container_url + process.run( + command, timeout=1200, verbose=True, ignore_status=False, shell=True) + + +def podman_pull(container_url): + """ + Use podman pull registry image + + :param container_url: image url + :return: CmdResult object + """ + pull_image_cmd = f"sudo podman pull {container_url}" + process.run(pull_image_cmd, timeout=600, verbose=True, ignore_status=False, shell=True) + + +def create_config_json_file(params): + """ + create json configuration file + + :param params: one dictionary to pass in configuration + """ + folder = params.get("config_file_path") + username = params.get("os_username") + password = params.get("os_password") + kickstart = "yes" == params.get("kickstart") + public_key_path = os.path.join(os.path.expanduser("~/.ssh/"), "id_rsa.pub") + filesystem_size_set = "yes" == params.get("filesystem_size_set") + enable_lvm_disk_partitions = "yes" == params.get("enable_lvm_disk_partitions") + enable_plain_disk_partitions = "yes" == params.get("enable_plain_disk_partitions") + enable_btrf_disk_partitions = "yes" == params.get("enable_btrf_disk_partitions") + file_dir_set = "yes" == params.get("file_dir_set") + + filesystem_dict = {"filesystem": [ + { + "mountpoint": "/", + "minsize": "10 GiB" + }, + { + "mountpoint": "/var/data", + "minsize": "15 GiB" + } + ] + } + + files_dict = {"files": [ + { + "path": "/etc/custom_file", + "data": "hello world" + }, + ] + } + + directories_dict = {"directories": [ + { + "path": "/etc/custom_dir", + + }, + ] + } + + enable_lvm_disk_partitions_dict = {"disk": { + "partitions": [ + { + "type": "plain", + "label": "data", + "minsize": "4 GiB", + "fs_type": "xfs", + "mountpoint": "/data" + }, + { + "type": "lvm", + "minsize": "15 GiB", + "name": "mainvg", + "logical_volumes": [ + { + "name": "rootlv", + "label": "root", + "minsize": "10 GiB", + "fs_type": "xfs", + "mountpoint": "/" + }, + { + "name": "swaplv", + "label": "swap", + "minsize": "1 GiB", + "fs_type": "swap" + }, + { + "name": "homelv", + "label": "home", + "minsize": "3 GiB", + "fs_type": "xfs", + "mountpoint": "/home" + }, + { + "name": "varloglv", + "label": "var", + "minsize": "2 GiB", + "fs_type": "xfs", + "mountpoint": "/var/log" + } + ] + } + ] + } + } + + enable_plain_disk_partitions_dict = {"disk": { + "partitions": [ + { + "type": "plain", + "label": "root", + "minsize": "10 GiB", + "minsize": "10 GiB", + "fs_type": "xfs", + "mountpoint": "/", + "minsize": "1 GiB", + "fs_type": "swap", + "minsize": "2 GiB", + "fs_type": "xfs", + "mountpoint": "/var/log" + } + ] + } + } + + enable_btrf_disk_partitions_dict = {"disk": { + "partitions": [ + { + "type": "plain", + "label": "swap", + "minsize": "4 GiB", + "fs_type": "swap" + }, + { + "type": "btrfs", + "minsize": "10 GiB", + "subvolumes": [ + { + "name": "root", + "mountpoint": "/" + }, + { + "name": "varlog", + "mountpoint": "/var/log" + } + ] + } + ] + } + } + + if not os.path.exists(public_key_path): + LOG.debug("public key doesn't exist, will help create one") + key_gen_cmd = "ssh-keygen -q -t rsa -N '' <<< $'\ny' >/dev/null 2>&1" + process.run(key_gen_cmd, shell=True, ignore_status=False) + + with open(public_key_path, 'r') as ssh: + key_value = ssh.read().rstrip() + if not kickstart: + cfg = { + "blueprint": { + "customizations": { + "user": [ + { + "name": username, + "password": password, + "groups": ["wheel"], + "key": "%s" % key_value, + }, + ], + "kernel": {"append": "mitigations=auto,nosmt"}, + }, + }, + } + else: + cfg = { + "blueprint": { + "customizations": { + "kernel": {"append": "mitigations=auto,nosmt"}, + "installer": { + "modules": {"enable": [ + "org.fedoraproject.Anaconda.Modules.Localization", + # disable takes precedence + "org.fedoraproject.Anaconda.Modules.Timezone", + ], + "disable": [ + # disable takes precedence + "org.fedoraproject.Anaconda.Modules.Timezone", + ] + }, + "kickstart": {"contents": "user --name %s --password %s --groups wheel\n" + "sshkey --username %s \"%s\"\ntext --non-interactive\nzerombr\n" + "clearpart --all --initlabel --disklabel=gpt\nautopart --noswap --type=lvm\n" + "network --bootproto=dhcp --device=link --activate --onboot=on\n reboot" % (username, password, username, key_value) + } + } + } + } + } + + if enable_lvm_disk_partitions: + filesystem_size_set = False + cfg['blueprint']['customizations'].update(enable_lvm_disk_partitions_dict) + + if enable_plain_disk_partitions: + filesystem_size_set = False + cfg['blueprint']['customizations'].update(enable_plain_disk_partitions_dict) + + if enable_btrf_disk_partitions: + cfg['blueprint']['customizations'].update(enable_btrf_disk_partitions_dict) + + if filesystem_size_set: + cfg['blueprint']['customizations'].update(filesystem_dict) + + if file_dir_set: + cfg['blueprint']['customizations'].update(files_dict) + cfg['blueprint']['customizations'].update(directories_dict) + + LOG.debug("what is cfg:%s", cfg) + config_json_path = pathlib.Path(folder) / "config.json" + config_json_path.write_text(json.dumps(cfg), encoding="utf-8") + return os.path.join(folder, "config.json") + + +def create_config_toml_file(params): + """ + create toml configuration file + + :param params: one dictionary to pass in configuration + """ + folder = params.get("config_file_path") + username = params.get("os_username") + password = params.get("os_password") + kickstart = "yes" == params.get("kickstart") + public_key_path = os.path.join(os.path.expanduser("~/.ssh/"), "id_rsa.pub") + filesystem_size_set = "yes" == params.get("filesystem_size_set") + filesystem_size_str = "" + fips_content = "" + file_dir_set = "yes" == params.get("file_dir_set") + file_dir_str = "" + + if not os.path.exists(public_key_path): + LOG.debug("public key doesn't exist, will help create one") + key_gen_cmd = "ssh-keygen -q -t rsa -N '' <<< $'\ny' >/dev/null 2>&1" + process.run(key_gen_cmd, shell=True, ignore_status=False) + + with open(public_key_path, 'r') as ssh: + key_value = ssh.read().rstrip() + + if filesystem_size_set: + filesystem_size_str = f""" + [[customizations.filesystem]] + mountpoint = "/" + minsize = "10 GiB" + + [[customizations.filesystem]] + mountpoint = "/var/data" + minsize = "20 GiB" + """ + if file_dir_set: + file_dir_str = f""" + [[customizations.files]] + path = "/etc/custom_file" + data = "hello world" + + [[customizations.directories]] + path = "/etc/custom_dir" + """ + + if not kickstart: + container_file_content = f"""\n + [[customizations.user]] + name = "{username}" + password = "{password}" + key = "{key_value}" + groups = ["wheel"] + {filesystem_size_str} + {file_dir_str} + [customizations.kernel] + append = "mitigations=auto,nosmt" + """ + else: + kick_start = {"contents": "user --name %s --password %s --groups wheel\n" + "rootpw --lock --iscrypted locked\n" + "sshkey --username %s \"%s\"\ntext --non-interactive\nzerombr\n" + "clearpart --all --initlabel --disklabel=gpt\nautopart --noswap --type=lvm\n" + "network --bootproto=dhcp --device=link --activate --onboot=on\n reboot" % (username, password, username, key_value) + } + if params.get("fips_enable") == "yes": + fips_content = f""" + [customizations] + fips = true + """ + + container_file_content = f"""\n + [customizations.kernel] + append = "mitigations=auto,nosmt" + {fips_content} + [customizations.installer.modules] + enable = [ + "org.fedoraproject.Anaconda.Modules.Localization" + ] + disable = [ + "org.fedoraproject.Anaconda.Modules.Timezone" + ] + {filesystem_size_str} + {file_dir_str} + [customizations.installer.kickstart] + contents = \"""{kick_start.get("contents")}\""" + """ + LOG.debug("what is toml content:%s", container_file_content) + config_toml_path = pathlib.Path(folder) / "config.toml" + config_toml_path.write_text(textwrap.dedent(container_file_content), encoding="utf8") + return os.path.join(folder, "config.toml") + + +def create_auth_json_file(params): + """ + create authentication json configuration file + + :param params: one dictionary to pass in configuration + """ + folder = params.get("config_file_path") + redhat_stage_registry = params.get("redhat_stage_registry") + registry_stage_key = params.get("registry_stage_key") + + cfg = { + "auths": { + "%s" % redhat_stage_registry: { + "auth": "%s" % registry_stage_key + } + } + } + + LOG.debug("what is auth json:%s", cfg) + config_json_path = pathlib.Path(folder) / "auth.json" + config_json_path.write_text(json.dumps(cfg), encoding="utf-8") + final_config_file = os.path.join(folder, "auth.json") + return final_config_file + + +def create_aws_secret_file(folder, aws_access_key_id, aws_access_key): + """ + Create aws secret key file + + :param folder: folder is used to have secret file + :param aws_access_key_id: aws access key id + :param aws_access_key: aws access key + """ + secret_path = pathlib.Path(folder) / "aws.secrets" + secret_path.write_text(textwrap.dedent(f""" + AWS_ACCESS_KEY_ID={aws_access_key_id} + AWS_SECRET_ACCESS_KEY={aws_access_key} + """), encoding="utf8") + + return os.path.join(folder, "aws.secrets") + + +def create_and_build_container_file(params): + """ + Create container file and build container tag + + :param params: one dictionary to wrap up all parameters + """ + folder = params.get("container_base_folder") + build_container = params.get("build_container") + container_tag = params.get("container_url") + manifest = params.get("manifest") + + # clean up existed image + clean_image_cmd = "sudo podman rmi %s" % container_tag + if manifest: + clean_image_cmd = "sudo podman manifest rm %s" % container_tag + process.run(clean_image_cmd, shell=True, ignore_status=True) + etc_config = '' + dnf_vmware_tool = '' + dnf_fips_install = '' + + # create VMware tool + if params.get("add_vmware_tool") == "yes": + vmware_tool_path = os.path.join(folder, "etc/vmware-tools/") + if not os.path.exists(vmware_tool_path): + os.makedirs(vmware_tool_path) + etc_config = "COPY etc/ /etc/" + dnf_vmware_tool = "dnf -y install open-vm-tools && dnf clean all && systemctl enable vmtoolsd.service && " + + download_vmware_config_cmd = "curl https://gitlab.com/fedora/bootc/" \ + "examples/-/raw/main/vmware/etc/vmware-tools/tools.conf > %s/tools.conf" % vmware_tool_path + process.run(download_vmware_config_cmd, shell=True, verbose=True, ignore_status=True) + + if params.get("fips_enable") == "yes" and params.get("enable_fips_enable_repo") == "yes": + dnf_fips_install = "RUN cat > /usr/lib/bootc/kargs.d/01-fips.toml <<'EOF'\n" \ + "kargs = ['fips=1']\n" \ + "match-architectures = ['x86_64']\n" \ + "EOF\n" \ + "RUN dnf install -y crypto-policies-scripts && " \ + "update-crypto-policies --no-reload --set FIPS " + + container_path = pathlib.Path(folder) / "Containerfile_tmp" + if os.path.exists("/etc/yum.repos.d/beaker-BaseOS.repo"): + shutil.copy("/etc/yum.repos.d/beaker-BaseOS.repo", folder) + if os.path.exists("/etc/yum.repos.d/beaker-AppStream.repo"): + shutil.copy("/etc/yum.repos.d/beaker-AppStream.repo", folder) + + create_sudo_file = "RUN echo '%wheel ALL=(ALL) NOPASSWD: ALL' > /etc/sudoers.d/wheel-passwordless-sudo" + enable_root_ssh = "RUN echo 'PermitRootLogin yes' >> /etc/ssh/sshd_config.d/01-permitrootlogin.conf" + + container_file_content = f"""\n + FROM {build_container} + {etc_config} + COPY beaker-BaseOS.repo /etc/yum.repos.d/ + COPY beaker-AppStream.repo /etc/yum.repos.d/ + {create_sudo_file} + {enable_root_ssh} + {dnf_fips_install} + RUN {dnf_vmware_tool} dnf install -y vim && dnf clean all + """ + + custom_repo = params.get("custom_repo") + if custom_repo: + repo_path = pathlib.Path(folder) / "rhel-9.4.repo" + repo_prefix = "rhel-9.4" + if "rhel-9.5" in custom_repo: + repo_path = pathlib.Path(folder) / "rhel-9.5.repo" + repo_prefix = "rhel-9.5" + if "rhel-9.6" in custom_repo: + repo_path = pathlib.Path(folder) / "rhel-9.6.repo" + repo_prefix = "rhel-9.6" + if "rhel-10.0" in custom_repo: + repo_path = pathlib.Path(folder) / "rhel-10.0.repo" + repo_prefix = "rhel-10.0" + compose_url = params.get("compose_url") + baseurl = get_baseurl_from_repo_file("/etc/yum.repos.d/beaker-AppStream.repo") + if baseurl: + compose_url = baseurl + vm_arch_name = params.get("vm_arch_name", "x86_64") + repo_content = f"""\n + [{repo_prefix}-baseos] + name=beaker-BaseOS\n + baseurl={compose_url}/compose/BaseOS/{vm_arch_name}/os/ + enabled=1 + gpgcheck=0 + sslverify=0\n + [{repo_prefix}-appstream] + name=beaker-appstream\n + baseurl={compose_url}/compose/AppStream/{vm_arch_name}/os/ + enabled=1 + gpgcheck=0 + sslverify=0\n + """ + nfv_repo_content = f""" + [{repo_prefix}-nfv] + name=beaker-NFV\n + baseurl={compose_url}/compose/NFV/{vm_arch_name}/os/ + enabled=1 + gpgcheck=0 + sslverify=0\n + """ + crb_repo_content = f""" + [{repo_prefix}-crb] + name=beaker-CRB\n + baseurl={compose_url}/compose/CRB/{vm_arch_name}/os/ + enabled=1 + gpgcheck=0 + sslverify=0\n + """ + + if "x86_64" in vm_arch_name: + repo_content = repo_content + nfv_repo_content + crb_repo_content + repo_path.write_text(textwrap.dedent(repo_content), encoding="utf8") + container_file_content = f"""\n + FROM {build_container} + COPY {custom_repo} /etc/yum.repos.d/ + {create_sudo_file} + {enable_root_ssh} + {dnf_fips_install} + Run dnf clean all + """ + build_cmd = "sudo podman build -t %s -f %s" % (container_tag, str(container_path)) + if manifest: + container_file_content = f"""\n + FROM {build_container} + {create_sudo_file} + {enable_root_ssh} + """ + build_cmd = "sudo podman build --platform linux/arm64,linux/amd64 --manifest %s -f %s" % (manifest, str(container_path)) + + container_path.write_text(textwrap.dedent(container_file_content), encoding="utf8") + process.run(build_cmd, shell=True, ignore_status=False) + + +def create_and_start_vmware_vm(params): + """ + prepare environment, upload vmdk, create and start vm + + @param params: one dictionary wrapping various parameter + """ + image_type = params.get("disk_image_type") + try: + install_vmware_govc_tool(params) + setup_vCenter_env(params) + (params) + if image_type == "vmdk": + import_vmdk_to_vCenter(params) + elif image_type == "anaconda-iso": + import_iso_to_vCenter(params) + create_vm_in_vCenter(params) + if image_type == "vmdk": + attach_disk_to_vm(params) + elif image_type == "anaconda-iso": + attach_iso_to_vm(params) + create_vmdk_on_vm(params) + + power_on_vm(params) + add_vmware_tool = "yes" == params.get("add_vmware_tool") + if add_vmware_tool: + verify_ssh_login_vm(params) + finally: + delete_vm_if_present(params) + + +def create_and_start_cloud_vm(params): + """ + prepare environment, create and start VM in cloud + + @param params: one dictionary wrapping various parameter + """ + try: + aws_utils.create_aws_instance(params) + verify_ssh_login_vm(params) + finally: + cleanup_aws_env(params) + + +def install_vmware_govc_tool(params): + """ + Download VmWare govc tool and install it + + :param params: wrap up test parameters + """ + vm_arch_name = params.get("vm_arch_name", "x86_64") + if "arm64" in vm_arch_name: + vm_arch_name = "arm64" + govc_install_cmd = f"curl -L -o - 'https://github.com/vmware/govmomi/releases/latest/download/govc_Linux_{vm_arch_name}.tar.gz' " \ + f"| tar -C /usr/local/bin -xvzf - govc" + if not os.path.exists("/usr/local/bin/govc"): + process.run(govc_install_cmd, shell=True, ignore_status=False) + + +def setup_vCenter_env(params): + """ + Download VmWare govc tool and install it + + @param params: one dictionary wrapping various parameter + """ + # vCenter information + os.environ["GOVC_URL"] = params.get("GOVC_URL") + os.environ["GOVC_USERNAME"] = params.get("GOVC_USERNAME") + os.environ["GOVC_PASSWORD"] = params.get("GOVC_PASSWORD") + os.environ["DATA_CENTER"] = params.get("DATA_CENTER") + os.environ["GOVC_DATASTORE"] = "%s" % params.get("DATA_STORE") + os.environ["GOVC_INSECURE"] = "true" + process.run("govc about", shell=True, ignore_status=False) + + +def import_vmdk_to_vCenter(params): + """ + import vmdk into vCenter + + @param params: one dictionary wrapping various parameter + """ + delete_datastore_if_existed(params) + import_cmd = f"govc import.vmdk -force=true {params.get('vm_disk_image_path')}" + process.run(import_cmd, shell=True, verbose=True, ignore_status=False) + + +def create_vmdk_on_vm(params): + """ + create empty vmdk on VM + + @param params: one dictionary wrapping various parameters + """ + vm_name = params.get("vm_name_bootc") + create_vmdk_cmd = f"govc vm.disk.create -vm {vm_name} -name {vm_name}.vmdk 10G" + process.run(create_vmdk_cmd, shell=True, verbose=True, ignore_status=False) + + +def import_iso_to_vCenter(params): + """ + import iso into vCenter + + @param params: one dictionary wrapping various parameter + """ + boot = params.get("vm_name_bootc") + iso_location = params.get("vm_disk_image_path") + check_iso_cmd = f"govc datastore.ls {boot}" + if process.run(check_iso_cmd, shell=True, verbose=True, ignore_status=True).exit_status == 0: + delete_iso_cmd = f"govc datastore.rm -f {boot}" + process.run(delete_iso_cmd, shell=True, verbose=True, ignore_status=False) + + import_iso_cmd = f"govc datastore.upload {iso_location} {boot}" + process.run(import_iso_cmd, shell=True, verbose=True, ignore_status=False) + + +def create_vm_in_vCenter(params): + """ + create VM in vCenter + + @param params: one dictionary wrapping various parameter + """ + create_cmd = "govc vm.create -net='VM Network' -on=false -c=2 " \ + "-m=4096 -g=centos9_64Guest -firmware=%s %s" % (params.get("firmware"), params.get("vm_name_bootc")) + process.run(create_cmd, shell=True, verbose=True, ignore_status=False) + + +def attach_disk_to_vm(params): + """ + attach disk to VM in vCenter + + @param params: one dictionary wrapping various parameter + """ + vm_name = params.get("vm_name_bootc") + attach_cmd = "govc vm.disk.attach -vm %s" \ + " -controller %s -link=false -disk=%s/%s.vmdk" % (vm_name, params.get("controller"), vm_name, vm_name) + process.run(attach_cmd, shell=True, verbose=True, ignore_status=False) + + +def attach_iso_to_vm(params): + """ + attach ISO to VM in vCenter + + @param params: one dictionary wrapping various parameter + """ + vm_name = params.get("vm_name_bootc") + add_cdrom_cmd = f"govc device.cdrom.add -vm {vm_name}" + id = process.run(add_cdrom_cmd, shell=True, verbose=True, ignore_status=False).stdout_text.strip() + + #insert ISO into CDROM + attach_cmd = f"govc device.cdrom.insert -vm {vm_name} -device {id} {vm_name}" + process.run(attach_cmd, shell=True, verbose=True, ignore_status=False) + + +def power_on_vm(params): + """ + power on VM in vCenter + + @param params: one dictionary wrapping various parameter + """ + vm_name = params.get("vm_name_bootc") + wait_boot_time = int(params.get("wait_boot_time", "40")) + power_on_cmd = "govc vm.power -on=true %s" % vm_name + process.run(power_on_cmd, shell=True, verbose=True, ignore_status=False) + time.sleep(wait_boot_time) + state_cmd = "govc vm.info -json %s |jq -r .virtualMachines[0].summary.runtime.powerState" % vm_name + result = process.run(state_cmd, shell=True, verbose=True, ignore_status=False).stdout_text.strip() + if result not in "poweredOn": + raise exceptions.TestFail(f"The VM state is not powered on, real state is: {result}") + + +def verify_ssh_login_vm(params): + """ + Verify ssh login VM successfully + + @param params: one dictionary wrapping various parameter + """ + ip_address = params.get("ip_address") + disk_image_type = params.get("disk_image_type") + aws_config_dict = eval(params.get("aws_config_dict", '{}')) + if ip_address is None: + if disk_image_type in ['ami'] and len(aws_config_dict) != 0: + ip_address = aws_utils.get_aws_instance_privateip(params) + else: + ip_address = get_vm_ip_address(params) + user = params.get("os_username") + passwd = params.get("os_password") + vm_params = {} + vm_params.update({"server_ip": ip_address}) + vm_params.update({"server_user": user}) + vm_params.update({"server_pwd": passwd}) + vm_params.update({"vm_ip": ip_address}) + vm_params.update({"vm_user": user}) + vm_params.update({"vm_pwd": passwd}) + remote_vm_obj = remote.VMManager(vm_params) + remote_vm_obj.check_network() + remote_vm_obj.setup_ssh_auth() + result = remote_vm_obj.cmd_status_output("whoami")[1].strip() + LOG.debug(f" remote VM test is: {result} ") + if result not in user: + raise exceptions.TestFail(f"The expected user name should be: {user}, but actually is: {result}") + return remote_vm_obj + + +def get_vm_ip_address(params): + """ + Get VM ip_address in vCenter + + @param params: one dictionary wrapping various parameter + """ + vm_name = params.get("vm_name_bootc") + get_ip_cmd = "govc vm.ip -v4 -wait=3m %s" % vm_name + result = process.run(get_ip_cmd, shell=True, verbose=True, ignore_status=False) + LOG.debug("result wcf: {result.stdout_text}") + if result.stdout_text.strip() == "" or result.stdout_text.strip() is None: + raise exceptions.TestFail(f"Can not get ip address") + return result.stdout_text.strip() + + +def delete_vm_if_present(params): + """ + delete vm if present + + @param params: one dictionary wrapping various parameter + """ + vm_name = params.get("vm_name_bootc") + find_cmd = "govc find / -type m -name %s" % vm_name + cmd_result = process.run(find_cmd, shell=True, verbose=True, ignore_status=True).stdout_text + LOG.debug(f"find vm in vsphere is:{cmd_result}") + if cmd_result: + vm_path = cmd_result.strip() + delete_cmd = "govc vm.destroy %s && govc datastore.rm -f %s" % (vm_name, vm_name) + process.run(delete_cmd, shell=True, verbose=True, ignore_status=True) + + +def delete_datastore_if_existed(params): + """ + delete data store if existed + + @param params: one dictionary wrapping various parameter + """ + vm_name = params.get("vm_name_bootc") + find_cmd = "govc datastore.ls %s" % vm_name + cmd_result = process.run(find_cmd, shell=True, verbose=True, ignore_status=True).stdout_text + if cmd_result: + delete_cmd = "govc datastore.rm -f %s" % vm_name + process.run(delete_cmd, shell=True, verbose=True, ignore_status=True) + + +def parse_container_url(params): + """ + Parse repository information from container url + + @param params: wrapped dictionary containing url + """ + container_url = params.get("container_url") + repository_info = container_url.split('/')[-1] + repository_name = repository_info.split(':')[0] + if "localhost" in container_url: + repository_name = "localhost-%s" % repository_name + return repository_name + + +def convert_disk_image_name(params): + """ + Convert disk type image name + + @param params: wrapped dictionary containing parameters + """ + repository_name = parse_container_url(params) + origin_disk_name, extension = os.path.splitext(params.get("output_name")) + dest_disk_name = "%s-%s%s" % (origin_disk_name, repository_name, extension) + return dest_disk_name + + +def set_root_passwd(remote_vm_obj, params): + """ + Use passwd to change root password + + @param remote_vm_obj: remote vm object + @param params: one dictionary containing parameters + """ + disk_image_type = params.get("disk_image_type") + root_passwd = params.get("root_passwd", "redhat") + fips_enable = params.get("fips_enable") == "yes" + if fips_enable: + change_passwd = remote_vm_obj.cmd_status_output("echo root:%s|sudo chpasswd" % root_passwd)[1].strip() + LOG.debug(f"change remote VM root password is: {change_passwd} ") + remote_vm_obj = None + + +def virt_install_vm(params): + """ + Use virt install tool to install vm + + @param params: one dictionary containing parameters + """ + vm_name = params.get("vm_name_bootc") + disk_image_type = params.get("disk_image_type") + image_ref = params.get("image_ref") + disk_path = params.get("vm_disk_image_path") + iso_install_path = params.get("iso_install_path") + format = params.get("disk_image_type") + firmware = params.get("firmware") + ovmf_code_path = params.get("ovmf_code_path") + ovmf_vars_path = params.get("ovmf_vars_path") + boot_option = '' + vm_arch_name = params.get("vm_arch_name", "x86_64") + machine_type = " --machine q35 " + secure_boot_feature0_enable = "yes" + if "aarch64" in vm_arch_name: + machine_type = "" + secure_boot_feature0_enable = "no" + if firmware in ['efi']: + if image_ref in ["centos", "fedora"]: + boot_option = f"--boot uefi,firmware.feature0.name=secure-boot,firmware.feature0.enabled={secure_boot_feature0_enable}," \ + f"firmware.feature1.name=enrolled-keys,firmware.feature1.enabled=no" + else: + boot_option = " --boot uefi" + if disk_image_type in ["anaconda-iso"]: + if os.path.exists(iso_install_path): + os.remove(iso_install_path) + check_squashfs = params.get("check_squashfs") == "yes" + if check_squashfs: + check_image_filesystem(params) + cmd = ("virt-install --name %s" + " --disk path=%s,bus=virtio,format=qcow2,size=12" + " --vcpus 3 --memory 3096" + " --osinfo detect=on,require=off" + " --graphics vnc" + " --video virtio" + " --serial pty" + " --wait 10" + " --cdrom %s" + " --debug" + " %s " + " %s " + " --noreboot" % + (vm_name, iso_install_path, disk_path, machine_type, boot_option)) + else: + cmd = ("virt-install --name %s" + " --disk path=%s,bus=virtio,format=%s" + " --import " + " --vcpus 3 --memory 3096" + " --osinfo detect=on,require=off" + " --graphics vnc --video virtio --noautoconsole --serial pty" + " --wait 10" + " --debug" + " %s " + " %s " + " --noreboot" % + (vm_name, disk_path, format, machine_type, boot_option)) + process.run(cmd, shell=True, verbose=True, ignore_status=True) + + +def check_image_filesystem(params): + """ + Check image file system + + @param params: one dictionary containing parameters + """ + disk_path = params.get("vm_disk_image_path") + mount_cmd = f"mount {disk_path} /mnt" + process.run(mount_cmd, shell=True, verbose=True, ignore_status=False) + check_squashfs_cmd = "file /mnt/images/install.img" + ret = process.run(check_squashfs_cmd, verbose=True, ignore_status=False, shell=True).stdout_text + if "Squashfs" not in ret: + raise exceptions.TestFail(f"Squashfs is not enabled") + + +def verify_in_vm_internal(vm, params): + """ + Verify something by login Vm + + @param vm: vm object + @param params: one dictionary wrapping various parameter + """ + root_user = "root" + root_passwd = params.get("root_passwd", "redhat") + fips_enable = params.get("fips_enable") == "yes" + disk_image_type = params.get("disk_image_type") + vm_arch_name = params.get("vm_arch_name", "x86_64") + if fips_enable and "x86_64" in vm_arch_name and disk_image_type not in ["anaconda-iso"]: + vm_session = vm.wait_for_login(username=root_user, password=root_passwd) + cmd = "fips-mode-setup --check" + res = vm_session.cmd_output(cmd) + vm_session.close() + LOG.debug('Session outputs:\n%s', res) + if "FIPS mode is enabled" not in res: + raise exceptions.TestFail(f"FIPS mode is not enabled") + + +def create_qemu_vm(params, env, test): + """ + prepare environment, virt install, and login vm + + @param params: one dictionary wrapping various parameters + @param env: environment + @param test: test case itself + """ + try: + virt_install_vm(params) + vm_name = params.get("vm_name_bootc") + env.create_vm(vm_type='libvirt', target=None, name=vm_name, params=params, bindir=test.bindir) + vm = env.get_vm(vm_name) + if vm.is_dead(): + LOG.debug("VM is dead, starting") + # workaround VM can not start in the first time on rhel10 + try: + vm.start() + except Exception as ex: + LOG.debug("start vm in retries") + vm.start() + ip_address = vm.wait_for_get_address(nic_index=0, timeout=120) + params.update({"ip_address": ip_address.strip()}) + remote_vm_obj = verify_ssh_login_vm(params) + LOG.debug(f"ip addressis wcf: {ip_address}") + set_root_passwd(remote_vm_obj, params) + verify_in_vm_internal(vm, params) + finally: + if vm and vm.is_alive(): + vm.destroy(gracefully=False) + vm.undefine(options='--nvram') + + +def get_group_and_user_ids(folder_path): + try: + stat_info = os.stat(folder_path) + gid = stat_info.st_gid + uid = stat_info.st_uid + return gid, uid + except FileNotFoundError: + LOG.debug(f"Folder '{folder_path}' not found.") + return None, None + except Exception as ex: + LOG.debug(f"Error occurred: {ex}") + return None, None + + +def prepare_aws_env(params): + """ + One method to prepare AWS environment for image build + + :param params: one collective object representing wrapped parameters + """ + aws_access_key_id = params.get("aws_access_key_id") + aws_access_key = params.get("aws_access_key") + aws_secret_folder = params.get("aws_secret_folder") + aws_region = params.get("aws_region") + create_aws_secret_file(aws_secret_folder, aws_access_key_id, aws_access_key) + aws_utils.create_aws_credentials_file(aws_access_key_id, aws_access_key) + aws_utils.create_aws_config_file(aws_region) + vm_arch_name = params.get("vm_arch_name", "x86_64") + if "s390x" not in vm_arch_name: + aws_utils.install_aws_cli_tool(params) + + +def cleanup_aws_env(params): + """ + One method to clean up AWS environment for image build + + :param params: one collective object representing wrapped parameters + """ + aws_utils.terminate_aws_instance(params) + aws_utils.delete_aws_ami_id(params) + aws_utils.delete_aws_ami_snapshot_id(params) + + +def cleanup_aws_ami_and_snapshot(params): + """ + One method to clean up AWS ami and snapshot for image build + + :param params: one collective object representing wrapped parameters + """ + aws_utils.delete_aws_ami_id(params) + aws_utils.delete_aws_ami_snapshot_id(params) + + +def convert_vhd_to_qcow2(params): + """ + Convert vhd disk format into qcow2 + + @param params: one dictionary wrapping various parameter + :return: Converted image path + """ + original_image_path = params.get('vm_disk_image_path') + converted_image_path = original_image_path.replace("vhd", "qcow2") + LOG.debug(f"converted vhd to qcow2 output is : {converted_image_path}") + + convert_cmd = f"qemu-img convert -p -f vpc -O qcow2 {original_image_path} {converted_image_path}" + process.run(convert_cmd, shell=True, verbose=True, ignore_status=False) + return converted_image_path + + +def untar_tgz_to_raw(params): + """ + extract image.tgz for GCP format to raw format:disk.raw + + @param params: one dictionary wrapping various parameter + """ + original_image_path = params.get('vm_disk_image_path') + tar_image_folder = os.path.dirname(original_image_path) + untar_image_path = os.path.join(tar_image_folder, "disk.raw") + LOG.debug(f"untar image.tgz to gce output is : {tar_image_folder}") + + tar_cmd = f"tar -xvzf {original_image_path} -C {tar_image_folder}" + process.run(tar_cmd, shell=True, verbose=True, ignore_status=False) + return untar_image_path + + +def check_bootc_image_version_id(params): + """ + check bootc image version id + + @param params: one dictionary wrapping various parameter + """ + expected_redhat_version_id = params.get("redhat_version_id") + if expected_redhat_version_id is None: + LOG.debug("don't need to check redhat version id") + else: + bootc_meta_info_dict = get_bootc_image_meta_info(params) + redhat_version_id = bootc_meta_info_dict.get("redhat.version-id") + compose_id = bootc_meta_info_dict.get("redhat.compose-id") + expected_compose_id = "RHEL-{}".format(expected_redhat_version_id) + if "-beta" in expected_compose_id: + expected_compose_id = expected_compose_id[0:expected_compose_id.index("-beta")] + if expected_redhat_version_id != redhat_version_id: + raise exceptions.TestFail(f"Expected redhat version id :{expected_redhat_version_id}, real version id is: {redhat_version_id}") + if expected_compose_id not in compose_id: + raise exceptions.TestFail(f"Expected compose id :{expected_compose_id}, real compose id is: {compose_id}") + + +def get_bootc_image_meta_info(params): + """ + get bootc image meta information + + @param params: one dictionary wrapping various parameter + """ + container_url = params.get('container_url') + cmd = "sudo skopeo inspect --retry-times=5 --tls-verify=false docker://%s |jq -r '.Labels'" % container_url + ret = process.run(cmd, timeout=40, verbose=True, ignore_status=True, shell=True).stdout_text + LOG.debug(f"skopeo inspect bootc image output is : {ret}") + + bootc_meta_info_dict = eval(ret) + return bootc_meta_info_dict + + +def create_registry_policy_file(params): + """ + create registry policy file + + @param params: one dictionary wrapping various parameter + """ + base_dir = params.get("config_file_path") + policy_file = os.path.join(base_dir, "policy.json") + pub_key_file = os.path.join(base_dir, "key.gpg") + local_registry = "localhost:5000" + + registry_policy = { + "default": [{"type": "insecureAcceptAnything"}], + "transports": { + "docker": { + f"{local_registry}": [ + { + "type": "signedBy", + "keyType": "GPGKeys", + "keyPath": f"{pub_key_file}" + } + ] + }, + "docker-daemon": { + "": [{"type": "insecureAcceptAnything"}] + } + } + } + + with open(policy_file, mode="w", encoding="utf-8") as f: + f.write(json.dumps(registry_policy)) + + +def create_lookaside_config_file(params): + """ + create look aside config file + + @param params: one dictionary wrapping various parameter + """ + base_dir = params.get("config_file_path") + lookaside_file = os.path.join(base_dir, "bib_lookaside.yaml") + lookaside_file_config = """ + docker: + localhost:5000: + lookaside: file:///var/lib/containers/sigstore + """ + with open(lookaside_file, mode="w", encoding="utf-8") as f: + f.write(lookaside_file_config) + + +def gpg_gen_key(params): + """ + generate gpg key + + @param params: one dictionary wrapping various parameter + """ + base_dir = params.get("config_file_path") + home_dir = f"{base_dir}/.gnupg" + pub_key_file = os.path.join(base_dir, "key.gpg") + if os.path.exists(home_dir): + return + + os.makedirs(home_dir, mode=0o700, exist_ok=False) + key_params = """ + %no-protection + Key-Type: RSA + Key-Length: 3072 + Key-Usage: sign + Name-Real: Bootc Image Builder Test usage + Name-Email: bib_test@redhat.com + Expire-Date: 0 + """ + email = "bib_test@redhat.com" + + subprocess.run( + ["gpg", "--gen-key", "--batch"], + check=True, capture_output=True, + env={"GNUPGHOME": home_dir}, + input=key_params, + text=True) + + subprocess.run( + ["gpg", "--output", pub_key_file, + "--armor", "--export", email], + check=True, capture_output=True, + env={"GNUPGHOME": home_dir}) + + +def retag_container_image_to_local_registry(params): + """ + re-tag the image to point it to our local registry + + @param params: one dictionary wrapping various parameter + """ + container_url = params.get('container_url') + pull_image_cmd = f"podman pull {container_url}" + process.run(pull_image_cmd, timeout=600, verbose=True, ignore_status=False, shell=True) + + index = container_url.index(":") + 1 + image_name = container_url[index:] + + delete_img_cmd = f"podman rmi localhost:5000/{image_name} -f " + process.run(delete_img_cmd, timeout=60, verbose=True, ignore_status=True, shell=True) + + cmd = f"podman tag {container_url} localhost:5000/{image_name}" + ret = process.run(cmd, timeout=40, verbose=True, ignore_status=False, shell=True).stdout_text + + list_image = "podman images localhost:5000/{image_name}" + ret = process.run(cmd, timeout=40, verbose=True, ignore_status=True, shell=True).stdout_text + LOG.debug(f"pomdman list image output is : {ret}") + return f"localhost:5000/{image_name}" + + +def ensure_registry(params): + """ + ensure registry is running + + @param params: one dictionary wrapping various parameter + """ + registry_container_name = subprocess.run([ + "podman", "ps", "-a", "--filter", "name=registry", "--format", "{{.Names}}" + ], check=True, capture_output=True).stdout.decode("utf-8").strip() + + if registry_container_name != "registry": + subprocess.run([ + "podman", "run", "-d", "-p", "5000:5000", "--restart", "always", "--name", "registry", "registry:2" + ], check=True, capture_output=True) + + registry_container_state = subprocess.run([ + "podman", "ps", "-a", "--filter", "name=registry", "--format", "{{.State}}" + ], check=True, capture_output=True).stdout.decode("utf-8").strip() + + if registry_container_state in ("paused", "exited"): + subprocess.run([ + "podman", "start", "registry" + ], check=True, capture_output=True) + time.sleep(20) + cmd = "podman ps" + output = process.run(cmd, timeout=40, verbose=True, ignore_status=True, shell=True).stdout_text + LOG.debug(f"pomdman list running container output is : {output}") + + +def sign_image(params): + """ + sign container image + + @param params: one dictionary wrapping various parameter + """ + gpg_gen_key(params) + ensure_registry(params) + local_registry_url = retag_container_image_to_local_registry(params) + create_registry_policy_file(params) + create_lookaside_config_file(params) + base_dir = params.get("config_file_path") + home_dir = f"{base_dir}/.gnupg" + email = "bib_test@redhat.com" + base_dir = params.get("config_file_path") + lookaside_file = os.path.join(base_dir, "bib_lookaside.yaml") + system_lookaside_conf_file = os.path.join( + "/etc/containers/registries.d", + os.path.basename(lookaside_file) + ) + shutil.copy(lookaside_file, system_lookaside_conf_file) + + subprocess.run([ + "podman", "push", + "--tls-verify=false", + "--sign-by", email, + f"{local_registry_url}", + ], check=True, capture_output=True, env={"GNUPGHOME": home_dir}) + os.unlink(system_lookaside_conf_file) + return local_registry_url + + +def get_baseurl_from_repo_file(repo_file_path): + """ + One method to get compose url from current repository file + + :param repo_file_path: file path to repository + """ + try: + with open(repo_file_path, 'r') as f: + for line in f: + line = line.strip() + if line.startswith("baseurl"): + baseurl = line.split("=")[1].strip() + return baseurl.split('/compose/')[0].strip() + return None + except FileNotFoundError: + return None diff --git a/provider/cpu.py b/provider/cpu.py new file mode 100644 index 00000000000..847b3a034fa --- /dev/null +++ b/provider/cpu.py @@ -0,0 +1,28 @@ +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Copyright Red Hat +# +# SPDX-License-Identifier: GPL-2.0 +# +# Author: smitterl@redhat.com +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +import platform + + +def patch_total_cpu_count_s390x(cpu_module): + """ + On s390x, override the avocado utility functions because on an + LPAR they would return the number of CPUs available on the CEC + but not on the LPAR. + + :param cpu_module: the module after import in calling script + """ + + if platform.machine() == "s390x": + online_before_test = cpu_module.online_count() + + def _online_before_test(): + return online_before_test + cpu_module.total_cpus_count = _online_before_test + cpu_module.total_count = _online_before_test diff --git a/provider/gpu/__init__.py b/provider/gpu/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/provider/gpu/gpu_base.py b/provider/gpu/gpu_base.py new file mode 100644 index 00000000000..2cbfbe66045 --- /dev/null +++ b/provider/gpu/gpu_base.py @@ -0,0 +1,235 @@ +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Copyright Red Hat +# +# SPDX-License-Identifier: GPL-2.0 +# +# Author: yicui@redhat.com +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +import logging +import re +import os +import platform +import requests + +from avocado.core import exceptions +from avocado.utils import process + +from virttest import libvirt_version +from virttest import utils_misc +from virttest import utils_package +from virttest import utils_sriov +from virttest import virsh + +from virttest.libvirt_xml import vm_xml +from virttest.utils_libvirt import libvirt_vmxml +from virttest.utils_test import libvirt + +LOG = logging.getLogger("avocado." + __name__) + + +def get_gpus_info(session=None): + """ + Get GPUs information + + :param session: The session object to the host + :raise: exceptions.TestError when command fails + :return: dict, GPUs' info. + eg. {'3b:00.0': {'driver': 'ixgbe', 'pci_id': '0000:3b:00.0', + 'iface': 'ens1f0', 'status': 'up'}, + '3b:00.1': {'driver': 'ixgbe', 'pci_id': '0000:3b:00.1', + 'iface': 'ens1f1', 'status': 'down'}} + + """ + dev_info = {} + status, output = utils_misc.cmd_status_output( + "lspci -D -nn|awk '/3D controller/'", + shell=True, session=session + ) + if status or not output: + raise exceptions.TestError( + "Unable to get 3D controllers. status: %s," + "stdout: %s." % (status, output) + ) + pattern = r'(\S+:\S+:\S+.\d+)\s.*\s\[(\w+:\w+)\]' + matches = re.findall(pattern, output) + for match in matches: + dev_info[match[0]] = {"pci_id": match[0], "ID": re.sub(":", " ", match[1])} + + for pci in dev_info.keys(): + _, output = utils_misc.cmd_status_output( + "lspci -v -s %s" % pci, shell=True, session=session + ) + driver_in_use = re.search("driver in use: (.*)", output) + if driver_in_use: + dev_info[pci].update({"driver": driver_in_use[1]}) + + LOG.debug(f"GPU info: {dev_info}.") + return dev_info + + +def get_gpu_pci(session=None): + """ + Get the pci id of the first available GPU. + + :param session: The session object to the host + :return: pci id of GPU, eg. 0000:01:00.0 + """ + return list(get_gpus_info(session=session).values())[0].get("pci_id") + + +def pci_to_addr(pci_id): + """ + Get address dict according to pci_id + + :param pci_id: PCI ID of a device(eg. 0000:05:10.1) + :return: address dict + """ + pci_list = ["0x%s" % x for x in re.split("[.:]", pci_id)] + return dict(zip(["domain", "bus", "slot", "function"], pci_list + ["pci"])) + + +class GPUTest(object): + """ + Wrapper class for GPU testing + """ + def __init__(self, vm, test, params, session=None): + self.vm = vm + self.test = test + self.params = params + self.session = session + self.remote_virsh_dargs = None + + libvirt_version.is_libvirt_feature_supported(self.params) + self.gpu_pci = get_gpu_pci(session=self.session) + if not self.gpu_pci: + test.cancel("NO available gpu found.") + self.gpu_pci_addr = pci_to_addr(self.gpu_pci) + self.gpu_dev_name = utils_sriov.get_device_name(self.gpu_pci) + + new_xml = vm_xml.VMXML.new_from_inactive_dumpxml(self.vm.name) + self.orig_config_xml = new_xml.copy() + + def parse_hostdev_dict(self): + """ + Parse hostdev_dict from params + + :return: The updated iface_dict + """ + gpu_pci_addr = self.gpu_pci_addr + hostdev_dict = eval(self.params.get('hostdev_dict', '{}')) + return hostdev_dict + + def check_gpu_dev(self, vm, status_error=False): + """ + Check GPU device in guest + + :param vm: vm object + :param status_error: True if expect not existing, otherwise False + """ + vm_session = vm.wait_for_login(timeout=240) + s, o = vm_session.cmd_status_output("lspci |grep 3D") + vm_session.close() + result = process.CmdResult(stdout=o, exit_status=s) + libvirt.check_exit_status(result, status_error) + + def nvidia_smi_check(self, vm_session): + """ + Run nvidia-smi command and check GPU device's info + + :param vm_session: vm's session + """ + gpu_pci = get_gpu_pci(session=vm_session) + s, o = vm_session.cmd_status_output("nvidia-smi -q") + if s or not re.search(gpu_pci, o): + self.test.fail("Failed to run nvidia-smi command. Status: %s, output: %s." + % (s, o)) + + def install_latest_driver(self, vm_session, local_rpm=False): + """ + Install the latest data centre driver + + :param vm_session: vm session object + :local_rpm: Install the driver using local rpm + """ + pkgs = ["gcc", "kernel*headers*", "kernel*devel*"] + if not utils_package.package_install(pkgs, vm_session): + self.test.error(f"Unable to install {pkgs} in guest!") + arch = platform.machine() + if local_rpm: + url = "https://developer.nvidia.com/datacenter-driver-downloads" + page = requests.Session().get(url) + pkg_download_cmd = re.findall(rf"(wget https://developer.download.nvidia.com/compute/nvidia-driver/\S+/local_installers/nvidia-driver-local-repo-rhel9-\S+{arch}.rpm)", page.text) + if not pkg_download_cmd: + self.test.error("Unable to get download command!") + pkg_name = os.path.basename(pkg_download_cmd[0]) + vm_session.cmd(pkg_download_cmd[0], timeout=240) + vm_session.cmd(f"rpm -i {pkg_name}", timeout=120) + else: + # TODO: Get distro from guest. epel repo should be covered in ci + distro = "rhel9" + pkg_mgr = utils_package.package_manager(vm_session, "epel-release") + if not pkg_mgr.is_installed("epel-release"): + vm_session.cmd_output_safe(f"subscription-manager repos --enable=rhel-9-for-{arch}-appstream-rpms") + vm_session.cmd_output_safe(f"subscription-manager repos --enable=rhel-9-for-{arch}-baseos-rpms") + vm_session.cmd_output_safe(f"subscription-manager repos --enable=codeready-builder-for-rhel-9-{arch}-rpms") + vm_session.cmd_output_safe("dnf -y install https://dl.fedoraproject.org/pub/epel/epel-release-latest-9.noarch.rpm", timeout=600) + + if vm_session.cmd_status(f"ls /etc/yum.repos.d/cuda-{distro}.repo"): + repo_url = f"https://developer.download.nvidia.com/compute/cuda/repos/{distro}/sbsa/cuda-{distro}.repo" + vm_session.cmd(f"dnf config-manager --add-repo {repo_url}") + vm_session.cmd(f"sed -i 's/^gpgcheck=1/gpgcheck=0/' /etc/yum.repos.d/cuda-{distro}.repo") + vm_session.cmd("dnf clean all") + vm_session.cmd("dnf -y module install nvidia-driver:open-dkms --skip-broken", timeout=600) + + def install_cuda_toolkit(self, vm_session, runfile=False): + """ + Install cuda toolkit + :param vm_session: vm session object + :runfile: Install the cuda toolkit using runfile + """ + if runfile: + url = "https://developer.nvidia.com/cuda-downloads" + page = requests.Session().get(url) + pkg_download_cmd = re.findall(r"(wget https://developer.download.nvidia.com/compute/cuda/\S+/local_installers/cuda_\S+_linux_sbsa.run)", page.text) + if not pkg_download_cmd: + self.test.error("Unable to get download command!") + pkg_name = os.path.basename(pkg_download_cmd[0]) + vm_session.cmd(pkg_download_cmd[0], timeout=240) + vm_session.cmd(f"sh {pkg_name} --silent", timeout=600) + else: + pkgs = "cuda-toolkit" + if not utils_package.package_install(pkgs, vm_session): + self.test.fail(f"Unable to install {pkgs} in guest!") + + def setup_default(self, **dargs): + """ + Default setup + + :param dargs: test keywords + """ + dev_name = dargs.get('dev_name') + managed_disabled = dargs.get('managed_disabled', False) + + self.test.log.debug("Removing the existing hostdev device...") + libvirt_vmxml.remove_vm_devices_by_type(self.vm, 'hostdev') + + if managed_disabled: + virsh.nodedev_detach(dev_name, debug=True, ignore_status=False) + + def teardown_default(self, **dargs): + """ + Default cleanup + + :param dargs: test keywords + """ + dev_name = dargs.get('dev_name') + managed_disabled = dargs.get('managed_disabled', False) + self.test.log.info("TEST_TEARDOWN: Recover test environment.") + if self.vm.is_alive(): + self.vm.destroy(gracefully=False) + self.orig_config_xml.sync() + + if managed_disabled: + virsh.nodedev_reattach(dev_name, debug=True, ignore_status=False) diff --git a/provider/guest_os_booting/guest_os_booting_base.py b/provider/guest_os_booting/guest_os_booting_base.py index 0e70009febd..9e637c2727d 100644 --- a/provider/guest_os_booting/guest_os_booting_base.py +++ b/provider/guest_os_booting/guest_os_booting_base.py @@ -1,7 +1,10 @@ import logging +import platform from avocado.core import exceptions from avocado.utils import distro +from avocado.utils import download +from avocado.utils import process from virttest import virsh from virttest.libvirt_xml import vm_xml @@ -22,11 +25,21 @@ def get_vm(params): vms = params.get('vms').split() firmware_type = params.get('firmware_type') detected_distro = distro.detect() - os_type_dict = { - ('ovmf' if any([vm_xml.VMXML.new_from_dumpxml(v).os.fetch_attrs(). - get('os_firmware') == "efi", vm_xml.VMXML. - new_from_dumpxml(v).os.fetch_attrs().get('nvram')]) - else 'seabios'): v for v in vms} + os_type_dict = {} + if platform.machine() == "s390x": + return vms[0] + + for _vm in vms: + if os_type_dict.get("seabios") and os_type_dict.get("ovmf"): + break + vm_os_attrs = vm_xml.VMXML.new_from_dumpxml(_vm).os.fetch_attrs() + is_ovmf = any([vm_os_attrs.get('os_firmware') == "efi", vm_os_attrs.get('nvram')]) + if is_ovmf: + if not os_type_dict.get("ovmf"): + os_type_dict["ovmf"] = _vm + elif not os_type_dict.get("seabios"): + os_type_dict["seabios"] = _vm + LOG.debug(f"VMS: {os_type_dict}") if not firmware_type: LOG.debug("Get default vm") if detected_distro.name == 'rhel': @@ -95,3 +108,14 @@ def check_vm_startup(vm, vm_name, error_msg=None): vm.wait_for_login().close() LOG.debug("Succeed to boot %s", vm_name) return vmxml + + +def test_file_download(url, path): + """ + Returns true if the file could be successfully downloaded + + :param url: source URL + :param path: destination path + """ + download.get_file(url, path) + return process.run('ls -d ' + path, ignore_status="yes").exit_status == 0 diff --git a/provider/interface/interface_base.py b/provider/interface/interface_base.py index f632e802aea..3aa12e76662 100644 --- a/provider/interface/interface_base.py +++ b/provider/interface/interface_base.py @@ -47,17 +47,23 @@ def create_hostdev(hostdev_dict): return hostdev_dev -def get_vm_iface(vm_session): +def get_vm_iface(vm_session, ignore_status=False): """ Get VM's 1st interface :param vm_session: An session to VM + :param ignore_status: Whether to raise an exception if there is no interface :return: VM's first interface """ - p_iface, _v_ifc = utils_net.get_remote_host_net_ifs(vm_session) + p_iface, _v_ifc = utils_net.get_remote_host_net_ifs( + vm_session, ip_options='-color=never') vm_iface = p_iface[:1:] if not vm_iface: - raise exceptions.TestFail("Failed to get vm's iface!") + if ignore_status: + logging.debug("There is no interface in VM!") + return + else: + raise exceptions.TestFail("Failed to get vm's iface!") return vm_iface[0] diff --git a/provider/interface/vdpa_base.py b/provider/interface/vdpa_base.py index d2463ac0e46..4ceeb6b367c 100644 --- a/provider/interface/vdpa_base.py +++ b/provider/interface/vdpa_base.py @@ -143,7 +143,7 @@ def get_multiplier(vm_session, pci_id): :return: The multiplier of VM's interface """ cmd = "lspci -vvv -s %s | awk -F '=' '/multiplier=/ {print $NF}'" % pci_id - act_mul = vm_session.cmd_output(cmd).strip() + act_mul = vm_session.cmd_output(cmd).splitlines()[-1] LOG.debug("Actual multiplier: %s", act_mul) return act_mul diff --git a/provider/libvirtd/libvirtd_base.py b/provider/libvirtd/libvirtd_base.py new file mode 100644 index 00000000000..3850930dc49 --- /dev/null +++ b/provider/libvirtd/libvirtd_base.py @@ -0,0 +1,54 @@ + +import logging + +from avocado.core import exceptions +from virttest import virsh +from virttest.staging import service + +LOG = logging.getLogger('avocado.' + __name__) + + +def check_service_status(service_name, expect_active=None, + expect_enabled=None): + """ + Check status of service + + :param service_name: name of service to be checked + :param expect_active: expect service status, True if active, + False if inactive, defaults to None + :param expect_enabled: expect service enablement, True if enabled + False if disenabled, defaults to None + """ + LOG.info(f'Check service status of {service_name}') + srvc = service.Factory.create_service(service_name) + LOG.debug(f'Service [{service_name}] status is ' + f'{"active" if srvc.status() else "inactive"}.\n' + f'Service [{service_name}] is ' + f'{"enabled" if srvc.is_enabled() else "disabled"}') + if expect_active is not None: + if srvc.status() == expect_active: + LOG.info(f'Service status check PASSED') + else: + raise exceptions.TestFail(f'Expect service [{service_name}] to be ' + f'{"active" if expect_active else "inactive"}') + if expect_enabled is not None: + if srvc.is_enabled() is expect_enabled: + LOG.info(f'Service enable check PASSED') + else: + raise exceptions.TestFail(f'Expect service [{service_name}] to be ' + f'{"enabled" if expect_enabled else "disabled"}') + + +def check_virsh_connection(msg): + """ + Check virsh connection by running virsh list + + :param msg: message to display + """ + LOG.info(f'Check virsh connection {msg}') + conn_result = virsh.dom_list(debug=True) + if conn_result.exit_status == 0: + LOG.info(f'Virsh connection check {msg} PASSED') + else: + raise exceptions.TestFail(f'Virsh connection {msg} FAILED:\n' + f'{conn_result.stderr_text}') diff --git a/provider/memory/memory_base.py b/provider/memory/memory_base.py index 2d3592826c6..68d5c47ceed 100644 --- a/provider/memory/memory_base.py +++ b/provider/memory/memory_base.py @@ -1,12 +1,26 @@ import re +import platform from avocado.core import exceptions +from avocado.utils import cpu +from avocado.utils import memory as avocado_mem + +from virttest import virsh +from virttest import libvirt_version +from virttest import utils_misc +from virttest.libvirt_xml.devices import memory +from virttest.libvirt_xml import vm_xml +from virttest.utils_test import libvirt +from virttest.utils_version import VersionInterval +from virttest.utils_libvirt import libvirt_vmxml +from virttest.utils_libvirt import libvirt_misc + +virsh_dargs = {"ignore_status": False, "debug": True} def convert_data_size(current_size, dest_unit="KiB"): """ Convert source value to expected value - :param current_size: current size str, eg: 1024MB :param dest_unit: dest size unit, eg: KiB, MiB :return: dest_size: The size is converted, eg: 1(the dest unit is given, @@ -47,3 +61,212 @@ def convert_data_size(current_size, dest_unit="KiB"): if isinstance(dest_size, float): return dest_size return int(dest_size) + + +def check_supported_version(params, test, vm): + """ + Check the supported version + + :param params: Dictionary with the test parameters + :param test: Test object + :param vm: Vm object + """ + guest_required_kernel = params.get('guest_required_kernel') + libvirt_version.is_libvirt_feature_supported(params) + utils_misc.is_qemu_function_supported(params) + if not guest_required_kernel: + return + + if not vm.is_alive(): + vm.start() + vm_session = vm.wait_for_login() + vm_kerv = vm_session.cmd_output('uname -r').strip().split('-')[0] + vm_session.close() + 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 + + +def create_file_within_nvdimm_disk(test, vm_session, test_device, test_file, + mount_point, error_msg="", test_str="test_text", + block_size=4096): + """ + Create a test file in the nvdimm file disk + + :param test: test object + :param vm_session: VM session + :param test_device: str, device value + :param test_file: str, file name to be used + :param mount_point: mount point path. + :param error_msg: Error msg content when useing mkfs cmd + :param test_str: str to be written into the nvdimm file disk + :param block_size: int, block size for mkfs.xfs -b + """ + # Create a file system + bsize_str = '-b size={}'.format(block_size) if block_size != 0 else '' + if any(platform.platform().find(ver) for ver in ('el8', 'el9')): + cmd = 'mkfs.xfs -f {} {} -m reflink=0'.format(test_device, bsize_str) + else: + cmd = 'mkfs.xfs -f {} {}'.format(test_device, bsize_str) + + vm_session.cmd("mkdir -p %s" % mount_point) + output = vm_session.cmd_output(cmd) + if error_msg: + if error_msg not in output: + test.fail("Expect to get '%s' in '%s'" % (error_msg, output)) + else: + return + test.log.debug("Command '%s' output:%s", cmd, output) + + # Mount the file system + uuid = re.findall( + r' UUID="(\S+)"', vm_session.cmd_output('blkid %s' % test_device))[0] + vm_session.cmd_status_output('mount -o dax -U {} {}'.format(uuid, mount_point)) + + cmd = 'echo \"%s\" >%s' % (test_str, test_file) + vm_session.cmd(cmd) + vm_session.cmd_output('umount %s' % mount_point) + + +def adjust_memory_size(params): + """ + Adjust the memory device size for different arch hugepage size + + :param params: a dict for parameters + eg: In arm, we need to consider: + 2M on 4k kernel package. + 512M on 64k kernel package. + """ + default_pagesize_KiB = avocado_mem.get_huge_page_size() + + if cpu.get_arch().startswith("aarch"): + params.update({'block_size': default_pagesize_KiB}) + params.update({'request_size': default_pagesize_KiB}) + params.update({'target_size': default_pagesize_KiB*2}) + + +def define_guest_with_memory_device(params, mem_attr_list, vm_attrs=None): + """ + Define guest with specified memory device. + + :param params: a dict for parameters. + :param mem_attr_list: memory device attributes list. + :param vm_attrs: basic vm attributes to define. + """ + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(params.get("main_vm")) + if vm_attrs: + vmxml.setup_attrs(**vm_attrs) + + if not isinstance(mem_attr_list, list): + mem_attr_list = [mem_attr_list] + for mem in mem_attr_list: + memory_object = libvirt_vmxml.create_vm_device_by_type('memory', mem) + vmxml.devices = vmxml.devices.append(memory_object) + vmxml.sync() + + +def plug_memory_and_check_result(test, params, mem_dict, operation='attach', + expected_error='', expected_event='', + alias='', **kwargs): + """ + Hot plug or hot unplug memory and check event. + + :param test: test object. + :param params: dictionary with the test parameters. + :param mem_dict: the memory dict to plug. + :param operation: the operation of plug or unplug. + :param expected_error: expected error after plug or unplug. + :param expected_event: expected event for plug or unplug. + :param alias: the plugged device alias + """ + vm_name = params.get('main_vm') + plug_mem = libvirt_vmxml.create_vm_device_by_type('memory', mem_dict) + + wait_event = True if expected_event else False + if operation == "attach": + res = virsh.attach_device(vm_name, plug_mem.xml, wait_for_event=wait_event, + event_type=expected_event, debug=True, **kwargs) + elif operation == "detach": + res = virsh.detach_device(vm_name, plug_mem.xml, wait_for_event=wait_event, + event_type=expected_event, debug=True, **kwargs) + elif operation == "detach_alias": + res = virsh.detach_device_alias( + vm_name, alias=alias, wait_for_event=wait_event, + event_type=expected_event, debug=True, **kwargs) + + if expected_error: + libvirt.check_result(res, expected_fails=expected_error) + else: + libvirt.check_exit_status(res) + + +def check_dominfo(vm, test, expected_max, expected_used): + """ + Check Max memory value and Used memory in virsh dominfo result. + + :param vm: vm object. + :param test: test object. + :param params: dictionary with the test parameters. + :param expected_max: expected Max memory in virsh dominfo. + :param expected_used: expected Used memory in virsh dominfo. + """ + result = virsh.dominfo(vm.name, **virsh_dargs).stdout_text.strip() + + dominfo_dict = libvirt_misc.convert_to_dict( + result, pattern=r'(\S+ \S+):\s+(\S+)') + if dominfo_dict["Max memory"] != expected_max: + test.fail("Memory value should be %s " % expected_max) + if dominfo_dict["Used memory"] != expected_used: + test.fail("Current memory should be %s " % expected_used) + test.log.debug("Check virsh dominfo successfully.") + + +def check_mem_page_sizes(test, pg_size=None, hp_size=None, hp_list=None): + """ + Check host is suitable for various memory page sizes + + :param test: test object + :param pg_size: int, default memory page size in KiB unit + :param hp_size: int, default memory huge page size in KiB unit + :param hp_list: list, huge page size int list in KiB unit + """ + default_page_size = avocado_mem.get_page_size() / 1024 + if pg_size and pg_size != default_page_size: + test.cancel("Expected host default page size is %s KiB, but get %s KiB" % + (pg_size, default_page_size)) + default_huge_page_size = avocado_mem.get_huge_page_size() + if hp_size and hp_size != default_huge_page_size: + test.cancel("Expected host default huge page size is %s KiB, but get %s KiB" % + (hp_size, default_huge_page_size)) + supported_hp_size_list = avocado_mem.get_supported_huge_pages_size() + if hp_list and not set(hp_list).issubset(set(supported_hp_size_list)): + test.cancel("Expected huge page size list is %s, but get %s" % + (hp_list, supported_hp_size_list)) + + +def compare_values(test, expected, actual, check_item=''): + """ + Compare two values are the same. + + :params test, test object. + :params expected, expected value. + :params actual, actual value. + :params check_item, the item to be checked. + """ + if expected != actual: + test.fail("Expect %s to get '%s' instead of '%s' " % ( + check_item, expected, actual)) + else: + test.log.debug("Check %s %s PASS", check_item, actual) diff --git a/provider/migration/base_steps.py b/provider/migration/base_steps.py index 661ce6c59c0..f2219c7aaa1 100644 --- a/provider/migration/base_steps.py +++ b/provider/migration/base_steps.py @@ -1,4 +1,5 @@ import os +import platform import time from six import itervalues @@ -13,6 +14,7 @@ from virttest import utils_libvirtd from virttest import utils_iptables from virttest import utils_misc +from virttest import virsh from virttest.utils_libvirt import libvirt_disk from virttest.utils_libvirt import libvirt_vmxml @@ -47,6 +49,8 @@ def __init__(self, test, vm, params): self.src_full_uri = libvirt_vm.complete_uri( self.params.get("migrate_source_host")) self.conn_list = [] + self.check_cont_ping = "yes" == self.params.get("check_cont_ping", "no") + self.check_cont_ping_log = self.params.get("check_cont_ping_log", "/tmp/log_file") self.remote_libvirtd_log = None migration_test = migration.MigrationTest() @@ -89,6 +93,11 @@ def setup_default(self): if start_vm == "yes" and not self.vm.is_alive(): self.vm.start() self.vm.wait_for_login().close() + if self.check_cont_ping: + self.test.log.debug("Starting ping command to check network during migration...") + vm_session = self.vm.wait_for_login() + ping_cmd = "ping 8.8.8.8 > %s 2>&1 &" % self.check_cont_ping_log + vm_session.sendline(ping_cmd) def run_migration(self): """ @@ -171,7 +180,7 @@ def run_migration(self): do_mig_param = {"vm": self.vm, "mig_test": self.migration_test, "src_uri": None, "dest_uri": dest_uri, "options": options, "virsh_options": virsh_options, "extra": extra, "action_during_mig": action_during_mig, "extra_args": extra_args} - migration_base.do_migration(do_mig_param) + migration_base.do_migration(**do_mig_param) def run_migration_again(self): """ @@ -222,12 +231,15 @@ def run_migration_again(self): do_mig_param = {"vm": self.vm, "mig_test": self.migration_test, "src_uri": None, "dest_uri": dest_uri, "options": options, "virsh_options": virsh_options, "extra": extra, "action_during_mig": action_during_mig, "extra_args": extra_args} - migration_base.do_migration(do_mig_param) + migration_base.do_migration(**do_mig_param) def run_migration_back(self): """ Execute migration from target host to source host """ + migrate_vm_back = "yes" == self.params.get("migrate_vm_back", "yes") + if not migrate_vm_back: + return virsh_options = self.params.get("virsh_options", "") extra = self.params.get("virsh_migrate_extra") options = self.params.get("virsh_migrate_options", "--live --verbose") @@ -267,6 +279,28 @@ def run_migration_back(self): % (cmd, cmd_result)) self.vm.connect_uri = self.src_uri + def check_vm_cont_ping(self, check_on_dest=True): + """ + Check continuous ping command in VM + + :param check_on_dest: Check whether on the destination machine + """ + dest_uri = self.params.get("virsh_migrate_desturi") + if self.check_cont_ping: + self.test.log.debug("Checking the output of %s", self.check_cont_ping_log) + if check_on_dest: + backup_uri, self.vm.connect_uri = self.vm.connect_uri, dest_uri + self.vm.cleanup_serial_console() + self.vm.create_serial_console() + vm_session = self.vm.wait_for_serial_login(timeout=360) + vm_session.cmd( + "> {0}; sleep 5; grep time= {0}".format(self.check_cont_ping_log)) + o = vm_session.cmd_output(f"cat {self.check_cont_ping_log}") + self.test.log.debug(f"ping command output: {o}") + vm_session.close() + if check_on_dest: + self.vm.connect_uri = backup_uri + def verify_default(self): """ Verify steps by default @@ -281,6 +315,7 @@ def verify_default(self): if int(self.migration_test.ret.exit_status) == 0: self.migration_test.post_migration_check([self.vm], self.params, dest_uri=dest_uri, src_uri=self.src_uri) + self.check_vm_cont_ping(check_on_dest=True) self.check_local_and_remote_log() def cleanup_default(self): @@ -343,9 +378,9 @@ def set_remote_log(self): log_level = self.params.get("libvirtd_debug_level") log_file = self.params.get("libvirtd_debug_file") log_filters = self.params.get("libvirtd_debug_filters") - file_type = self.params.get("libvirtd_file_type") + remote_file_type = self.params.get("remote_file_type") - service_name = utils_libvirtd.Libvirtd(file_type).service_name + service_name = utils_libvirtd.Libvirtd(remote_file_type).service_name file_path = utils_config.get_conf_obj(service_name).conf_path self.test.log.debug("Config file path: %s" % file_path) cmd = "ls {0} || mkdir -p {0}".format(os.path.dirname(log_file)) @@ -364,25 +399,46 @@ def check_local_and_remote_log(self, local_str_in_log=True, remote_str_in_log=Tr :param remote_str_in_log: True if the remote file should include the given string, otherwise, False """ - check_str_local_log = eval(self.params.get("check_str_local_log", "[]")) - check_str_remote_log = self.params.get("check_str_remote_log", "") + try: + check_str_local_log = eval(self.params.get("check_str_local_log", "[]")) + check_no_str_local_log = eval(self.params.get("check_no_str_local_log", "[]")) + check_str_remote_log = eval(self.params.get("check_str_remote_log", "[]")) + check_no_str_remote_log = eval(self.params.get("check_no_str_remote_log", "[]")) + except Exception as e: + self.test.error(f"Wrong test configuration. Unable to eval one or more parameter(s): {str(e)}") log_file = self.params.get("libvirtd_debug_file") + runner_on_target = None + if check_str_local_log: for check_log in check_str_local_log: libvirt.check_logfile(check_log, log_file, str_in_log=local_str_in_log) - if check_str_remote_log: - runner_on_target = None + if check_no_str_local_log: + for check_log in check_no_str_local_log: + local_str_in_log = False + libvirt.check_logfile(check_log, log_file, str_in_log=local_str_in_log) + if check_str_remote_log or check_no_str_remote_log: server_ip = self.params.get("server_ip") server_user = self.params.get("server_user", "root") server_pwd = self.params.get("server_pwd") runner_on_target = remote.RemoteRunner(host=server_ip, username=server_user, password=server_pwd) - libvirt.check_logfile(check_str_remote_log, - log_file, - str_in_log=remote_str_in_log, - cmd_parms=self.params, - runner_on_target=runner_on_target) + + if check_str_remote_log: + for check_log in check_str_remote_log: + libvirt.check_logfile(check_log, + log_file, + str_in_log=remote_str_in_log, + cmd_parms=self.params, + runner_on_target=runner_on_target) + if check_no_str_remote_log: + remote_str_in_log = False + for check_log in check_no_str_remote_log: + libvirt.check_logfile(check_log, + log_file, + str_in_log=remote_str_in_log, + cmd_parms=self.params, + runner_on_target=runner_on_target) def remote_add_or_remove_port(self, port, add=True): """ @@ -475,3 +531,64 @@ def cleanup_disks_remote(params, vm): disk_path = disk.get("source") cmd = "rm -f %s" % disk_path remote.run_remote_cmd(cmd, params, ignore_status=False) + + +def sync_cpu_for_mig(params): + """ + Sync cpu xml for migration + + :param params: Dictionary with the test parameters + """ + dest_uri = params.get("virsh_migrate_desturi") + vm_name = params.get("main_vm") + + cpu_dest_xml = virsh.domcapabilities(uri=dest_uri) + cpu_src_xml = virsh.domcapabilities() + mig_cpu_xml = os.path.join(data_dir.get_tmp_dir(), "cpu_xml") + with open(mig_cpu_xml, 'w+') as fd: + fd.write(cpu_dest_xml.stdout.strip()) + fd.write(cpu_src_xml.stdout.strip()) + out = virsh.hypervisor_cpu_baseline(mig_cpu_xml, options="--migratable") + dom_xml = vm_xml.VMXML.new_from_dumpxml(vm_name) + cpuxml = vm_xml.VMCPUXML() + cpuxml.xml = out.stdout.strip() + dom_xml.cpu = cpuxml + dom_xml.sync() + + +def check_cpu_for_mig(params): + """ + Check cpu for migration + + :param params: Dictionary with the test parameters + :return: if the cpu on the source and target hosts are the same, return True + """ + dest_uri = params.get("virsh_migrate_desturi") + remote_ip = params.get("server_ip") + remote_user = params.get("server_user") + remote_pwd = params.get("server_pwd") + + # aarch64 only supports migration tests between hosts with the same CPU, so + # no need to check the CPU. + if platform.machine() == "aarch64": + return True + + cpu_src_xml = virsh.domcapabilities(debug=True).stdout_text.strip() + mig_src_xml = os.path.join(data_dir.get_tmp_dir(), "mig_src.xml") + with open(mig_src_xml, 'w+') as fd: + fd.write(cpu_src_xml) + + remote_session = remote.remote_login("ssh", remote_ip, "22", + remote_user, remote_pwd, + r'[$#%]') + utils_misc.make_dirs(os.path.dirname(mig_src_xml), remote_session) + remote_session.close() + remote.scp_to_remote(remote_ip, '22', remote_user, remote_pwd, mig_src_xml, + mig_src_xml, limit="", log_filename=None, timeout=60, + interface=None) + + ret = virsh.hypervisor_cpu_compare(xml_file=mig_src_xml, uri=dest_uri, debug=True).stdout_text.strip() + if "identical" in ret or "superset" in ret: + return True + else: + return False diff --git a/provider/migration/migration_base.py b/provider/migration/migration_base.py index 8e3c473edba..4e60a4645c6 100644 --- a/provider/migration/migration_base.py +++ b/provider/migration/migration_base.py @@ -15,6 +15,7 @@ from virttest.libvirt_xml import vm_xml from virttest.migration import MigrationTest +from virttest.utils_libvirt import libvirt_disk # pylint: disable=W0611 from virttest.utils_libvirt import libvirt_memory from virttest.utils_libvirt import libvirt_monitor from virttest.utils_libvirt import libvirt_network # pylint: disable=W0611 @@ -62,7 +63,7 @@ def parse_funcs(action_during_mig, test, params): "action_during_mig_again' is required") act_dict = {} func_param = one_action.get('func_param') - if func_param: + if func_param and isinstance(func_param, str): func_param = eval(func_param) act_dict.update({'func': eval(one_action.get('func')), @@ -71,6 +72,8 @@ def parse_funcs(action_during_mig, test, params): 'before_pause': one_action.get('before_pause'), 'need_sleep_time': one_action.get('need_sleep_time'), 'func_param': func_param}) + if one_action.get('wait_for_after_event_timeout'): + act_dict.update({'wait_for_after_event_timeout': one_action.get('wait_for_after_event_timeout')}) action_during_mig.append(act_dict) return action_during_mig else: @@ -78,24 +81,24 @@ def parse_funcs(action_during_mig, test, params): "function name and list are supported") -def do_migration(do_mig_param): +def do_migration(**kwargs): """ The wrapper function to call migration - :param do_mig_param: do migration parameters, dict, contains vm object, - MigrationTest object, source uri, target uri, migration - options, virsh options, extra options for migration, list - or single function to run during migration, arguments for test - """ - vm = do_mig_param['vm'] - mig_test = do_mig_param['mig_test'] - src_uri = do_mig_param['src_uri'] - dest_uri = do_mig_param['dest_uri'] - options = do_mig_param['options'] - virsh_options = do_mig_param['virsh_options'] - extra = do_mig_param['extra'] - action_during_mig = do_mig_param['action_during_mig'] - extra_args = do_mig_param['extra_args'] + :param kwargs: do migration parameters, dict, contains vm object, + MigrationTest object, source uri, target uri, migration + options, virsh options, extra options for migration, list + or single function to run during migration, arguments for test + """ + vm = kwargs.get('vm') + mig_test = kwargs.get('mig_test') + src_uri = kwargs.get('src_uri') + dest_uri = kwargs.get('dest_uri') + options = kwargs.get('options') + virsh_options = kwargs.get('virsh_options') + extra = kwargs.get('extra') + action_during_mig = kwargs.get('action_during_mig') + extra_args = kwargs.get('extra_args') vm_name = None if extra and "--dname" in extra: @@ -220,7 +223,7 @@ def check_output(output, expected_value_list, test): logging.debug("Actual output is %s", output) for item in expected_value_list: if not re.findall(item, output): - test.fail("Unalbe to find {}".format(item)) + test.fail("Unable to find {}".format(item)) def check_event_output(params, test, virsh_session=None, remote_virsh_session=None): @@ -290,6 +293,7 @@ def execute_statistics_command(params): """ vm_name = params.get("migrate_main_vm") disk_type = params.get("loop_disk_type") + loop_time = params.get("loop_time", "1") vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) if disk_type: @@ -298,18 +302,19 @@ def execute_statistics_command(params): disks = vmxml.get_disk_all_by_expr('device==disk') logging.debug("disks: %s", disks) debug_kargs = {'ignore_status': False, 'debug': True} - for disk in list(disks.values()): - if disk_type: - disk_source = disk.find('source').get('dev') - else: - disk_source = disk.find('source').get('file') - disk_target = disk.find('target').get('dev') - logging.debug("disk_source: %s", disk_source) - logging.debug("disk_target: %s", disk_target) - virsh.domblkstat(vm_name, disk_target, "", **debug_kargs) - virsh.domblkinfo(vm_name, disk_source, **debug_kargs) - virsh.domstats(vm_name, **debug_kargs) - virsh.dommemstat(vm_name, **debug_kargs) + for i in range(int(loop_time)): + for disk in list(disks.values()): + if disk_type: + disk_source = disk.find('source').get('dev') + else: + disk_source = disk.find('source').get('file') + disk_target = disk.find('target').get('dev') + logging.debug("disk_source: %s", disk_source) + logging.debug("disk_target: %s", disk_target) + virsh.domblkstat(vm_name, disk_target, "", **debug_kargs) + virsh.domblkinfo(vm_name, disk_source, **debug_kargs) + virsh.domstats(vm_name, **debug_kargs) + virsh.dommemstat(vm_name, **debug_kargs) def check_qemu_mem_lock_hard_limit(params): @@ -450,23 +455,23 @@ def set_bandwidth(params): virsh.migrate_getspeed(vm_name, debug=True) -def check_vm_status_during_mig(params): +def check_vm_status_during_mig(vm_name, dest_state=None, src_state=None, dest_uri=None, src_reason=None): """ Check vm status during migration - :param params: dict, get expected status of vm, vm name, destination uri, source uri and timeout value + :param vm_name: vm name + :param dest_state: expected status of vm on target host + :param src_state: expected status of vm on source host + :param dest_uri: destination uri + :param src_reason: expected reason of vm state on source host :raise: test fail when check vm status failed """ - vm_status_during_mig = params.get("vm_status_during_mig") - vm_name = params.get("migrate_main_vm") - dest_uri = params.get("virsh_migrate_desturi") - src_uri = params.get("virsh_migrate_connect_uri") - timeout_value = params.get("timeout_value") - if timeout_value: - time.sleep(int(timeout_value)) - for uri in [dest_uri, src_uri]: - if not libvirt.check_vm_state(vm_name, vm_status_during_mig, uri=uri): - raise exceptions.TestFail("VM status is not '%s' during migration on %s." % (vm_status_during_mig, uri)) + if dest_state: + if not libvirt.check_vm_state(vm_name, dest_state, uri=dest_uri): + raise exceptions.TestFail("VM status is not '%s' during migration on target." % dest_state) + if src_state: + if not libvirt.check_vm_state(vm_name, src_state, src_reason): + raise exceptions.TestFail("VM status is not '%s' during migration on source." % src_state) def check_vm_state(params): @@ -510,14 +515,18 @@ def do_common_check(params): second_bandwidth = params.get("second_bandwidth") migration_obj = params.get("migration_obj") vm_name = params.get("main_vm") + remote_ip = params.get("server_ip") + postcopy_options = params.get("postcopy_options") if migration_options == "postcopy_bandwidth" and second_bandwidth: libvirt_domjobinfo.check_domjobinfo(migration_obj.vm, params) # check job info when migration is in paused status - expected_domjobinfo = '{"src_items": {"str_items": {"Job type": "Unbounded", "Operation": "Outgoing migration"}}}' - params.update({"expected_domjobinfo": expected_domjobinfo}) - libvirt_monitor.check_domjobinfo_output(params) + expected_domjobinfo = {"src_items": {"str_items": {"Job type": "Unbounded", "Operation": "Outgoing migration"}}} + libvirt_monitor.check_domjobinfo_output(vm_name, + expected_domjobinfo=expected_domjobinfo, + postcopy_options=postcopy_options, + remote_ip=remote_ip) # check domain state with reason check_vm_state(params) @@ -564,7 +573,7 @@ def resume_migration_again(params): do_mig_param = {"vm": migration_obj.vm, "mig_test": migration_obj.migration_test, "src_uri": None, "dest_uri": dest_uri, "options": options, "virsh_options": virsh_options, "extra": extra_twice_during_mig, "action_during_mig": None, "extra_args": extra_args_twice_during_mig} - do_migration(do_mig_param) + do_migration(**do_mig_param) def check_event_before_unattended(params): @@ -702,18 +711,20 @@ def do_domjobabort(params): dest_uri = params.get("virsh_migrate_desturi") vm_name = params.get("main_vm") domjobabort_err_msg = params.get("domjobabort_err_msg") - postcopy_options = params.get("postcopy_options") + domjobabort_on_src = "yes" == params.get("domjobabort_on_src", "no") + domjobabort_options = params.get("domjobabort_options", "") - if postcopy_options: - ret = virsh.domjobabort(vm_name, option="--postcopy", debug=True, uri=dest_uri) + if domjobabort_on_src: + uri = None else: - ret = virsh.domjobabort(vm_name, debug=True, uri=dest_uri) + uri = dest_uri + ret = virsh.domjobabort(vm_name, options=domjobabort_options, debug=True, uri=uri) libvirt.check_result(ret, expected_fails=domjobabort_err_msg, check_both_on_error=True) -def get_vm_serial_session_on_dest(params): +def write_vm_disk_on_dest(params): """ - Get vm serial session on dest + Write vm's disk on dest :param params: dictionary with the test parameter, get dest uri and migration object """ @@ -724,5 +735,24 @@ def get_vm_serial_session_on_dest(params): migration_obj.vm.cleanup_serial_console() migration_obj.vm.create_serial_console() vm_session = migration_obj.vm.wait_for_serial_login(timeout=120) - params.update({"vm_session": vm_session}) + vm_session.cmd("while true; do echo 'do disk I/O error test' >> /tmp/disk_io_error_test; sleep 1; done &") + vm_session.close() migration_obj.vm.connect_uri = backup_uri + + +def check_resume(params): + """ + Check resume result + + :param params: dictionary with the test parameter, get vm name, dest uri + and error message. + """ + vm_name = params.get("main_vm") + desturi = params.get("virsh_migrate_desturi") + resume_err_msg_src = params.get("resume_err_msg_src") + resume_err_msg_target = params.get("resume_err_msg_target") + + ret = virsh.resume(vm_name, debug=True) + libvirt.check_result(ret, expected_fails=resume_err_msg_src, check_both_on_error=True) + ret = virsh.resume(vm_name, debug=True, uri=desturi) + libvirt.check_result(ret, expected_fails=resume_err_msg_target, check_both_on_error=True) diff --git a/provider/migration/migration_vtpm.py b/provider/migration/migration_vtpm.py new file mode 100644 index 00000000000..1d0dc517e35 --- /dev/null +++ b/provider/migration/migration_vtpm.py @@ -0,0 +1,153 @@ +import logging as log +import os + +from avocado.utils import process + +from virttest import remote +from virttest import utils_package +from virttest import virsh + +from virttest.libvirt_xml import vm_xml +from virttest.utils_libvirt import libvirt_secret +from virttest.utils_libvirt import libvirt_vmxml +from virttest.utils_test import libvirt + +from provider.migration import base_steps # pylint: disable=W0611 + +# Using as lower capital is not the best way to do, but this is just a +# workaround to avoid changing the entire file. +logging = log.getLogger('avocado.' + __name__) + + +def check_vtpm_func(params, vm, test, remote_host=False): + """ + Check vtpm function + + :param params: dict, test parameters + :param vm: VM object + :param test: test object + :param remote_host: True to check context on remote + """ + tpm_cmd = params.get("tpm_cmd") + dest_uri = params.get("virsh_migrate_desturi") + src_uri = params.get("virsh_migrate_connect_uri") + test.log.debug("Check vtpm func: %s (remote).", remote) + if remote_host: + if vm.serial_console is not None: + vm.cleanup_serial_console() + vm.connect_uri = dest_uri + if vm.serial_console is None: + vm.create_serial_console() + vm_session = vm.wait_for_serial_login(timeout=240) + if not utils_package.package_install("tpm2-tools", vm_session): + test.error("Failed to install tpm2-tools in vm") + cmd_result = vm_session.cmd_status(tpm_cmd) + vm_session.close() + if remote_host: + if vm.serial_console is not None: + vm.cleanup_serial_console() + vm.connect_uri = src_uri + if cmd_result: + test.fail("Fail to run '%s': %s." % (tpm_cmd, cmd_result)) + + +def setup_vtpm(params, test, vm): + """ + Setup vTPM device in guest xml + + :param params: dict, test parameters + :param vm: VM object + :param test: test object + """ + vm_name = params.get("migrate_main_vm") + tpm_dict = eval(params.get('tpm_dict', '{}')) + auth_sec_dict = params.get("auth_sec_dict") + + test.log.info("Setup vTPM device in guest xml.") + if vm.is_alive(): + vm.destroy(gracefully=False) + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + # Remove all existing tpm devices + vmxml.remove_all_device_by_type('tpm') + + tpm_dict['backend']['encryption_secret'] = auth_sec_dict['sec_uuid'] + libvirt_vmxml.modify_vm_device(vmxml, 'tpm', tpm_dict) + + vm.start() + vm.wait_for_login().close() + + +def set_secret(params): + """ + Set secret + + :param params: dict, test parameters + """ + auth_sec_dict = eval(params.get("auth_sec_dict")) + src_secret_value = params.get("src_secret_value") + src_secret_value_path = params.get("src_secret_value_path") + dst_secret_value = params.get("dst_secret_value") + dst_secret_value_path = params.get("dst_secret_value_path") + remote_pwd = params.get("migrate_dest_pwd") + remote_ip = params.get("migrate_dest_host") + remote_user = params.get("remote_user", "root") + + def _create_secret(session=None, remote_args=None, secret_value_path=None): + """ + create secret + + :param session: a session object of remote host + :param remote_args: remote host parameters + :param secret_value_path: the path of secret value + """ + src_sec_uuid = None + dst_sec_uuid = None + libvirt_secret.clean_up_secrets(session) + if remote_args: + dst_sec_uuid = libvirt.create_secret(auth_sec_dict, remote_args=remote_args) + else: + src_sec_uuid = libvirt.create_secret(auth_sec_dict) + auth_sec_dict.update({"sec_uuid": src_sec_uuid}) + if os.path.exists(secret_value_path): + os.remove(secret_value_path) + if session: + cmd = "echo '%s' > %s" % (dst_secret_value, secret_value_path) + process.run(cmd, shell=True) + remote.scp_to_remote(remote_ip, '22', remote_user, remote_pwd, + secret_value_path, secret_value_path, + limit="", log_filename=None, timeout=60, + interface=None) + cmd = f"virsh secret-set-value {dst_sec_uuid} --file {secret_value_path} --plain" + remote.run_remote_cmd(cmd, params) + else: + cmd = "echo '%s' > %s" % (src_secret_value, secret_value_path) + process.run(cmd, shell=True) + cmd = f"virsh secret-set-value {src_sec_uuid} --file {secret_value_path} --plain" + process.run(cmd, shell=True) + return src_sec_uuid, dst_sec_uuid + + src_sec_uuid, _ = _create_secret(secret_value_path=src_secret_value_path) + params.update({"auth_sec_dict": auth_sec_dict}) + virsh_dargs = {'remote_ip': remote_ip, 'remote_user': remote_user, + 'remote_pwd': remote_pwd, 'unprivileged_user': None, + 'ssh_remote_auth': True} + remote_virsh_session = None + remote_virsh_session = virsh.VirshPersistent(**virsh_dargs) + _, dst_sec_uuid = _create_secret(session=remote_virsh_session, remote_args=virsh_dargs, + secret_value_path=dst_secret_value_path) + return src_sec_uuid, dst_sec_uuid + + +def compare_swtpm_version(major, minor): + """ + Get swtpm pkg version and check whether > major.minor + + :param major: swtpm major version number + :param minor: swtpm minor version number + :return: boolean value compared to major.minor + """ + cmd = 'rpm -q swtpm' + v_swtpm = process.run(cmd).stdout_text.strip().split('-') + v_major = int(v_swtpm[1].split('.')[0]) + v_minor = int(v_swtpm[1].split('.')[1]) + return False if (v_major == major and v_minor < minor) else True diff --git a/provider/numa/numa_base.py b/provider/numa/numa_base.py index d1eacc97843..053305c4b16 100644 --- a/provider/numa/numa_base.py +++ b/provider/numa/numa_base.py @@ -10,6 +10,7 @@ import re from avocado.core import exceptions +from avocado.utils import memory from avocado.utils import process from virttest import cpu @@ -26,36 +27,64 @@ class NumaTest(object): :param params: dict with the test parameters :param test: test object """ - def __init__(self, vm, params, test): + def __init__(self, vm, params, test, session=None): self.params = params self.test = test self.vm = vm + self.session = session cmd = "numactl --hardware" - status, self.host_numactl_info = utils_misc.cmd_status_output(cmd, shell=True) + status, self.host_numactl_info = utils_misc.cmd_status_output(cmd, shell=True, session=self.session) if status != 0: test.error("Failed to get information from %s", cmd) - self.host_numa_info = utils_misc.NumaInfo() + self.host_numa_info = utils_misc.NumaInfo(session=self.session) self.online_nodes = self.host_numa_info.get_online_nodes().copy() - self.online_nodes_withmem = self.host_numa_info.get_online_nodes_withmem() - self.all_usable_numa_nodes = self.online_nodes_withmem.copy() + self.online_nodes_withmem = self.host_numa_info.get_online_nodes_withmem().copy() self.virsh_dargs = {'ignore_status': False, 'debug': True} - def check_numa_nodes_availability(self, expect_nodes_num=2): - if len(self.all_usable_numa_nodes) < expect_nodes_num: + def get_available_numa_nodes(self, expect_node_free_mem_min=None): + """ + Get availbe host numa nodes accroding to min free memory + + :param expect_node_free_mem_min: int, the minimum of the node free memory + :return: list, available host numa nodes + """ + expected_numa_list = self.online_nodes_withmem.copy() + if expect_node_free_mem_min: + for a_node in self.online_nodes_withmem: + node_free_mem = self.host_numa_info.read_from_node_meminfo(a_node, 'MemFree') + if int(node_free_mem) < expect_node_free_mem_min: + expected_numa_list.remove(a_node) + self.test.log.debug("Host numa node '%s' free memory is %s" + "which doesn't meet requirement", a_node, node_free_mem) + self.test.log.debug("Host numa nodes in list %s have free memory bigger than %s" % (expected_numa_list, + (str(expect_node_free_mem_min) if expect_node_free_mem_min else "0"))) + return expected_numa_list + + def check_numa_nodes_availability(self, expect_nodes_num=2, expect_node_free_mem_min=None): + """ + Check if the host numa nodes are available for testing + + :param expect_nodes_num: int, the number of host numa nodes + :param expect_node_free_mem_min: int, the minimum of the node free memory + """ + self.online_nodes_withmem = self.get_available_numa_nodes(expect_node_free_mem_min) + available_node_num = len(self.online_nodes_withmem) + if available_node_num < expect_nodes_num: self.test.cancel("Expect %d numa nodes at " "least, but found %d" % (expect_nodes_num, - len(self.all_usable_numa_nodes))) + available_node_num)) + self.test.log.debug("The number of host numa node with " + "memory is %s which meets the " + "requirement", available_node_num) - def setup(self, node_index=0): - self.check_numa_nodes_availability() - vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(self.vm.name) - self.params['backup_vmxml'] = vmxml.copy() - kernel_hp_file = self.params.get('kernel_hp_file') - if kernel_hp_file and kernel_hp_file.count('/sys/devices/system/node/'): - self.params['kernel_hp_file'] = kernel_hp_file % self.online_nodes_withmem[node_index] + def setup(self, expect_nodes_num=2, expect_node_free_mem_min=None): + self.check_numa_nodes_availability(expect_nodes_num, expect_node_free_mem_min) + if self.vm: + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(self.vm.name) + self.params['backup_vmxml'] = vmxml.copy() def teardown(self): - if self.vm.is_alive(): + if self.vm and self.vm.is_alive(): self.vm.destroy() backup_vmxml = self.params.get("backup_vmxml") if backup_vmxml: @@ -63,38 +92,44 @@ def teardown(self): backup_vmxml.sync() hpc_2M = self.params.get('hp_config_2M') hpc_1G = self.params.get('hp_config_1G') - for hpc in [hpc_2M, hpc_1G]: + hpc_list = self.params.get('hpc_list', []) + hpc_list.extend([hpc_2M, hpc_1G]) + for hpc in hpc_list: if hpc: + self.test.log.debug("Teardown: clean up hugepage setting for %d", hpc.hugepage_size) hpc.cleanup() - def prepare_vm_xml(self): + def prepare_vm_xml(self, required_nodes=None): """ Prepare vm xml + :param required_nodes: list, the specified numa node ids, like [0, 1, 2] :return: VMXML object """ single_host_node = self.params.get('single_host_node') - vm_attrs = eval(self.params.get('vm_attrs')) + vm_attrs = eval(self.params.get('vm_attrs', '{}')) numa_memory = self.params.get('numa_memory') numa_memnode = self.params.get('numa_memnode') memory_backing = eval(self.params.get('memory_backing', '{}')) # Setup vm basic attributes vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(self.vm.name) - vmxml.setup_attrs(**vm_attrs) + if vm_attrs: + vmxml.setup_attrs(**vm_attrs) # Setup numa tune attributes nodeset = None if single_host_node: - all_nodes = self.all_usable_numa_nodes + nodes_used = required_nodes if required_nodes else self.online_nodes_withmem if single_host_node == 'no': # When memory bind to multiple numa nodes, # the test only selects the first two numa nodes with memory on the host - nodeset = ','.join(['%d' % all_nodes[0], '%d' % all_nodes[1]]) + nodeset = ','.join(['%d' % nodes_used[0], '%d' % nodes_used[1]]) + nodeset = convert_to_string_with_dash(nodeset) elif single_host_node == 'yes': # When memory bind to single numa node, the test only selects # the first host numa node. - nodeset = '%d' % all_nodes[0] + nodeset = '%d' % nodes_used[0] self.params['nodeset'] = nodeset numa_tune_dict = {} @@ -107,9 +142,13 @@ def prepare_vm_xml(self): if nodeset: numa_memory.update({'nodeset': nodeset}) numa_tune_dict.update({'numa_memory': numa_memory}) + self.params["numa_memory"] = numa_memory if numa_memnode: - numa_memnode = eval(numa_memnode % nodeset) - numa_tune_dict.update({'numa_memnode': numa_memnode}) + if numa_memnode.count('%s'): + numa_memnode = numa_memnode % nodeset + self.params["numa_memnode"] = numa_memnode + numa_tune_dict.update({'numa_memnode': eval(numa_memnode)}) + self.test.log.debug(numa_tune_dict) if numa_tune_dict: vmxml.setup_attrs(**numa_tune_dict) @@ -160,7 +199,7 @@ def get_host_numa_memory_alloc_info(mem_size): :param mem_size: int, the vm memory size :return: str, the matched output in numa_maps """ - cmd = 'grep -B1 %s /proc/`pidof qemu-kvm`/smaps' % mem_size + cmd = 'grep -B1 "%s " /proc/`pidof qemu-kvm`/smaps' % mem_size out = process.run(cmd, shell=True, verbose=True).stdout_text.strip() matches = re.findall('(\w+)-', out) if not matches: @@ -193,3 +232,75 @@ def convert_to_list_of_int(cpus_in_short, cpu_num): """ cpu_list = cpu.cpus_string_to_affinity_list(cpus_in_short, cpu_num) return [index for index in range(0, len(cpu_list)) if cpu_list[index] == 'y'] + + +def check_hugepage_availability(pages_list): + """ + Check if the configured huge page size is supported on the system + + :param pages_list: list, like [{'size': '1048576', 'unit': 'KiB'}] + :raises: exceptions.TestSkipError: when hugepage is not supported + """ + unit_mapping = {'G': 1048576, 'M': 1024, 'KiB': 1} + supported_hugepages = memory.get_supported_huge_pages_size() + for a_page in pages_list: + if a_page.get("size") is None or a_page.get("unit") is None: + raise exceptions.TestError("'size' and 'unit' are required") + if a_page['size'].count("%s"): + continue + size = int(a_page['size']) + unit = a_page['unit'] + size *= unit_mapping[unit] + if size not in supported_hugepages: + raise exceptions.TestSkipError("The hugepage size '%s' is " + "not supported on current " + "arch (support: %s)" % (size, + supported_hugepages)) + + +def adjust_parameters(params, hugepage_size=None, node_index="0", hugepage_mem=1048576, target_nodes=""): + """ + This function will adjust parameters according to current + architecture and given hugepage size and parameters. + + Used parameters: + - memory_backing: optional + - kernel_hp_file: optional + + Adjusted parameters: + - hugepage_size: hugepage size in KiB to be allocated + - kernel_hp_file: huge page kernel file, + like /sys/devices/system/node/node0/hugepages/hugepages-2048kB/nr_hugepages + - expected_hugepage_size: expected hugepage size for the test + - target_hugepages: hugepage numbers to be allocated + Above four parameters are used by test_setup.HugePageConfig() + - memory_backing: memory backing dict used by test case, like + {'hugepages': {'pages': [{'size': '%s', 'unit': 'KiB'}]}} + + :param params: dict, test parameters + :param hugepage_size: int, huge page size in KiB + :param node_index: str, the numa node index + :param hugepage_mem: int, the hugepage memory in KiB to be allocated + :param target_nodes: str, numa nodes to set, for example "0 1" + """ + default_hugepage_size = memory.get_huge_page_size() + page_size = default_hugepage_size if hugepage_size is None else hugepage_size + params['hugepage_size'] = page_size + memory_backing = params['memory_backing'] + if memory_backing and memory_backing.count('%s'): + params['memory_backing'] = memory_backing % str(page_size) + kernel_hp_file = params.get('kernel_hp_file') + if kernel_hp_file: + if kernel_hp_file.count('/sys/devices/system/node/node%s/hugepages/hugepages-%s'): + params['kernel_hp_file'] = kernel_hp_file % (node_index, str(page_size)) + elif kernel_hp_file.count('/sys/kernel/mm/hugepages/hugepages-%s'): + params['kernel_hp_file'] = kernel_hp_file % str(page_size) + params['expected_hugepage_size'] = page_size + params['target_hugepages'] = hugepage_mem // page_size + if page_size == default_hugepage_size: + hugepage_path = "/dev/hugepages" + else: + hugepage_path = "/dev/hugepages%d" % page_size + if target_nodes: + params['target_nodes'] = target_nodes + params['vm_hugepage_mountpoint'] = hugepage_path diff --git a/provider/save/save_base.py b/provider/save/save_base.py index c003e3ee202..843df0b416e 100644 --- a/provider/save/save_base.py +++ b/provider/save/save_base.py @@ -8,29 +8,35 @@ VIRSH_ARGS = {'debug': True, 'ignore_status': False} -def pre_save_setup(vm): +def pre_save_setup(vm, serial=False): """ Setup vm before save: Start ping process and get uptime since when on vm :param vm: vm instance + :param serial: Whether to use a serial connection :return: a tuple of pid of ping and uptime since when """ - session = vm.wait_for_login() + if serial: + vm.cleanup_serial_console() + vm.create_serial_console() + session = vm.wait_for_serial_login() + else: + session = vm.wait_for_login() upsince = session.cmd_output('uptime --since').strip() LOG.debug(f'VM has been up since {upsince}') - ping_cmd = 'ping 127.0.0.1' + ping_cmd = 'ping 127.0.0.1 >/tmp/ping_out 2>&1' # This session shouldn't be closed or it will kill ping session.sendline(ping_cmd + '&') - check_session = vm.wait_for_login() - pid_ping = check_session.cmd_output('pidof ping').strip().split()[-1] - check_session.close() + ping_output = session.cmd_output('pidof ping') + LOG.debug(f'ping cmd output: {ping_output}') + pid_ping = ping_output.strip().split()[-1] LOG.debug(f'Pid of ping: {pid_ping}') return pid_ping, upsince -def post_save_check(vm, pid_ping, upsince): +def post_save_check(vm, pid_ping, upsince, serial=False): """ Check vm status after save-restore: Whether ping is still running, uptime since when is the same as before @@ -39,8 +45,14 @@ def post_save_check(vm, pid_ping, upsince): :param vm: vm instance :param pid_ping: pid of ping :param upsince: uptime since when + :param serial: Whether to use a serial connection """ - session = vm.wait_for_login() + if serial: + vm.cleanup_serial_console() + vm.create_serial_console() + session = vm.wait_for_serial_login() + else: + session = vm.wait_for_login() upsince_restore = session.cmd_output('uptime --since').strip() LOG.debug(f'VM has been up (after restore) since {upsince_restore}') LOG.debug(session.cmd_output(f'pidof ping')) @@ -50,8 +62,8 @@ def post_save_check(vm, pid_ping, upsince): session.close() if upsince_restore != upsince: - raise exceptions.TestWarn(f'Uptime since {upsince_restore} is ' - f'incorrect, should be {upsince}') + LOG.warning(f'Uptime since {upsince_restore} is ' + f'incorrect, should be {upsince}') ping_cmd = 'ping 127.0.0.1' if ping_cmd not in proc_info: raise exceptions.TestFail('Cannot find running ping command ' diff --git a/provider/snapshot/snapshot_base.py b/provider/snapshot/snapshot_base.py index 8f0af052cfc..bf124a754a4 100644 --- a/provider/snapshot/snapshot_base.py +++ b/provider/snapshot/snapshot_base.py @@ -62,6 +62,18 @@ def create_snapshot_by_xml(self, snap_dict, snap_disk_list, options=''): virsh.snapshot_create(self.vm.name, snap_options, **self.virsh_dargs) virsh.snapshot_dumpxml(self.vm.name, snap_dict['snap_name'], **self.virsh_dargs) + def check_current_snapshot(self, snap_name): + """ + Check vm current snapshot name is expected + + :param snap_name, expected snapshot name. + """ + current_name = virsh.snapshot_current( + self.vm.name, **self.virsh_dargs).stdout.strip() + if current_name != snap_name: + self.test.fail("Current snapshot name is %s, should be %s" % ( + current_name, snap_name)) + def delete_snapshot(self, snap_names, options=''): """ Delete snapshots of the vm diff --git a/provider/sriov/check_points.py b/provider/sriov/check_points.py index 06231f64aea..22c4005e1a1 100644 --- a/provider/sriov/check_points.py +++ b/provider/sriov/check_points.py @@ -1,5 +1,6 @@ import aexpect import logging +import platform import re from avocado.core import exceptions @@ -139,6 +140,8 @@ def check_vm_network_accessed(vm_session, ping_count=3, ping_timeout=5, :raise: test.fail when ping fails. :return: Output of ping command """ + if platform.machine() != "x86_64": + return if not ping_dest: ping_dest = sriov_base.get_ping_dest(vm_session) if tcpdump_iface: diff --git a/provider/sriov/sriov_base.py b/provider/sriov/sriov_base.py index 289bd4044c5..67a4be69171 100644 --- a/provider/sriov/sriov_base.py +++ b/provider/sriov/sriov_base.py @@ -1,5 +1,6 @@ -import re import os +import re +import time from avocado.core import exceptions from avocado.utils import process @@ -17,10 +18,11 @@ from virttest.utils_libvirt import libvirt_vmxml from virttest.utils_libvirt import libvirt_virtio from virttest.utils_libvirt import libvirt_network -from virttest.utils_libvirt import libvirt_pcicontr from provider.interface import interface_base +SKIP_CHECKS = False + def setup_vf(pf_pci, params, session=None): """ @@ -125,6 +127,8 @@ def __init__(self, vm, test, params, session=None): session=self.session) utils_sriov.set_vf(self.pf_pci_path, 0, session=self.session) + time.sleep(10) + self.host_linked_ifaces = utils_net.get_net_if(state="UP") setup_vf(self.pf_pci, self.params, session=self.session) self.pf_info = utils_sriov.get_pf_info_by_pci( self.pf_pci, session=self.session) @@ -143,38 +147,29 @@ def __init__(self, vm, test, params, session=None): self.default_vf_mac = utils_sriov.get_vf_mac( self.pf_name, session=self.session) self.vf_mac = "" - self.dev_slot = None - self.controller_dicts = eval(self.params.get("controller_dicts", "[]")) + + iface_attrs = self.params.get('iface_dict') if self.params.get( + 'iface_dict') else self.params.get('hostdev_dict') + + if self.pf_name not in self.host_linked_ifaces: + test.log.debug("skip connection check on this host") + global SKIP_CHECKS + SKIP_CHECKS = True + else: + if (self.params.get("dev_name", "vf") == "pf" or + (not self.params.get("network_dict") and iface_attrs + and iface_attrs.count("pf_"))): + self.host_linked_ifaces.remove(self.pf_name) + if not self.host_linked_ifaces: + self.test.cancel("This test needs at least 1 linked " + "interface(excluding PF) available " + "on the host.") new_xml = vm_xml.VMXML.new_from_inactive_dumpxml(self.vm.name) self.orig_config_xml = new_xml.copy() def __del__(self): recover_vf(self.pf_pci, self.params, 0, session=self.session) - def update_disk_addr(self, disk_dict): - """ - Update disk address - - :param disk_dict: The original disk attrs - :return: The updated disk attrs - """ - if self.controller_dicts: - dev_bus = self.controller_dicts[-1].get('index') - dev_attrs = {'bus': dev_bus} - if disk_dict['target']['bus'] != "scsi": - dev_attrs.update({'type': self.controller_dicts[-1].get('type')}) - if self.controller_dicts[-1].get('model') == 'pcie-to-pci-bridge': - self.dev_slot = 1 - dev_attrs.update({'slot': self.dev_slot}) - - disk_dict.update({"address": {'attrs': dev_attrs}}) - if disk_dict['target']['bus'] == "scsi": - disk_dict['address']['attrs'].update({'type': 'drive'}) - - if self.controller_dicts[-1]['model'] == 'pcie-root-port': - self.controller_dicts.pop() - return disk_dict - def parse_iface_dict(self): """ Parse iface_dict from params @@ -197,15 +192,6 @@ def parse_iface_dict(self): if vf_pci_addr2.get('type'): del vf_pci_addr2['type'] iface_dict = eval(self.params.get('hostdev_dict', '{}')) - - if self.controller_dicts and iface_dict: - iface_bus = "%0#4x" % int(self.controller_dicts[-1].get('index')) - iface_attrs = {'bus': iface_bus} - if isinstance(self.dev_slot, int): - self.dev_slot += 1 - iface_attrs.update({'slot': self.dev_slot}) - iface_dict.update({"address": {'attrs': iface_attrs}}) - self.test.log.debug("iface_dict: %s.", iface_dict) return iface_dict def parse_network_dict(self): @@ -243,40 +229,6 @@ def parse_iommu_test_params(self): "br_dict": br_dict, "dev_type": dev_type} return iommu_params - def prepare_controller(self): - """ - Prepare controller(s) - - :return: Updated controller attrs - """ - if not self.controller_dicts: - return - - for contr_dict in self.controller_dicts: - pre_controller = contr_dict.get("pre_controller") - if pre_controller: - pre_contrs = list( - filter(None, [c.get('index') for c in self.controller_dicts - if c['type'] == contr_dict['type'] and - c['model'] == pre_controller])) - if pre_contrs: - pre_idx = pre_contrs[0] - else: - pre_idx = libvirt_pcicontr.get_max_contr_indexes( - vm_xml.VMXML.new_from_dumpxml(self.vm.name), - contr_dict['type'], pre_controller) - if not pre_idx: - self.test.error( - f"Unable to get index of {pre_controller} controller!") - contr_dict.pop("pre_controller") - libvirt_vmxml.modify_vm_device( - vm_xml.VMXML.new_from_dumpxml(self.vm.name), 'controller', - contr_dict, 100) - contr_dict['index'] = libvirt_pcicontr.get_max_contr_indexes( - vm_xml.VMXML.new_from_dumpxml(self.vm.name), - contr_dict['type'], contr_dict['model'])[-1] - return self.controller_dicts - def get_dev_name(self): """ Get device name @@ -306,12 +258,11 @@ def get_rom_file(self): rom_vendor_device = lspci_stdout[1:-1].replace(':', '') + '.rom' rom_file = os.path.join('/usr/share/ipxe', rom_vendor_device) if not os.path.exists(rom_file): - build_cmd = "git clone https://github.com/ipxe/ipxe.git;\ - pushd ipxe/src; make bin/{0}; cp bin/{0} {1}; popd; \ - rm -rf ipxe".format(rom_vendor_device, rom_file) - process.run(build_cmd, shell=True, verbose=True) - if not os.path.exists(rom_file): - self.test.error("This test needs rom file: %s." % rom_file) + virtio_rom_file = "/usr/share/ipxe/1af41000.rom" + if not os.path.exists(virtio_rom_file): + self.test.error(f"This test needs a rom file, but neither {rom_file} " + f"nor {virtio_rom_file} exist!") + return virtio_rom_file return rom_file def create_iface_dev(self, dev_type, iface_dict): diff --git a/provider/usb/usb_base.py b/provider/usb/usb_base.py new file mode 100644 index 00000000000..333c93a2fff --- /dev/null +++ b/provider/usb/usb_base.py @@ -0,0 +1,49 @@ +from avocado.utils import distro +from avocado.utils import process + + +def get_host_pkg_and_cmd(): + """ + Get package and related command on the host. + + :return: pkg_and_cmd, extra usb package name and command. + """ + if int(distro.detect().version) <= 9: + pkg_and_cmd = ("usbredir-server", "usbredirserver") + else: + pkg_and_cmd = ("usbredir-tools", "usbredirect") + return pkg_and_cmd + + +def start_redirect_server(params, usb_cmd, vendor_id, product_id): + """ + Start redirect server + + :param params: Dict with test params. + :param usb_cmd, the usb command to confirm how to start server. + :param vendor_id, vendor id. + :param product_id, produce id. + :return server_id, redirect server id + """ + port_num = params.get("port_num") + if usb_cmd == "usbredirserver": + ps = process.SubProcess("usbredirserver -p {} {}:{}".format + (port_num, vendor_id, product_id), + shell=True) + elif usb_cmd == "usbredirect": + ps = process.SubProcess( + "usbredirect --device {}:{} --as {}:{}".format + (vendor_id, product_id, "127.0.0.1", port_num), + shell=True) + server_id = ps.start() + return server_id + + +def kill_redirect_server(usb_cmd): + """ + Kill redirect server + + :param usb_cmd, the usb command to kill server. + """ + if 'server_id' in globals(): + process.run("killall {}".format(usb_cmd), ignore_status=True) diff --git a/provider/v2v_vmcheck_helper.py b/provider/v2v_vmcheck_helper.py index c0b89a788a6..74dd11901ef 100644 --- a/provider/v2v_vmcheck_helper.py +++ b/provider/v2v_vmcheck_helper.py @@ -37,7 +37,8 @@ 'virtio_rng': '2.6.26', 'cache_none': 'virt-v2v-1.42.0-4', 'q35': 'virt-v2v-1.43.3-2', - 'virtio_model': 'virt-v2v-1.45.97-4'} + 'virtio_model': 'virt-v2v-1.45.97-4', + 'virtio_skip': 'virt-v2v-2.0.0-1'} # bz#1961107 V2V_ADAPTE_SPICE_REMOVAL_VER = "[virt-v2v-1.45.92,)" V2V_VSOCK_SUPPORT_LINUX_VER = "[virt-v2v-2.0.2-1,)" @@ -421,7 +422,7 @@ def _id_short_to_long(short_id): verbose=False) short_id_all = output.stdout_text.splitlines() if short_id not in [os_id.strip() for os_id in short_id_all]: - LOG.info("Not found shourt_id '%s' on host", short_id) + LOG.info("Not found short_id '%s' on host", short_id) long_id = _guess_long_id(short_id) else: cmd = "osinfo-query os --fields=id short-id='%s'| tail -n +3" % short_id @@ -693,7 +694,7 @@ def check_linux_vm(self): pci_devs = self.checker.get_vm_pci_list() virtio_devs = ["Virtio network device", "Virtio block device", - "Virtio memory balloon"] + "Virtio (memory|1.0) balloon"] # Virtio RNG supports from kernel-2.6.26 # https://wiki.qemu.org/Features/VirtIORNG if compare_version(FEATURE_SUPPORT['virtio_rng'], kernel_version): @@ -783,11 +784,20 @@ def check_windows_vm(self): self.log_err(err_msg) # Check Red Hat VirtIO drivers and display adapter + if not compare_version(FEATURE_SUPPORT['virtio_skip']): + reason = "Unsupported if v2v < %s" % FEATURE_SUPPORT['virtio_skip'] + LOG.info('Skip Checking VirtIO drivers: %s' % reason) + return + LOG.info("Checking VirtIO drivers and display adapter") expect_video = self.get_expect_video_model() has_virtio_win, has_qxldod = self.get_virtio_win_config() + cpu_drivers = ['Intel Processor', 'AMD Processor'] expect_drivers = ["Red Hat VirtIO SCSI", - "Red Hat VirtIO Ethernet Adapte"] + "Red Hat VirtIO Ethernet Adapte", + "VirtIO RNG", + "VirtIO Serial", + "VirtIO Balloon"] expect_adapter = 'Microsoft Basic Display Driver' virtio_win_qxl_os = ['win2008r2', 'win7'] virtio_win_qxldod_os = ['win10', 'win2016', 'win2019'] @@ -830,7 +840,15 @@ def check_windows_vm(self): if expect_drivers: for driver in expect_drivers: self.log_err("Not find driver: %s" % driver) - + if re.search(r"(Intel|AMD) Processor", win_dirvers): + if re.search(r"(Intel|AMD) Processor", win_dirvers).group(0) in cpu_drivers: + LOG.info("CPU driver '%s' is found" % re.search(r"(Intel|AMD) Processor", win_dirvers).group(0)) + else: + err_msg = "CPU driver is not found" + self.log_err(err_msg) + cpu_status = self.checker.get_cpu_status() + if not re.search(r'OK', cpu_status): + self.log_err("cpu status is abnormal") # Check graphic and video type in VM XML self.check_vm_xml() diff --git a/provider/vfio/__init__.py b/provider/vfio/__init__.py new file mode 100644 index 00000000000..d59409523b3 --- /dev/null +++ b/provider/vfio/__init__.py @@ -0,0 +1,97 @@ +import logging +import re + +from avocado.core.exceptions import TestFail +from virttest.libvirt_xml.devices.hostdev import Hostdev +from virttest.libvirt_xml.nodedev_xml import MdevXML, NodedevXML + +LOG = logging.getLogger("avcoado." + __name__) + + +def get_hostdev_xml(address, model=""): + """ + Creates a hostdev instance for a mediated device + with given uuid. + + :param address: For mediated devices, the UUID of the mediated device + For PCI devices, the full address element + :param model: mediated device type model, e.g. 'vfio-ccw' + If omitted, treat as PCI device + """ + + hostdev_xml = Hostdev() + hostdev_xml.mode = "subsystem" + if "vfio" in model: + hostdev_xml.model = model + hostdev_xml.type = "mdev" + hostdev_xml.source = hostdev_xml.new_source(**{"uuid": address}) + else: + hostdev_xml.type = "pci" + hostdev_xml.managed = "yes" + hostdev_xml.source = hostdev_xml.new_source(**address) + hostdev_xml.xmltreefile.write() + return hostdev_xml + + +def get_nodedev_xml(device_type, parent, uuid, domains=[]): + """ + Create and return the node device XML for Mediated Devices. + + :param device_type: //capabilities/type@id + :param parent: //parent + :param uuid: //capability/uuid + :param domains: for vfio_ap-passthrough, the domains to be passed through + e.g. ["00.000e", "00.000f", "01.000e", "01.000f"] + """ + device_xml = NodedevXML() + device_xml["parent"] = parent + mdev_xml = MdevXML() + attributes = { + "type_id": device_type, + "uuid": uuid, + } + if domains: + attrs = [] + cards = [] + doms = [] + for domain in domains: + card, dom = domain.split(".") + if card not in cards: + attrs.append({"name": "assign_adapter", "value": "0x" + card}) + cards.append(card) + if dom not in doms: + attrs.append({"name": "assign_domain", "value": "0x" + dom}) + doms.append(dom) + attributes["attrs"] = attrs + mdev_xml.setup_attrs(**attributes) + device_xml.set_cap(mdev_xml) + LOG.debug("Device XML: %s", device_xml) + return device_xml + + +def get_parent_device(device_name): + """ + Gets the parent device name for the given device name + as known by libvirt + + :param device_name: node device name + """ + xml = NodedevXML.new_from_dumpxml(device_name) + return xml["parent"] + + +def check_pci_device_present(guest_pci_id, name_part, session): + """ + Checks if the pci device with id and given part of its name + are present in the guest + + :param guest_pci_id: expected device id inside of the guest, + e.g. '0000:00:00.0' + :param name_part: part of it's name e.g. "Mellanox Technologies" + :param session: guest session + :raises TestFail: if the device is not listed + """ + s, o = session.cmd_status_output("lspci", print_func=LOG.debug) + pattern = guest_pci_id + ".*" + name_part + if s or not [x for x in o.split("\n") if re.search(pattern, x)]: + raise TestFail(f"Couldn't find {guest_pci_id} with {name_part} in {o}") diff --git a/provider/vfio/ccw.py b/provider/vfio/ccw.py index d447a04ddd1..86e7fb846cb 100644 --- a/provider/vfio/ccw.py +++ b/provider/vfio/ccw.py @@ -1,13 +1,12 @@ import logging as log from avocado.core.exceptions import TestError - -from virttest import utils_package -from virttest import virsh -from virttest.utils_zchannels import SubchannelPaths +from virttest import utils_package, virsh from virttest.utils_misc import cmd_status_output -from virttest.libvirt_xml.devices.hostdev import Hostdev from virttest.utils_test.libvirt import mkfs +from virttest.utils_zchannels import SubchannelPaths + +from provider.vfio import get_hostdev_xml # default disk paths supposing only one DASD is passed through DASD_DISK = "/dev/dasda" @@ -18,7 +17,7 @@ # Using as lower capital is not the best way to do, but this is just a # workaround to avoid changing the entire file. -logging = log.getLogger('avocado.' + __name__) +logging = log.getLogger("avocado." + __name__) def read_write_operations_work(session, chpids, makefs=True): @@ -67,8 +66,9 @@ def read_write(session): if err: raise TestError("Some read/write operation failed. %s" % out) if cmd == cmd3 and "kaixo" not in out: - raise TestError("Didn't get the written value '%s'" - " from file '%s'" % ("kaixo", out)) + raise TestError( + "Didn't get the written value '%s'" " from file '%s'" % ("kaixo", out) + ) def make_dasd_part(path, session): @@ -83,8 +83,7 @@ def make_dasd_part(path, session): cmd = "fdasd -a %s" % path err, out = cmd_status_output(cmd, shell=True, session=session) if err: - raise TestError("Couldn't create partition. Status code '%s'. %s." - % (err, out)) + raise TestError("Couldn't create partition. Status code '%s'. %s." % (err, out)) return True @@ -116,6 +115,8 @@ def format_dasd(path, session): err, out = cmd_status_output(cmd, shell=True, session=session) if err: raise TestError("Couldn't format disk. %s" % out) + udev_cmd = "udevadm settle" + cmd_status_output(udev_cmd, shell=True, session=session) return True @@ -177,6 +178,17 @@ def set_device_online(device_id, session=None): raise TestError("Could not set device online. %s" % out) +def get_subchannel_info(session=None): + """ + Gets the subchannel path info + + :param session: if given, get info inside guest + """ + paths = SubchannelPaths(session) + paths.get_info() + return paths + + def get_first_device_identifiers(chpids, session): """ Gets the usual device identifier cssid.ssid.devno @@ -187,13 +199,12 @@ def get_first_device_identifiers(chpids, session): :raises TestError: if the device can't be found inside guest """ - paths = SubchannelPaths(session) - paths.get_info() - devices_inside_guest = [x for x in paths.devices - if x[paths.HEADER["CHPIDs"]] == chpids] + paths = get_subchannel_info(session) + devices_inside_guest = [ + x for x in paths.devices if x[paths.HEADER["CHPIDs"]] == chpids + ] if not devices_inside_guest: - raise TestError("Device with chpids %s wasn't" - " found inside guest" % chpids) + raise TestError("Device with chpids %s wasn't" " found inside guest" % chpids) first = devices_inside_guest[0] return first[paths.HEADER["Device"]], first[paths.HEADER["Subchan."]] @@ -208,10 +219,10 @@ def device_is_listed(session, chpids): :return: True if device is listed """ - paths = SubchannelPaths(session) - paths.get_info() - devices_inside_guest = [x for x in paths.devices - if x[paths.HEADER["CHPIDs"]] == chpids] + paths = get_subchannel_info(session) + devices_inside_guest = [ + x for x in paths.devices if x[paths.HEADER["CHPIDs"]] == chpids + ] return len(devices_inside_guest) > 0 @@ -272,6 +283,20 @@ def stop_device(uuid): logging.warning("Couldn't stop device. %s", out) +def detach_hostdev(vm_name, uuid): + """ + Detaches the mdev to the machine. + + :param vm_name: VM name + :param uuid: mdev uuid + """ + + hostdev_xml = get_hostdev_xml(uuid, "vfio-ccw") + virsh.detach_device( + vm_name, hostdev_xml.xml, flagstr="--current", ignore_status=False + ) + + def attach_hostdev(vm_name, uuid): """ Attaches the mdev to the machine. @@ -280,14 +305,10 @@ def attach_hostdev(vm_name, uuid): :param uuid: mdev uuid """ - hostdev_xml = Hostdev() - hostdev_xml.mode = "subsystem" - hostdev_xml.model = "vfio-ccw" - hostdev_xml.type = "mdev" - hostdev_xml.source = hostdev_xml.new_source(**{"uuid": uuid}) - hostdev_xml.xmltreefile.write() - virsh.attach_device(vm_name, hostdev_xml.xml, flagstr="--current", - ignore_status=False) + hostdev_xml = get_hostdev_xml(uuid, "vfio-ccw") + virsh.attach_device( + vm_name, hostdev_xml.xml, flagstr="--current", ignore_status=False + ) def assure_preconditions(): @@ -295,27 +316,49 @@ def assure_preconditions(): Makes sure that preconditions are established. """ - utils_package.package_install(["mdevctl", - "driverctl"]) + utils_package.package_install(["mdevctl", "driverctl"]) + + +def select_first_available_device(device_ids): + """ + Loops through the given device identifiers and selects + the first device that exists on the system. + + :param device_ids: list of potential device identifiers. + :return device: device info as defined by SubchannelPaths + :raise TestError: if no available devices is found. + """ + paths = get_subchannel_info() + for device in paths.devices: + for device_id in device_ids: + if device[paths.HEADER["Device"]] == device_id: + return device + raise TestError(f"None of the devices is available, {device_ids}") -def get_device_info(devid=None): +def get_device_info(devid="", full=False): """ Gets the device info for passthrough. It selects a device that's safely removable if devid is not given. :param devid: The ccw device id, e.g. 0.0.5000 - :return: Subchannel and Channel path ids (schid, chpids) + Also supports value 'dasd' to return the first available DASD + :param full: per default only return schid, chpids; return + full device info if True + :return: The device info """ - paths = SubchannelPaths() - paths.get_info() + paths = get_subchannel_info() device = None - if devid: - device = paths.get_device(devid) - else: + if not devid: device = paths.get_first_unused_and_safely_removable() + elif devid == "dasd": + device = paths.get_first_dasd_in_use() + else: + device = paths.get_device(devid) + if full: + return device schid = device[paths.HEADER["Subchan."]] chpids = device[paths.HEADER["CHPIDs"]] return schid, chpids diff --git a/provider/vfio/mdev_handlers.py b/provider/vfio/mdev_handlers.py index 67982185040..74e1b77d820 100644 --- a/provider/vfio/mdev_handlers.py +++ b/provider/vfio/mdev_handlers.py @@ -1,26 +1,25 @@ """ This module contains classes and functions for handling mediated devices """ -import logging +import logging +import re from time import sleep from uuid import uuid4 -from avocado.core.exceptions import TestError -from avocado.core.exceptions import TestFail - +from avocado.core.exceptions import TestError, TestFail from virttest import virsh from virttest.utils_misc import wait_for -from virttest.utils_zcrypt import CryptoDeviceInfoBuilder, \ - APMaskHelper, MatrixDevice, load_vfio_ap, unload_vfio_ap +from virttest.utils_zcrypt import (APMaskHelper, CryptoDeviceInfoBuilder, + MatrixDevice, load_vfio_ap, unload_vfio_ap) -from provider.vfio import ccw +from provider.vfio import ccw, get_nodedev_xml, get_parent_device -LOG = logging.getLogger('avocado.' + __name__) +LOG = logging.getLogger("avocado." + __name__) class MdevHandler(object): - """ Base class for mdev type specific implementations """ + """Base class for mdev type specific implementations""" def create_nodedev(self, api="nodedev"): """ @@ -37,7 +36,7 @@ def create_nodedev(self, api="nodedev"): raise NotImplementedError() def get_target_address(self): - """ Returns a target address to use for hostdev """ + """Returns a target address to use for hostdev""" raise NotImplementedError() def check_device_present_inside_guest(self, session): @@ -49,7 +48,7 @@ def check_device_present_inside_guest(self, session): raise NotImplementedError() def clean_up(self): - """ Stops the mediated device and returns resources to the host """ + """Stops the mediated device and returns resources to the host""" raise NotImplementedError() @staticmethod @@ -76,22 +75,25 @@ def get_first_mdev_nodedev_name(): result = virsh.nodedev_list(cap="mdev", debug=True) device_names = result.stdout.strip().splitlines() if result.exit_status or len(device_names) == 0: - raise TestError("Couldn't create nodedev. %s. %s." % - (result.stderr, result.stdout)) + raise TestError( + "Couldn't create nodedev. %s. %s." % (result.stderr, result.stdout) + ) return device_names[0] class CcwMdevHandler(MdevHandler): - """ Class implementing test methods for vfio_ccw-io """ + """Class implementing test methods for vfio_ccw-io""" def __init__(self): - self.uuid = None + self.uuid = str(uuid4()) self.chpids = None self.schid = None self.target_address = None self.expected_device_address = None self.device_id = None + self.nodedev_pattern = r"mdev.*\d{4}" self.session = None + self.parent = None def create_nodedev(self, api="mdevctl", devid=None): """ @@ -100,24 +102,39 @@ def create_nodedev(self, api="mdevctl", devid=None): :return: name of mdev device as node device """ - if api != "mdevctl": + previously_run = self.schid is not None + if not previously_run: + self.schid, self.chpids = ccw.get_device_info(devid) + self.parent = get_parent_device("ccw_" + devid.replace(".", "_")) + ccw.set_override(self.schid) + + if api == "mdevctl": + return self._mdevctl_start() + elif api == "nodedev": + device_xml = get_nodedev_xml("vfio_ccw-io", self.parent, self.uuid) + return self._nodedev_create(device_xml.xml) + else: raise TestError("Handling mdev via '%s' is not implemented." % api) - self.schid, self.chpids = ccw.get_device_info(devid) - self.device_id, _ = ccw.get_first_device_identifiers(self.chpids, None) - ccw.set_override(self.schid) - self.uuid = str(uuid4()) + def _mdevctl_start(self): ccw.start_device(self.uuid, self.schid) return get_first_mdev_nodedev_name() + def _nodedev_create(self, xml): + res = virsh.nodedev_create(xml, debug=True, ignore_status=False) + o = res.stdout_text + return re.search(self.nodedev_pattern, o)[0] + def get_target_address(self): """ Returns a valid target device address :return: hostdev target address """ - self.target_address = "address.type=ccw,address.cssid=0xfe,address.ssid=0x0,address.devno=0x1111" + self.target_address = ( + "address.type=ccw,address.cssid=0xfe,address.ssid=0x0,address.devno=0x1111" + ) self.expected_device_address = "0.0.1111" return self.target_address @@ -129,13 +146,21 @@ def check_device_present_inside_guest(self, session): :raises: TestFail if device not found """ self.session = session - device, _ = ccw.get_first_device_identifiers(self.chpids, session) - if device != self.expected_device_address: - raise TestFail("Couldn't find device inside guest." - "Expected address %s, found %s." % - (self.expected_device_address, device)) - LOG.debug("Device was found inside guest with" - " expected id %s." % device) + paths = ccw.get_subchannel_info(session) + found_devices = [ + x + for x in paths.devices + if x[paths.HEADER["Device"]] == self.expected_device_address + ] + if not found_devices: + raise TestFail( + "Couldn't find device inside guest." + "Expected address %s, found %s." + % (self.expected_device_address, paths.devices) + ) + LOG.debug( + "Device was found inside guest with" " expected id %s." % found_devices[0] + ) def clean_up(self): """ @@ -150,46 +175,63 @@ def clean_up(self): # need to sleep to avoid issue with setting device offline # adding a wait_for would likely be more complicated sleep(1) - if self.device_id: - ccw.set_device_offline(self.device_id) class ApMdevHandler(MdevHandler): - """ Class implementing test methods for vfio_ap-passthrough """ + """Class implementing test methods for vfio_ap-passthrough""" def __init__(self): + self.uuid = str(uuid4()) self.mask_helper = None self.matrix_dev = None self.session = None self.devices = None + self.nodedev_pattern = "mdev.*matrix" # minimal supported hwtype self.MIN_HWTYPE = 10 self.vfio_ap_loaded = None - def create_nodedev(self, api="sysfs"): + def create_nodedev(self, api="sysfs", domains=[]): """ Creates a mediated device of a specific type and returns its name from libvirt. :return: name of mdev device as node device """ - if api != "sysfs": + previously_run = self.devices is not None + if not previously_run: + load_vfio_ap() + self.vfio_ap_loaded = True + + info = CryptoDeviceInfoBuilder.get() + LOG.debug("Host lszcrypt got %s", info) + + if not info.entries or int(info.domains[0].hwtype) < self.MIN_HWTYPE: + raise TestError( + "vfio-ap requires at least HWTYPE %s." % self.MIN_HWTYPE + ) + + if not domains: + self.devices = [info.domains[0]] + else: + self.devices = [x for x in info.domains if ".".join(x.id) in domains] + self.mask_helper = APMaskHelper.from_infos(self.devices) + + if api == "sysfs": + self.matrix_dev = MatrixDevice.from_infos(self.devices) + return get_first_mdev_nodedev_name() + elif api == "nodedev": + device_xml = get_nodedev_xml( + "vfio_ap-passthrough", "ap_matrix", self.uuid, domains + ) + return self._nodedev_create(device_xml.xml) + else: raise TestError("Handling mdev via '%s' is not implemented." % api) - load_vfio_ap() - self.vfio_ap_loaded = True - - info = CryptoDeviceInfoBuilder.get() - LOG.debug("Host lszcrypt got %s", info) - - if not info.entries or int(info.domains[0].hwtype) < self.MIN_HWTYPE: - raise TestError("vfio-ap requires at least HWTYPE %s." % self.MIN_HWTYPE) - - self.devices = [info.domains[0]] - self.mask_helper = APMaskHelper.from_infos(self.devices) - self.matrix_dev = MatrixDevice.from_infos(self.devices) - - return get_first_mdev_nodedev_name() + def _nodedev_create(self, xml): + res = virsh.nodedev_create(xml, debug=True, ignore_status=False) + o = res.stdout_text + return re.search(self.nodedev_pattern, o)[0] def create_blank_nodedev(self): """ @@ -231,15 +273,20 @@ def verify_passed_through(): if guest_info.domains: default_driver_on_host = self.devices[0].driver driver_in_guest = guest_info.domains[0].driver - LOG.debug("Expecting default drivers from host and guest" - " to be the same: { host: %s, guest: %s }", - default_driver_on_host, driver_in_guest) + LOG.debug( + "Expecting default drivers from host and guest" + " to be the same: { host: %s, guest: %s }", + default_driver_on_host, + driver_in_guest, + ) return default_driver_on_host == driver_in_guest return False if not wait_for(verify_passed_through, timeout=60, step=10): - raise TestFail("Crypto domain not attached correctly in guest." - " Please, check the test log for details.") + raise TestFail( + "Crypto domain not attached correctly in guest." + " Please, check the test log for details." + ) def clean_up(self): """ diff --git a/provider/viommu/__init__.py b/provider/viommu/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/provider/viommu/viommu_base.py b/provider/viommu/viommu_base.py new file mode 100644 index 00000000000..ccaafcedce8 --- /dev/null +++ b/provider/viommu/viommu_base.py @@ -0,0 +1,245 @@ +import os +import logging + +from avocado.core import exceptions + +from virttest import libvirt_version +from virttest import utils_net + +from virttest.libvirt_xml import vm_xml +from virttest.utils_libvirt import libvirt_vmxml +from virttest.utils_libvirt import libvirt_virtio +from virttest.utils_libvirt import libvirt_pcicontr + +LOG = logging.getLogger('avocado.' + __name__) + + +def get_devices_pci(vm_session, test_devices): + """ + Get the devices pci + + :param vm_session: VM session + :param test_devices: test devices to check + :return: The test devices' pci + """ + result = {} + for dev in test_devices: + s, o = vm_session.cmd_status_output( + "lspci | awk 'BEGIN{IGNORECASE=1} /%s/ {print $1}'" % dev) + LOG.debug(o) + if s: + exceptions.TestFail("Failed to get pci address!") + result.update({dev: o.strip().splitlines()}) + return result + + +def get_added_devices_pci(vm_session, test_devices, orig_devices=None): + """ + Get the newly added devices pci + + :param vm_session: VM session + :param test_devices: test devices to check + :param orig_devices: The original devices + :return: The pci of the added device + """ + result = {} + act_devices = get_devices_pci(vm_session, test_devices) + if not orig_devices: + return act_devices + for k, v in act_devices.items(): + added_dev = list(filter(lambda x: x not in orig_devices.get(k), v)) + LOG.debug(f"added dev: {added_dev}") + if not added_dev: + exceptions.TestFail("Failed to get the added devices' pci address!") + result[k] = added_dev + return result + + +def get_iommu_dev_dir(vm_session, pci_addr): + """ + Get iommu group's devices + + :param vm_session: VM session + :param pci_addr: Device pci address + :return: The directory of iommu group devices + """ + cmd = ("find /sys/kernel/iommu_groups/ -type l | xargs ls -l | awk -F " + "'/' '/%s / {print(\"\",$2,$3,$4,$5,$6)}' OFS='/' " % pci_addr) + s, o = vm_session.cmd_status_output(cmd) + LOG.debug(o) + if s: + exceptions.TestFail("Failed to find iommu group!") + return o.strip().splitlines()[-1] + + +def check_vm_iommu_group(vm_session, test_devices, orig_devices=None): + """ + Check the devices with iommu enabled are located in a separate iommu group + + :param vm_session: VM session + :param test_devices: test devices to check + :param orig_devices: The original devices + :return: The test devices' iommu group info + """ + act_devices = get_added_devices_pci(vm_session, test_devices, orig_devices) + result = {} + for dev in test_devices: + tmp_path = [] + for pci_addr in act_devices[dev]: + device_dir = get_iommu_dev_dir(vm_session, pci_addr) + s, dev_pci = vm_session.cmd_status_output("ls %s" % device_dir) + LOG.debug(f"dev pci: {dev_pci}") + if s: + exceptions.TestFail("Failed to get the device in the iommu group!") + tmp_path.append(os.path.join(device_dir, pci_addr)) + result.update({dev: tmp_path}) + return result + + +class VIOMMUTest(object): + def __init__(self, vm, test, params, session=None): + self.vm = vm + self.test = test + self.params = params + self.session = session + self.remote_virsh_dargs = None + self.controller_dicts = eval(self.params.get("controller_dicts", "[]")) + + libvirt_version.is_libvirt_feature_supported(self.params) + new_xml = vm_xml.VMXML.new_from_inactive_dumpxml(self.vm.name) + self.orig_config_xml = new_xml.copy() + + def parse_iface_dict(self): + """ + Parse iface_dict from params + + :return: The updated iface_dict + """ + mac_addr = utils_net.generate_mac_address_simple() + iface_dict = eval(self.params.get("iface_dict", "{}")) + + if self.controller_dicts and iface_dict: + iface_bus = "%0#4x" % int(self.controller_dicts[-1].get("index")) + iface_attrs = {"bus": iface_bus} + if self.controller_dicts[-1].get("model") == "pcie-to-pci-bridge": + iface_slot = libvirt_pcicontr.get_free_pci_slot( + vm_xml.VMXML.new_from_dumpxml(self.vm.name), + controller_bus=iface_bus) + iface_attrs.update({"slot": iface_slot}) + + iface_dict.update({"address": {"attrs": iface_attrs}}) + self.test.log.debug("iface_dict: %s.", iface_dict) + return iface_dict + + def prepare_controller(self): + """ + Prepare controller(s) + + :return: Updated controller attrs + """ + if not self.controller_dicts: + return + for i in range(len(self.controller_dicts)): + contr_dict = self.controller_dicts[i] + pre_controller = contr_dict.get("pre_controller") + if pre_controller: + pre_contrs = list( + filter(None, [c.get("index") for c in self.controller_dicts + if c["type"] == contr_dict["type"] and + c["model"] == pre_controller])) + if pre_contrs: + pre_idx = pre_contrs[0] + else: + pre_idx = libvirt_pcicontr.get_max_contr_indexes( + vm_xml.VMXML.new_from_dumpxml(self.vm.name), + contr_dict["type"], pre_controller)[-1] + pre_contr_bus = "%0#4x" % int(pre_idx) + contr_attrs = {"bus": pre_contr_bus} + contr_slot = libvirt_pcicontr.get_free_pci_slot( + vm_xml.VMXML.new_from_dumpxml(self.vm.name), + controller_bus=pre_contr_bus) + if contr_dict.get("model") in ["pcie-to-pci-bridge", "pcie-switch-upstream-port", "pcie-switch-downstream-port'"]: + contr_slot = "0" + contr_attrs.update({"slot": contr_slot}) + self.test.log.debug(contr_slot) + if contr_dict.get("model") in ["pcie-switch-upstream-port"]: + pci_devices = list(vm_xml.VMXML.new_from_dumpxml(self.vm.name).xmltreefile.find("devices")) + used_function = [] + for dev in pci_devices: + address = dev.find("address") + if address is not None and address.get("bus") == pre_contr_bus: + used_function.append(address.get("function")) + self.test.log.debug(contr_dict) + self.test.log.debug(f"Used function: {used_function}") + available_function = sorted(list(filter(lambda x: x not in used_function, ["%0#x" % d for d in range(8)]))) + self.test.log.debug(f"available_function: {available_function}") + contr_function = available_function[0] + contr_attrs.update({"function": contr_function}) + + contr_dict.update({"address": {"attrs": contr_attrs}}) + contr_dict.pop("pre_controller") + libvirt_vmxml.modify_vm_device( + vm_xml.VMXML.new_from_dumpxml(self.vm.name), "controller", + contr_dict, 100) + contr_dict["index"] = libvirt_pcicontr.get_max_contr_indexes( + vm_xml.VMXML.new_from_dumpxml(self.vm.name), + contr_dict["type"], contr_dict["model"])[-1] + self.controller_dicts[i] = contr_dict + + self.test.log.debug(f"Prepared controllers according to {self.controller_dicts}") + return self.controller_dicts + + def update_disk_addr(self, disk_dict): + """ + Update disk address + + :param disk_dict: The original disk attrs + :return: The updated disk attrs + """ + if self.controller_dicts: + dev_bus = self.controller_dicts[-1].get("index") + dev_attrs = {"bus": "0"} + if disk_dict["target"]["bus"] != "scsi": + dev_attrs = {"bus": dev_bus} + dev_attrs.update({"type": self.controller_dicts[-1].get("type")}) + if self.controller_dicts[-1].get("model") == "pcie-to-pci-bridge": + dev_slot = libvirt_pcicontr.get_free_pci_slot( + vm_xml.VMXML.new_from_dumpxml(self.vm.name), + controller_bus=dev_bus) + dev_attrs.update({"slot": dev_slot}) + + disk_dict.update({"address": {"attrs": dev_attrs}}) + if disk_dict["target"]["bus"] == "scsi": + disk_dict["address"]["attrs"].update({"type": "drive", "controller": dev_bus}) + + if self.controller_dicts[-1]["model"] in ["pcie-root-port", "pcie-switch-downstream-port"]: + self.controller_dicts.pop() + return disk_dict + + def setup_iommu_test(self, **dargs): + """ + iommu test environment setup + + :param dargs: Other test keywords + """ + iommu_dict = dargs.get("iommu_dict", {}) + dev_type = dargs.get("dev_type", "interface") + cleanup_ifaces = "yes" == dargs.get("cleanup_ifaces", "yes") + + if cleanup_ifaces: + libvirt_vmxml.remove_vm_devices_by_type(self.vm, "interface") + libvirt_vmxml.remove_vm_devices_by_type(self.vm, "hostdev") + if iommu_dict: + self.test.log.info("TEST_SETUP: Add iommu device.") + libvirt_virtio.add_iommu_dev(self.vm, iommu_dict) + + def teardown_iommu_test(self, **dargs): + """ + Cleanup iommu test environment + + :param dargs: Other test keywords + """ + self.test.log.info("TEST_TEARDOWN: Recover test environment.") + if self.vm.is_alive(): + self.vm.destroy(gracefully=False) + self.orig_config_xml.sync() diff --git a/provider/virtual_disk/disk_base.py b/provider/virtual_disk/disk_base.py index 6ba294dcfbe..f84a61720e5 100644 --- a/provider/virtual_disk/disk_base.py +++ b/provider/virtual_disk/disk_base.py @@ -1,5 +1,7 @@ import logging import os +import re +import time from avocado.utils import lv_utils from avocado.utils import process @@ -48,6 +50,7 @@ def __init__(self, test, vm, params): self.new_image_path = '' self.path_list = '' self.disk_backend = '' + self.disk_size = "50M" @staticmethod def get_source_list(vmxml, disk_type, target_dev): @@ -73,12 +76,17 @@ def get_source_list(vmxml, disk_type, target_dev): backing_list = disk.get_backingstore_list() if disk_type != 'rbd_with_auth' and backing_list != []: backing_list.pop() - source_list = [elem.find('source').get('file') or - elem.find('source').get('name') or - elem.find('source').get('dev') or - elem.find('source').get('volume') - for elem in backing_list - if elem.find("source") is not None] + for elem in backing_list: + source_ele = elem.find("source") + if source_ele is not None: + source_list.append(source_ele.get('file') or + source_ele.get('name') or + source_ele.get('dev') or + source_ele.get('volume')) + if source_ele.find("dataStore"): + source_list.append( + source_ele.find("dataStore").find('source').get('file')) + source_list.insert(0, active_level_path) break @@ -120,15 +128,21 @@ def prepare_disk_obj(self, disk_type, disk_dict, new_image_path='', **kwargs): size = kwargs.get("size", "50M") if kwargs.get("size"): kwargs.pop("size") - libvirt.create_local_disk("file", path=new_image_path, size=size, - disk_format=self.params.get("disk_image_format", 'qcow2'), - **kwargs) + libvirt.create_local_disk( + "file", path=new_image_path, size=size, + disk_format=self.params.get("disk_image_format", 'qcow2'), + **kwargs) disk_dict.update({'source': {'attrs': {'file': new_image_path}}}) elif disk_type == 'block': if not new_image_path: new_image_path = self.create_lvm_disk_path( - vg_name=self.vg_name, lv_name=self.lv_name, **kwargs) + vg_name=self.vg_name, lv_name=self.lv_name, + simulated_iscsi=self.params.get("simulated_iscsi"), **kwargs) + if self.params.get('convert_format'): + process.run("qemu-img create -f %s /dev/%s/%s %s" % ( + self.params.get('convert_format'), self.vg_name, + self.lv_name, self.disk_size), shell=True) disk_dict.update({'source': {'attrs': {'dev': new_image_path}}}) elif disk_type == 'volume': @@ -146,7 +160,7 @@ def prepare_disk_obj(self, disk_type, disk_dict, new_image_path='', **kwargs): new_image_path = nfs_res['mount_dir'] + '/test.img' libvirt.create_local_disk("file", path=new_image_path, - size='50M', + size=self.disk_size, disk_format="qcow2", **kwargs) disk_dict.update({'source': {'attrs': {'file': new_image_path}}}) @@ -163,6 +177,17 @@ def prepare_disk_obj(self, disk_type, disk_dict, new_image_path='', **kwargs): "auth": {"auth_user": auth_username, "secret_usage": "cephlibvirt", "secret_type": "ceph"}}}) + elif disk_type == 'rbd_with_luks_and_auth': + mon_host, auth_username, new_image_path, _ = \ + self.create_rbd_disk_path(self.params, create_img_by_qemu_cmd=True) + disk_dict.update({'source': { + 'attrs': {'protocol': "rbd", "name": new_image_path}, + "hosts": [{"name": mon_host}], + "auth": {"auth_user": auth_username, + "secret_usage": self.params.get("ceph_usage_name"), + "secret_type": "ceph"}}}) + self.add_luks_encryption_to_disk_dict( + disk_dict, self.params.get("luks_sec_dict") % new_image_path) elif disk_type == "nbd": nbd_server_host = process.run('hostname', ignore_status=False, @@ -193,19 +218,63 @@ def prepare_disk_obj(self, disk_type, disk_dict, new_image_path='', **kwargs): "port": nbd_server_port}]}, }) + elif disk_type == "ssh_with_key": + new_image_path, known_hosts_path, keyfile = \ + self.create_ssh_disk_path(self.params, **kwargs) + ssh_user = os.environ.get("USER") + disk_dict.update( + {'source': {"attrs": {"protocol": "ssh", + "name": new_image_path}, + "identity": [{"username": "%s" % ssh_user, + "keyfile": keyfile}], + "knownhosts": known_hosts_path, + "hosts": [{"name": "127.0.0.1", + "port": "22"}]}}) + + elif disk_type == "ssh_with_passwd": + new_image_path, known_hosts_path, _ = \ + self.create_ssh_disk_path(self.params, **kwargs) + disk_dict.update( + {'source': {"attrs": {"protocol": "ssh", + "name": new_image_path}, + "knownhosts": known_hosts_path, + "hosts": [{"name": "127.0.0.1", + "port": "22"}], + "auth": {"auth_user": self.params.get("iscsi_user"), + "secret_usage": "libvirtiscsi", + "secret_type": "iscsi"}}}) + disk_obj = libvirt_vmxml.create_vm_device_by_type("disk", disk_dict) self.test.log.debug('Create disk object is :%s', disk_obj) return disk_obj, new_image_path - def cleanup_disk_preparation(self, disk_type): + def add_luks_encryption_to_disk_dict(self, disk_dict, secret_dict): + """ + Add luks encryption to disk dict. + + :param disk_dict: disk dict. + :param secret_dict: secret dict to define a secret. + """ + sec_uuid = libvirt_secret.create_secret(sec_dict=eval(secret_dict)) + virsh.secret_set_value(sec_uuid, self.params.get("secret_pwd"), + debug=True, ignore_status=False) + disk_source = disk_dict["source"] + disk_source.update( + {"encryption": {"secret": {"type": "passphrase", "uuid": sec_uuid}, + "encryption": "luks", "attrs": {"engine": "librbd"}}}) + return disk_dict + + def cleanup_disk_preparation(self, disk_type, **kwargs): """ Clean up the preparation of different type disk :param disk_type: disk type """ if disk_type == 'block': - self.cleanup_block_disk_preparation(self.vg_name, self.lv_name) + self.cleanup_block_disk_preparation( + self.vg_name, self.lv_name, + simulated_iscsi=self.params.get("simulated_iscsi")) elif disk_type == 'file': if os.path.exists(self.new_image_path): @@ -219,7 +288,7 @@ def cleanup_disk_preparation(self, disk_type): elif disk_type == 'nfs': libvirt.setup_or_cleanup_nfs(is_setup=False) - elif disk_type == "rbd_with_auth": + elif disk_type in ["rbd_with_auth", "rbd_with_luks_and_auth"]: self.cleanup_rbd_disk_path(self.params) elif disk_type == "nbd": @@ -228,19 +297,28 @@ def cleanup_disk_preparation(self, disk_type): except Exception as ndbEx: self.test.log.debug("Clean Up nbd failed: %s", str(ndbEx)) + elif disk_type == "ssh_with_key" or disk_type == "ssh_with_passwd": + self.cleanup_ssh_disk_path(self.new_image_path, **kwargs) + @staticmethod - def cleanup_block_disk_preparation(vg_name, lv_name): + def cleanup_block_disk_preparation(vg_name, lv_name, **kwargs): """ Clean up volume group, logical volume, iscsi target. - :params vg_name: volume group name - :params lv_name: volume name + :param vg_name: volume group name + :param lv_name: volume name + :param kwargs: optional keyword arguments. """ lv_utils.lv_remove(vg_name, lv_name) lv_utils.vg_remove(vg_name) - libvirt.setup_or_cleanup_iscsi(is_setup=False) - if os.path.exists('/dev/%s' % vg_name): - os.rmdir('/dev/%s' % vg_name) + if kwargs.get("simulated_iscsi"): + time.sleep(3) + process.run("modprobe %s -r" % re.findall( + r"modprobe (\S+)", kwargs.get("simulated_iscsi"))[0]) + else: + libvirt.setup_or_cleanup_iscsi(is_setup=False) + if os.path.exists('/dev/%s' % vg_name): + os.rmdir('/dev/%s' % vg_name) @staticmethod def create_volume_for_disk_path(test, params, pool_name='pool_name', @@ -282,16 +360,34 @@ def create_lvm_disk_path(vg_name='vg0', lv_name='lv0', **kwargs): :params lv_name: volume name :return path: path for disk image """ - device_name = libvirt.setup_or_cleanup_iscsi(is_setup=True) + if kwargs.get("simulated_iscsi"): + process.run(kwargs.get("simulated_iscsi"), shell=True) + device_name = get_simulated_iscsi() + else: + device_name = libvirt.setup_or_cleanup_iscsi(is_setup=True) lv_utils.vg_create(vg_name, device_name) size = kwargs.get("size", "200M") if kwargs.get("size"): kwargs.pop("size") path = libvirt.create_local_disk("lvm", size=size, vgname=vg_name, - lvname=lv_name, **kwargs) + lvname=lv_name) return path + @staticmethod + def cleanup_ssh_disk_path(new_image_path, **kwargs): + """ + Clean up ssh disk image + + :params new_image_path: the new image path. + :param kwargs: optional keyword arguments. + """ + keyfile = kwargs.get("keyfile") + known_hosts_path = kwargs.get("known_hosts_path") + for file in [keyfile, f"{keyfile}.pub", known_hosts_path, new_image_path]: + if os.path.exists(file): + os.remove(file) + @staticmethod def cleanup_rbd_disk_path(params): """ @@ -311,11 +407,13 @@ def cleanup_rbd_disk_path(params): os.remove(params.get('configfile')) @staticmethod - def create_rbd_disk_path(params): + def create_rbd_disk_path(params, create_img_by_qemu_cmd=False): """ Prepare rbd type disk image path :params params: Dict with the test parameters. + :params create_img_by_qemu_cmd: The flag for whether creating rbd type + image by qemu, default False :return: tuple, include monitor host, auth username, new image path and secret uuid """ @@ -337,13 +435,61 @@ def create_rbd_disk_path(params): sec_uuid = libvirt_secret.create_secret(sec_dict=sec_dict) virsh.secret_set_value(sec_uuid, auth_key, debug=True) - ceph.rbd_image_rm(mon_host, new_image_path.split("/")[0], - new_image_path.split("/")[1]) - ceph.rbd_image_create(mon_host, new_image_path.split("/")[0], - new_image_path.split("/")[1], rbd_image_size) + if not create_img_by_qemu_cmd: + ceph.rbd_image_rm(mon_host, new_image_path.split("/")[0], + new_image_path.split("/")[1]) + ceph.rbd_image_create(mon_host, new_image_path.split("/")[0], + new_image_path.split("/")[1], rbd_image_size) + else: + libvirt.create_local_disk( + disk_type="file", path='', + extra=params.get("rbd_image_parameter").format( + new_image_path, auth_username, auth_key, mon_host), + disk_format=params.get("rbd_image_format"), size=rbd_image_size) return mon_host, auth_username, new_image_path, sec_uuid + @staticmethod + def create_ssh_disk_path(params, **kwargs): + """ + Prepare ssh type disk image path + + :params params: Dict with the test parameters. + :param kwargs: optional keyword arguments. + :params return: tuple, include new_image_path, known_hosts_path and keyfile. + """ + authorized_path = "/root/.ssh/authorized_keys" + sec_dict = eval(params.get("sec_dict", "{}")) + secret_pwd = params.get("secret_pwd") + new_image_path = params.get("new_image_path") + with_secret_passwd = "yes" == params.get("with_secret_passwd", "no") + + if not new_image_path: + new_image_path = data_dir.get_data_dir() + '/test.img' + size = kwargs.get("size", "50M") + if kwargs.get("size"): + kwargs.pop("size") + libvirt.create_local_disk( + "file", path=new_image_path, size=size, + disk_format=params.get("disk_image_format", 'qcow2')) + + keyfile = kwargs.get("keyfile") + known_hosts_path = kwargs.get("known_hosts_path") + for file in [keyfile, f"{keyfile}.pub", known_hosts_path]: + if os.path.exists(file): + os.remove(file) + + process.run("ssh-keygen -t rsa -q -N '' -f %s" % keyfile, shell=True) + process.run("ssh-keyscan -p 22 127.0.0.1 >> %s" % known_hosts_path, shell=True) + process.run("cat %s >> %s" % (f"{keyfile}.pub", authorized_path), shell=True) + + if with_secret_passwd: + libvirt_secret.clean_up_secrets() + sec_uuid = libvirt_secret.create_secret(sec_dict=sec_dict) + virsh.secret_set_value(sec_uuid, secret_pwd, + debug=True, ignore_status=False) + return new_image_path, known_hosts_path, keyfile + def prepare_relative_path(self, disk_type, **kwargs): """ Prepare relative path @@ -483,3 +629,14 @@ def prepare_backing_file(self, disk_type, backing_file_type, backing_format): process.run(backing_cmd, shell=True, verbose=True) return based_image, backing_file + + +def get_simulated_iscsi(): + """ + Get simulated iscsi device. + + :return simulated iscsi device name. + """ + res = process.run("lsscsi", shell=True).stdout_text.strip() + device_name = re.findall(r"Linux\s*scsi_debug\s*\d+\s+(\S+)\s*", res)[0] + return device_name diff --git a/provider/virtual_network/network_base.py b/provider/virtual_network/network_base.py index 0271f32c141..97cc290bbbc 100644 --- a/provider/virtual_network/network_base.py +++ b/provider/virtual_network/network_base.py @@ -1,24 +1,64 @@ import logging +import math +import re import shutil import aexpect - from avocado.core import exceptions from avocado.utils import process - from virttest import remote +from virttest import utils_misc from virttest import utils_net +from virttest import utils_package from virttest import virsh - from virttest.libvirt_xml import network_xml +from virttest.libvirt_xml import vm_xml VIRSH_ARGS = {'ignore_status': False, 'debug': True} LOG = logging.getLogger('avocado.' + __name__) +def get_vm_ip(session, mac, ip_ver="ipv4", timeout=5, ignore_error=False): + """ + Get vm ip address + + :param session: vm session + :param mac: mac address of vm + :param ip_ver: ip version, defaults to "ipv4" + :param ignore_error: True to return None, False to raise exception, + defaults to False + :return: ip address of given mac + """ + def _get_vm_ip(): + iface_info = utils_net.get_linux_iface_info(mac=mac, session=session) + addr_list = iface_info['addr_info'] + if ip_ver == "ipv4": + target_addr = [addr for addr in addr_list if addr['family'] == 'inet'] + elif ip_ver == "ipv6": + target_addr = [addr for addr in addr_list if addr['family'] == 'inet6' + and addr['scope'] == 'global' + and addr.get('mngtmpaddr') is not True] + + if len(target_addr) == 0: + LOG.warning(f'No ip addr of given mac: {mac}') + return + elif len(target_addr) > 1: + LOG.warning(f'Multiple ip addr: {target_addr}') + + return target_addr[0]['local'] + + vm_ip = utils_misc.wait_for(_get_vm_ip, timeout, ignore_errors=True) + + if not vm_ip and not ignore_error: + raise exceptions.TestError( + f'Cannot find {ip_ver} addr with given mac: {mac}') + + return vm_ip + + def get_test_ips(session, mac, ep_session, ep_mac, net_name=None, - ip_ver='ipv4'): + ip_ver='ipv4', host_iface=None): """ Get ips including vm ip, endpoint ip, host ip @@ -28,13 +68,18 @@ def get_test_ips(session, mac, ep_session, ep_mac, net_name=None, :param ep_mac: mac address of endpoint vm :param net_name: name of virtual network :param ip_ver: ip version, ipv4/ipv6 + :param host_iface: Host interface :return: a dict of ip addresses """ ips = {} - ips['vm_ip'], ips['ep_vm_ip'] = [utils_net.get_guest_ip_addr( - sess, mac_ad, ip_version=ip_ver) - for sess, mac_ad in [(session, mac), (ep_session, ep_mac)]] - ips['host_public_ip'] = utils_net.get_host_ip_address(ip_ver=ip_ver) + ips['vm_ip'] = get_vm_ip(session, mac, ip_ver=ip_ver) + ips['ep_vm_ip'] = get_vm_ip(ep_session, ep_mac, ip_ver=ip_ver) + if not host_iface: + host_public_ip = utils_net.get_host_ip_address(ip_ver=ip_ver) + else: + host_public_ip = utils_net.get_ip_address_by_interface(host_iface, + ip_ver=ip_ver) + ips['host_public_ip'] = host_public_ip if net_name: net_inst = network_xml.NetworkXML.new_from_net_dumpxml(net_name) @@ -57,20 +102,15 @@ def ping_check(params, ips, session=None, force_ipv4=True, **args): :param force_ipv4: whether to force ping with ipv4 :param args: other kwargs """ - outside_ip = ips.get('outside_ip') - vm_ip = ips.get('vm_ip') - ep_vm_ip = ips.get('ep_vm_ip') - host_public_ip = ips.get('host_public_ip') - host_virbr_ip = ips.get('host_virbr_ip') - outside_ip = ips.get('outside_ip') ping_patterns = {k: v for k, v in params.items() if '_ping_' in k} + failures = [] for pattern, expect_result in ping_patterns.items(): source, destination = pattern.split('_ping_') if destination == 'outside' and not force_ipv4: LOG.debug('No need to test ping outside with ipv6') continue - dest_ip = eval(f'{destination}_ip') + dest_ip = ips.get(f'{destination}_ip') if dest_ip is None: raise exceptions.TestError(f'IP of {destination} is None') @@ -79,22 +119,33 @@ def ping_check(params, ips, session=None, force_ipv4=True, **args): LOG.info(f'TEST_STEP: Ping from {source} to {destination} ' f'(ip: {dest_ip})') ping_session = session if source == 'vm' else None - status, _ = utils_net.ping(dest=dest_ip, count=5, - timeout=10, - session=ping_session, - force_ipv4=force_ipv4, - **ping_args) + + def _ping(): + """ Helper function to make use of wait_for """ + status, output = utils_net.ping(dest=dest_ip, count=5, + timeout=10, + session=ping_session, + force_ipv4=force_ipv4, + **ping_args) + if status and "unreachable" in output and expect_result == 'pass': + return False + return status == 0 + + status = utils_misc.wait_for(_ping, timeout=15) + ping_result = (status is True) == (expect_result == 'pass') msg = f'Expect ping from {source} to {destination} should ' \ f'{expect_result.upper()}, actual result is ' \ - f'{"PASS" if status == 0 else "FAIL"}' - ping_result = (status == 0) == (expect_result == 'pass') + f'{"PASS" if ping_result else "FAIL"}' if ping_result: LOG.debug(msg) else: - raise exceptions.TestFail(msg) + LOG.error(msg) + failures.append(msg) + if failures: + raise exceptions.TestFail('.'.join(failures)) -def create_tap(tap_name, bridge_name, user): +def create_tap(tap_name, bridge_name, user, flag=''): """ Create tap device @@ -104,7 +155,7 @@ def create_tap(tap_name, bridge_name, user): """ # Create tap device with ip command tap_cmd = f'ip tuntap add mode tap user {user} group {user} name ' \ - f'{tap_name};ip link set {tap_name} up;' \ + f'{tap_name} {flag};ip link set {tap_name} up;' \ f'ip link set {tap_name} master {bridge_name}' # Execute command as root process.run(tap_cmd, shell=True, verbose=True) @@ -127,6 +178,8 @@ def create_macvtap(macvtap_name, iface, user): tap_index = process.run(cmd_get_tap, shell=True).stdout_text.strip() device_path = f'/dev/tap{tap_index}' logging.debug(f'device_path: {device_path}') + # Check the current permissions + process.run('ls -l %s' % device_path, shell=True) # Change owner and group for device process.run(f'chown {user} {device_path};chgrp {user} {device_path}', shell=True) @@ -256,3 +309,151 @@ def set_static_ip(iface, ip, netmask, session): """ session.cmd('systemctl stop NetworkManager'), session.cmd(f'ifconfig {iface} {ip}/{netmask}') + + +def get_iface_xml_inst(vm_name, comment, index=0, options='', virsh_ins=virsh): + """ + Get iface xml instance with given vm and index + + :param vm_name: name of vm + :param comment: comment to log + :param index: index of interface on vm, defaults to 0 + :return: xml instance of interface + """ + vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name, options=options, + virsh_instance=virsh_ins) + iface = vmxml.get_devices('interface')[index] + LOG.debug(f'Interface xml ({comment}):\n{iface}') + return iface + + +def get_ethtool_coalesce(iface): + """ + Get coalesce parameters from ethtool command output + + :param iface: interface name + :return: dict-type coalesce parameters + """ + eth_out = process.run(f'ethtool -c {iface}').stdout_text + eth_out = re.sub("[\t ]+", "", eth_out) + eth_out = re.sub("n/a", "0", eth_out) + items = [x.split(':') for x in eth_out.splitlines() if x] + coalesce = {item[0]: item[1].strip() for item in items[1:] if len(item) == 2} + + return coalesce + + +def check_iface_attrs(iface, key, expect_val): + """ + Check whether interface attribute value meets expectation + + :param iface: interface name + :param key: interface attribute key + :param expect_val: expect attribute value + """ + actual_val = iface.fetch_attrs().get(key) + LOG.debug(f'Expect {key}: {expect_val}\n' + f'Actual {key}: {actual_val}') + if actual_val != expect_val: + raise exceptions.TestFail(f'Updated {key} of iface should be ' + f'{expect_val}, NOT {actual_val}') + + +def check_throughput(serv_runner, cli_runner, ip_addr, bw, th_type): + """ + Check actual thoughput of network using netperf + + :param serv_runner: runner of netserver + :param cli_runner: runner of netperf client + :param ip_addr: ip address + :param bw: bandwidth setting + :param th_type: inbound or outbound + """ + + serv_runner('netserver') + netperf_out = cli_runner(f'netperf -H {ip_addr}') + LOG.debug(netperf_out) + serv_runner('pkill netserver') + + actual_throu = float(netperf_out.strip().splitlines()[-1].split()[-1]) + expect_throu = int(bw) * 8 / 1024 + + msg = f'Expected {th_type}: {expect_throu}, actual {th_type}: {actual_throu}' + if not math.isclose(expect_throu, actual_throu, rel_tol=0.1): + raise exceptions.TestFail(f'Actual {th_type} is not close to expected ' + f'{th_type}:\n{msg}') + LOG.debug(msg) + + +def exec_netperf_test(params, env): + """ + Verify the guest can work well under the netperf stress test + + :param params: Dictionary with the test parameters. + :param env: Dictionary with test environment. + """ + netperf_client = params.get("netperf_client") + netperf_server = params.get("netperf_server") + extra_cmd_opts = params.get("extra_cmd_opts", "") + netperf_timeout = params.get("netperf_timeout", "60") + test_protocol = params.get("test_protocol") + vms = params.get('vms').split() + vm_objs = {vm_i: env.get_vm(vm_i) for vm_i in vms} + before_test_cores = process.run("coredumpctl list", ignore_status=True, verbose=True).stdout_text + + def _get_access_info(netperf_address): + LOG.debug(f"check {netperf_address}...") + session = None + if re.match(r"((\d){1,3}\.){3}(\d){1,3}", netperf_address): + func = process.run + test_ip = netperf_address + else: + if netperf_address not in vms: + raise exceptions.TestError(f"Unable to get {netperf_address} from {vms}!") + vm = vm_objs.get(netperf_address) + if not vm.is_alive(): + vm.start() + session = vm.wait_for_login() + test_ip = vm.get_address() + func = session.cmd + return func, test_ip, session + + c_func, c_ip, c_session = _get_access_info(netperf_client) + s_func, s_ip, s_session = _get_access_info(netperf_server) + + try: + if not utils_package.package_install("netperf", c_session): + raise exceptions.TestError("Unable to install netperf in the client host!") + if not utils_package.package_install("netperf", s_session): + raise exceptions.TestError("Unable to install netperf in the server host!") + c_func("systemctl stop firewalld") + s_func("systemctl stop firewalld") + + LOG.debug("Start netserver...") + if s_ip == netperf_server: + s_func("killall netserver", ignore_status=True) + s_func("netserver") + + LOG.debug("Run netperf command...") + test_cmd = f"netperf -H {s_ip} -l {netperf_timeout} -C -c -t {test_protocol} {extra_cmd_opts}" + c_func(test_cmd, timeout=120) + + for vm in vm_objs.values(): + try: + vm.wait_for_login().close() + except (remote.LoginError, aexpect.ShellError) as e: + LOG.error(f"Unable to access to {vm.name}, guest os may have crashed - {e}") + vm.destroy() + vm.start() + vm.wait_for_login().close() + after_test_cores = process.run("coredumpctl list", + ignore_status=True, verbose=True).stdout_text + if after_test_cores != before_test_cores: + raise exceptions.TestFail("There are coredump files during the test!") + + finally: + LOG.info("Test teardown: Cleanup env.") + s_func("killall netserver") + s_func("systemctl start firewalld") + # TODO: Start firewalld on guest + process.run("systemctl start firewalld", ignore_status=True) diff --git a/provider/virtual_network/passt.py b/provider/virtual_network/passt.py index 5bcaa2f7a1d..4a9468b302a 100644 --- a/provider/virtual_network/passt.py +++ b/provider/virtual_network/passt.py @@ -1,6 +1,8 @@ import logging import os import random +import re +import time from socket import socket import aexpect @@ -136,8 +138,8 @@ def check_proc_info(params, log_file, mac): socket_dir = params.get('socket_dir') host_iface = params.get('host_iface') - host_iface = host_iface if host_iface else utils_net.get_net_if( - state="UP")[0] + host_iface = host_iface if host_iface else utils_net.get_default_gateway( + iface_name=True, force_dhcp=True, json=True) proc_info = get_proc_info('passt') LOG.debug(proc_info) @@ -156,7 +158,6 @@ def check_proc(target): failed_check.append(f'{target} should be in process CMD') check_list = [ - f'--mac-addr {mac}', f'--interface {host_iface}', f'--log-file {log_file}', f'--socket {socket_dir}', @@ -170,15 +171,17 @@ def check_proc(target): raise exceptions.TestFail(';'.join(failed_check)) -def check_vm_ip(iface_attrs, session, host_iface): +def check_vm_ip(iface_attrs, session, host_iface, vm_iface=None): """ Check if vm ip and prefix meet expectation :param iface_attrs: attributes of interface :param session: shell session instance of vm :param host_iface: host interface + :param vm_iface: VM interface, can be omitted on x86_64 """ - vm_iface = 'eno' + iface_attrs.get('acpi', {'index': '1'})['index'] + if not vm_iface: + vm_iface = 'eno' + iface_attrs.get('acpi', {'index': '1'})['index'] vm_ip, prefix = get_iface_ip_and_prefix(vm_iface, session=session) LOG.debug(f'VM ip and prefix: {vm_ip}, {prefix}') if 'ips' in iface_attrs: @@ -198,7 +201,13 @@ def check_vm_ip(iface_attrs, session, host_iface): raise exceptions.TestFail('vm ip and prefix should be ' 'the same as host') - set_ipv6_info = get_iface_ip_and_prefix(host_iface, ip_ver='ipv6')[0] + host_ipv6_info = get_iface_ip_and_prefix(host_iface, ip_ver='ipv6') + # If the host does not support IPv6, the guest will not support it either, cancel the test + if host_ipv6_info: + set_ipv6_info = host_ipv6_info[0] + else: + raise exceptions.TestCancel(f'Host ipv6 is not available, skip the test!') + # The settings in attrs should take precedence if there is if 'ips' in iface_attrs: iface_ipv6_info = [ip for ip in iface_attrs['ips'] if ip['family'] == 'ipv6'][0] @@ -231,23 +240,44 @@ def check_vm_mtu(session, iface, mtu): raise exceptions.TestFail(f'Wrong vm mtu: {vm_mtu}, should be {mtu}') -def check_default_gw(session): +def check_default_gw(session, host_iface=None, multiple_nexthops=False): """ - Check whether default host gateways of host and guest are consistent + Check whether default host gateways of host and guest are consistent, + i.e. the guest's gateways are available on the host. :param session: vm shell session instance - """ - host_gw = utils_net.get_default_gateway(force_dhcp=True) - vm_gw = utils_net.get_default_gateway(session=session, force_dhcp=True) + :param host_iface: if given, only check gateway information on this + host interface + """ + LOG.debug(f'Get host default ipv4 gateway') + host_gw = utils_net.get_default_gateway( + force_dhcp=True, target_iface=host_iface, json=True, multiple_nexthops=multiple_nexthops) + LOG.debug(f'Get guest default ipv4 gateway') + vm_gw = utils_net.get_default_gateway( + session=session, force_dhcp=True, json=True, multiple_nexthops=multiple_nexthops) LOG.debug(f'Host and vm default ipv4 gateway: {host_gw}, {vm_gw}') - host_gw_v6 = utils_net.get_default_gateway(ip_ver='ipv6') - vm_gw_v6 = utils_net.get_default_gateway(session=session, ip_ver='ipv6') - LOG.debug(f'Host and vm default ipv6 gateway: {host_gw_v6}, {vm_gw_v6}') - - if host_gw != vm_gw: + if [x for x in vm_gw if x not in host_gw]: raise exceptions.TestFail( 'Host default ipv4 gateway not consistent with vm.') - if host_gw_v6 != vm_gw_v6: + LOG.debug(f'Get host default ipv6 gateway') + _host_gw_v6 = utils_net.get_default_gateway(ip_ver='ipv6', + target_iface=host_iface, + json=True, + multiple_nexthops=multiple_nexthops) + if not _host_gw_v6: + raise exceptions.TestFail('Guest has no ipv6 gateway!') + LOG.debug(f'Get guest default ipv6 gateway') + vm_gw_v6 = utils_net.get_default_gateway(session=session, + ip_ver='ipv6', + json=True, + multiple_nexthops=multiple_nexthops) + if not vm_gw_v6: + raise exceptions.TestFail('Guest has no ipv6 gateway!') + host_gw_v6 = _host_gw_v6 if isinstance(_host_gw_v6, list) else [_host_gw_v6] + vm_gw_v6 = vm_gw_v6 if isinstance(vm_gw_v6, list) else [vm_gw_v6] + LOG.debug(f'Host and vm default ipv6 gateway: {host_gw_v6}, {vm_gw_v6}') + + if [x for x in vm_gw_v6 if x not in host_gw_v6]: raise exceptions.TestFail( 'Host default ipv6 gateway not consistent with vm.') @@ -261,6 +291,16 @@ def check_nameserver(session): get_cmd = 'cat /etc/resolv.conf|grep -vE "#|;"' on_host = process.run(get_cmd, shell=True).stdout_text.strip() on_vm = session.cmd_output(get_cmd).strip() + LOG.debug(f'Output on host:\n{on_host}\nOutput on vm:\n{on_vm}') + # remove zone index + on_host = [re.sub(r'%.*', '', x) for x in on_host.split()] + on_vm = [re.sub(r'%.*', '', x) for x in on_vm.split()] + # Remove irrelevant items such as "search" + on_host = set([(on_host[i], on_host[i + 1]) for i in range(len(on_host)) + if on_host[i].lower() == 'nameserver']) + on_vm = set([(on_vm[i], on_vm[i + 1]) for i in range(len(on_vm)) + if on_vm[i].lower() == 'nameserver']) + LOG.debug(f'On host:\n{on_host}\nOn vm:\n{on_vm}') if on_host == on_vm: LOG.debug(f'Nameserver on vm is consistent with host:\n{on_host}') else: @@ -294,6 +334,7 @@ def check_protocol_connection(src_sess, tar_sess, protocol, addr, cmd_listen = f'socat {protocol}-LISTEN:{tar_port} -' LOG.debug(cmd_listen) tar_sess.sendline(cmd_listen) + time.sleep(1) msg = f'Message {utils_misc.generate_random_string(6)} '\ f'from source via {protocol}' if src_iface: @@ -321,20 +362,26 @@ def check_protocol_connection(src_sess, tar_sess, protocol, addr, f'actually is {conneted}') -def check_connection(vm, vm_iface, protocols): +def check_connection(vm, vm_iface, protocols, host_iface=None): """ Check connection of vm and host :param vm: vm instance :param vm_iface: interface of vm :param protocols: protocols to check - """ - default_gw = utils_net.get_default_gateway(force_dhcp=True) - default_gw_v6 = utils_net.get_default_gateway(ip_ver='ipv6') + :param host_iface: host interface to get default gw for + if ommitted all default routes are returned + """ + default_gw = utils_net.get_default_gateway( + force_dhcp=True, target_iface=host_iface, json=True + ) + vm_session = vm.wait_for_serial_login() + default_gw_v6_vm = utils_net.get_default_gateway( + session=vm_session, ip_ver='ipv6', json=True) for protocol in protocols: host_sess = aexpect.ShellSession('su') vm_sess = vm.wait_for_serial_login(timeout=60) - gw = default_gw if protocol[-1] == '4' else default_gw_v6 + gw = default_gw if protocol[-1] == '4' else default_gw_v6_vm src_iface = None if protocol[-1] == '4' else vm_iface try: check_protocol_connection(vm_sess, host_sess, protocol, gw, @@ -380,7 +427,7 @@ def check_port_listen(ports, protocol, host_ip=None): """ if protocol.lower() not in ('tcp', 'udp'): raise exceptions.TestError(f'Unsupported protocol: {protocol}') - cmd_listen = process.run(f"ss -{protocol[0].lower()}lpn|egrep 'passt.avx2'", + cmd_listen = process.run(f"ss -{protocol[0].lower()}lpn|egrep 'passt'", shell=True).stdout_text for item in ports: if item in cmd_listen: @@ -390,13 +437,14 @@ def check_port_listen(ports, protocol, host_ip=None): 'listened to') -def check_portforward(vm, host_ip, params): +def check_portforward(vm, host_ip, params, host_iface=None): """ Check function for portforward :param vm: vm instance :param host_ip: host ipv4 address :param params: test params + :param host_iface: host interface for passt """ host_ip_v6 = params.get('host_ip_v6') tcp_port_list = eval(params.get('tcp_port_list', '[]')) @@ -426,6 +474,7 @@ def check_passt_pid_not_exist(): pid_passt = process.run('pidof passt', ignore_status=True).stdout_text.strip() if pid_passt: + utils_misc.kill_process_tree(pid_passt) raise exceptions.TestFail(f'Process of passt still exists: ' f'{pid_passt}') diff --git a/provider/virtual_network/tftpboot.py b/provider/virtual_network/tftpboot.py new file mode 100644 index 00000000000..6b3d14dfabe --- /dev/null +++ b/provider/virtual_network/tftpboot.py @@ -0,0 +1,109 @@ +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# See LICENSE for more details. +# +# Copyright: Red Hat Inc. 2024 +# Author: Sebastian Mitterle +import logging as log +import os + +from avocado.utils import process +from virttest import virsh +from virttest.utils_test import libvirt + +logging = log.getLogger("avocado." + __name__) + +tftp_dir = "/var/lib/tftpboot" +boot_file = "pxelinux.cfg" +net_name = "tftpnet" + +cleanup_actions = [] + + +def create_tftp_content(install_tree_url, kickstart_url, arch): + """ + Creates the folder for the tftp server, + downloads images assuming they are below /images, + and creates the pxe configuration file + + :param install_tree_url: url of the installation tree + :param kickstart_url: url of the kickstart file + :param arch: the architecture + """ + + if arch != "s390x": + raise NotImplementedError(f"No implementation available for '{arch}'.") + + process.run("mkdir " + tftp_dir, ignore_status=False, shell=True, verbose=True) + cleanup_actions.insert(0, lambda: process.run("rm -rf " + tftp_dir, ignore_status=False, shell=True, verbose=True)) + + pxeconfig_content = """# pxelinux +default linux +label linux +kernel kernel.img +initrd initrd.img +""" + kernel_cmdline = ("append ip=dhcp inst.repo=%s inst.noverifyssl" + % install_tree_url) + if kickstart_url: + kernel_cmdline += " inst.ks=%s" % kickstart_url + else: + logging.debug("Create pxelinux.cfg without kickstart.") + pxeconfig_content += kernel_cmdline + + with open(os.path.join(tftp_dir, boot_file), "w") as f: + f.write(pxeconfig_content) + + cmds = [] + + initrd_img_url = install_tree_url + "/images/initrd.img" + kernel_img_url = install_tree_url + "/images/kernel.img" + + cmds.append("curl %s -o %s/initrd.img" % (initrd_img_url, tftp_dir)) + cmds.append("curl %s -o %s/kernel.img" % (kernel_img_url, tftp_dir)) + + cmds.append("chmod -R a+r " + tftp_dir) + cmds.append("chown -R nobody: " + tftp_dir) + cmds.append("chcon -R --reference /usr/sbin/dnsmasq " + tftp_dir) + cmds.append("chcon -R --reference /usr/libexec/libvirt_leaseshelper " + tftp_dir) + + for cmd in cmds: + process.run(cmd, ignore_status=False, shell=True, verbose=True) + + +def create_tftp_network(): + """ + Creates a libvirt network that will serve + the tftp content + """ + + net_params = { + "net_forward": "{'mode':'nat'}", + "net_ip_address": "192.168.150.1", + "dhcp_start_ipv4": "192.168.150.2", + "dhcp_end_ipv4": "192.168.150.254", + "tftp_root": tftp_dir, + "bootp_file": boot_file + } + + net_xml = libvirt.create_net_xml(net_name, net_params) + virsh.net_create(net_xml.xml, debug=True, ignore_status=False) + cleanup_actions.insert(0, lambda: virsh.net_destroy(net_name)) + + +def cleanup(): + """ + Runs registered clean up actions + """ + for action in cleanup_actions: + try: + action() + except: + logging.debug("There were errors during cleanup. Please check the log.") diff --git a/requirements-travis.txt b/requirements-travis.txt index ad5bff09681..baa31f9a5af 100644 --- a/requirements-travis.txt +++ b/requirements-travis.txt @@ -1,10 +1,14 @@ coverage==5.1 nose==1.3.0 nosexcover==1.0.8 -tox==1.5.0 -virtualenv==1.9.1 +tox==1.5.0; python_version < '3.8' +tox==4.16.0; python_version > '3.7' +virtualenv==1.9.1; python_version < '3.8' +virtualenv==20.26.6; python_version > '3.7' simplejson==3.8.1 -inspektor==0.5.2 -pylint==2.11.1 +inspektor==0.5.2; python_version < '3.8' +inspektor==0.5.3; python_version > '3.7' +pylint==2.11.1; python_version < '3.8' +pylint==3.2.6; python_version > '3.7' pyenchant importlib-metadata==4.13.0; python_version == '3.7' diff --git a/requirements.txt b/requirements.txt index 166d4a0dcb9..2c8964b2416 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,4 +2,4 @@ coverage==3.6 nose==1.3.0 nosexcover==1.0.8 tox==1.5.0 -virtualenv==1.9.1 +virtualenv==20.26.6 diff --git a/spell.ignore b/spell.ignore index 1fa9be1a81c..c597e9cbf05 100644 --- a/spell.ignore +++ b/spell.ignore @@ -91,9 +91,11 @@ buf bz BZ cachetune +capabilities cartesian ccw CCW +CEC cd cdrom cellno @@ -150,6 +152,7 @@ conf config Config configs +Cong coredump corescount cpu @@ -168,6 +171,7 @@ ctrl currentvcpu curvcpu CVE +cvm dac DAC darget @@ -178,6 +182,9 @@ datetime DAX dbus de +decrypt +decrypted +decryption deduplicate del deplist @@ -186,6 +193,7 @@ desc dest desturi dev +devid devname devno devnode @@ -260,6 +268,7 @@ dzheng ebtables efi eg +egd els embeddedqemu emulatorbin @@ -339,6 +348,8 @@ getspeed gfxcard Gib GiB +gic +GIC gid gluster Gluster @@ -375,7 +386,9 @@ hostfile hostname hostnuma hotplug +hotplugs Hotplug +Hotplugs hotpluggable hotplugged Hotplugged @@ -393,6 +406,7 @@ hugepage Hugepage hugepages hugetlbfs +hwclock hwinfo hwtype hyperv @@ -426,6 +440,8 @@ inodes inpect installable installroot +intel +intremap invtsc inx io @@ -453,6 +469,7 @@ ip IP ipaddress iperf +ips IPs iptable iptables @@ -473,6 +490,7 @@ kallsysm kb kconfig kdump +keepalive kexec keycodes keypresses @@ -492,6 +510,8 @@ kwargs lan lcheng lchown +lcong +Liang libexec libguestfs libnbd @@ -528,6 +548,7 @@ lspci lstat lstatlist lsusb +lszcrypt lszdev luks Luks @@ -575,6 +596,7 @@ mdev mdevctl mellanox mem +memoryBacking mems memballoon memhog @@ -720,6 +742,7 @@ ovs OVS ovsbridge pagesize +parameterless params paravirtual parma @@ -804,12 +827,15 @@ qed qem qemu qmp +QE QMP +qos quiesce qxl QXL qxldod Radix +ras rases rawio rbd @@ -835,6 +861,8 @@ resize Resize resized resizing +resolv +resolvectl restared restorecon ret @@ -868,6 +896,7 @@ sata scenaries schedinfo schid +scm scp scsi schid @@ -1080,6 +1109,7 @@ upadte Updae uperf uptime +urandom uri URI uris @@ -1110,6 +1140,7 @@ vdb vdb's vdc vddk +vdpa vdsm vdx vepa @@ -1136,6 +1167,7 @@ vhbas vhost vhostuer vhostuser +vhostvdpa vid viostor vir @@ -1226,3 +1258,7 @@ hwrng buitin Meina meili +ntp +userfaultfd +datastore +https diff --git a/v2v/tests/cfg/convert_from_file.cfg b/v2v/tests/cfg/convert_from_file.cfg index 84d1586e4ea..555013784cf 100644 --- a/v2v/tests/cfg/convert_from_file.cfg +++ b/v2v/tests/cfg/convert_from_file.cfg @@ -37,6 +37,8 @@ output_method = "rhev" - local: only dest_local + - none: + only dest_none variants: - input_mode: variants: @@ -50,6 +52,14 @@ - latest8: boottype = 3 image_url = "LATEST_RHEL8_IMAGE_URL_V2V_EXAMPLE" + - virt_v2v_in_place: + only output_mode.none + boottype = 3 + image_url = "LATEST_RHEL9_IMAGE_URL_V2V_EXAMPLE" + checkpoint = 'virt_v2v_in_place' + msg_content = 'virt-v2v-in-place: warning: virt-v2v-in-place is NOT SUPPORTED .*? use virt-v2v instead of this tool.' + expect_msg = yes + skip_vm_check = yes - libvirtxml: only source_none input_mode = "libvirtxml" @@ -112,12 +122,13 @@ ova_dir = OVA_DIR_BUG_2069768_V2V_EXAMPLE input_file = '${ova_copy_dir}/OVA_FILE_BUG_2069768_V2V_EXAMPLE' - cpu_topology: + only output_mode.rhev checkpoint = 'cpu_topology' v2v_debug = force_on - ova_file_name = OVA_DIR_RHEL_LINUX_V2V_EXAMPLE.ova - ova_dir = OVA_DIR_ROOT_V2V_EXAMPLE/${ova_file_name} + ova_file_name = OVA_FILE_CPU_TOPOLOGY_V2V_EXAMPLE + ova_dir = OVA_DIR_ROOT_V2V_EXAMPLE ova_copy_dir = 'OVA_DIR_COPY_V2V_EXAMPLE' - input_file = ${ova_copy_dir}/${ova_file_name} + input_file = ${ova_dir}/${ova_file_name} msg_content_yes = '' - special: ova_dir = 'OVA_DIR_SPECIAL_V2V_EXAMPLE' @@ -158,7 +169,6 @@ expect_msg = yes input_file = ${ova_dir}/${ova_file} - aws: - only output_mode.rhev ova_dir = OVA_DIR_AWS_V2V_EXAMPLE variants: - rhel7_2: @@ -186,41 +196,78 @@ variants: - latest8: v2v_debug = force_on - only esx_67 + only esx_80 main_vm = 'VM_NAME_RHEL8_V2V_EXAMPLE' - msg_content = 'scp -T' + msg_content = "nbdcopy .*?" + version_required = "[virt-v2v-2.0.7-1.el9,)" expect_msg = yes + boottype = 3 - latest7: - only esx_67 + only esx_80 main_vm = 'VM_NAME_RHEL7_V2V_EXAMPLE' - latest6: enable_legacy_policy = yes - only esx_67 + only esx_80 main_vm = 'VM_NAME_RHEL6_V2V_EXAMPLE' + boottype = 3 + #skip check guest because of bug1647352 + skip_vm_check = yes - regular_user_sudo: checkpoint = 'regular_user_sudo' main_vm = 'VM_NAME_RHEL8_V2V_EXAMPLE' env_settings = 'eval `ssh-agent`;ssh-add;sudo -E LIBGUESTFS_BACKEND=direct' unprivileged_user = 'USER_UNPRIVILEGED_V2V_EXAMPLE' + boottype = 3 #os_directory = '/home/${unprivileged_user}' - only esx_67 + only esx_80 - nvme_disk: - only esx_67 + only esx_80 #add required version due to bug2070530 version_required = "[virt-v2v-2.0.7-1.el9,)" main_vm = 'VM_NAME_NVME_RHEL8_V2V_EXAMPLE' - datastore = esx6.7-function + datastore = esx8.0-function + boottype = 3 #Skip pre-check by bz#2068992. Will modify once the bug fixed. skip_virsh_pre_conn = yes - percent_encode: - only esx_70 + only esx_80 only output_mode.libvirt version_required = "[virt-v2v-2.0.7-1.el9,)" main_vm = 'VM_NAME_PERCENT_ENCODING_RHEL9_V2V_EXAMPLE' - datastore = esx7.0-function + datastore = esx8.0-function + boottype = 3 + - space_name: + only esx_80 + only output_mode.libvirt + boottype = 3 + version_required = "[virt-v2v-2.3.4-6.el9,)" + main_vm = "VM_NAME_SPACE_NAME_VMX_V2V_EXAMPLE" + - special_character: + only esx_80 + boottype = 3 + version_required = "[virt-v2v-2.4.0-2.el9,)" + main_vm = "VM_NAME_SPACE_NAME_VMX_V2V_EXAMPLE" + checkpoint = 'special_character' + expect_msg = 'yes' + msg_content = 'nbd_connect_uri.*No such file or directory.*' + - wrong_vmx: + only esx_80 + boottype = 3 + version_required = "[virt-v2v-2.4.0-2.el9,)" + main_vm = VM_NAME_RHEL9_V2V_EXAMPLE + checkpoint = 'wrong_vmx' + msg_content_yes = "virt-v2v: error: input file is a VMDK \(disk image\), but we are expecting a VMX \(VMware metadata\)" + - no_ssh_agent: + only esx_80 + version_required = "[virt-v2v-2.4.0-2.el9,)" + boottype = 3 + main_vm = VM_NAME_RHEL9_V2V_EXAMPLE + expect_msg = 'no' + msg_content = 'scp -T.*source.vmx' + checkpoint = 'no_ssh_agent' - vmx_default: # Default - vmx_nfs_src = NFS_ESX67_VMX_V2V_EXAMPLE + vmx_nfs_src = NFS_ESX70_VMX_V2V_EXAMPLE # Do not skip vm checking by default skip_vm_check = no # By default, v2v will try to connect to source hypervisor @@ -233,45 +280,46 @@ skip_virsh_pre_conn = no variants: - win2012r2: - only esx_60 + only esx_70 only windows os_version = 'win2012r2' - has_genid = 'no' + has_genid = 'yes' main_vm = 'VM_NAME_GENID_WIN2012R2_V2V_EXAMPLE' - vmx_nfs_src = NFS_ESX60_VMX_V2V_EXAMPLE + vmx_nfs_src = NFS_ESX70_VMX_V2V_EXAMPLE # genid only supports libvirt, local, qemu only output_mode.libvirt - win2019: - only esx_67 + only esx_70 only windows os_version = 'win2019' has_genid = 'yes' main_vm = 'VM_NAME_GENID_WIN2019_V2V_EXAMPLE' - vmx_nfs_src = NFS_ESX67_VMX_V2V_EXAMPLE + vmx_nfs_src = NFS_ESX70_VMX_V2V_EXAMPLE # genid only supports libvirt, local, qemu only output_mode.libvirt - win10: - only esx_67 + only esx_70 only windows os_version = 'win10' has_genid = 'yes' main_vm = 'VM_NAME_GENID_WIN10_V2V_EXAMPLE' - vmx_nfs_src = NFS_ESX67_VMX_V2V_EXAMPLE + vmx_nfs_src = NFS_ESX70_VMX_V2V_EXAMPLE # genid only supports libvirt, local, qemu only output_mode.libvirt - latest8: - only esx_67 - main_vm = 'VM_NAME_RHEL8_V2V_EXAMPLE' + only esx_70 + main_vm = 'VM_NAME_ESX70_RHEL8_V2V_EXAMPLE' - latest7: - only esx_67 - main_vm = 'VM_NAME_RHEL7_V2V_EXAMPLE' + only esx_70 + main_vm = 'VM_NAME_ESX70_RHEL7_V2V_EXAMPLE' - latest6: enable_legacy_policy = yes - only esx_67 - main_vm = 'VM_NAME_RHEL6_V2V_EXAMPLE' + only esx_70 + main_vm = 'VM_NAME_ESX70_RHEL6_V2V_EXAMPLE' - cpu_topology: - only esx_67 - vmx_nfs_src = NFS_ESX67_VMX_V2V_EXAMPLE + only esx_70 + only output_mode.rhev + vmx_nfs_src = NFS_ESX70_FUNC_VMX_V2V_EXAMPLE main_vm = 'VM_NAME_CPU_TOPOLOGY_V2V_EXAMPLE' v2v_debug = force_on checkpoint = 'cpu_topology' @@ -279,13 +327,13 @@ variants: - negative_test: status_error = 'yes' - only parse.SHA1,parse.SHA256 + only parse.SHA1,parse.SHA256,special_character,wrong_vmx - positive_test: status_error = 'no' variants: - linux: only ova,vmx,disk - no win2008r2_ostk,aws.win2019 + no win2008r2_ostk,aws.win2019,special_character,wrong_vmx - windows: os_type = 'windows' shutdown_command = 'shutdown /s /f /t 0' diff --git a/v2v/tests/cfg/convert_vm_to_libvirt.cfg b/v2v/tests/cfg/convert_vm_to_libvirt.cfg index a274d745736..3d528aa0ee8 100644 --- a/v2v/tests/cfg/convert_vm_to_libvirt.cfg +++ b/v2v/tests/cfg/convert_vm_to_libvirt.cfg @@ -28,7 +28,7 @@ - it_default: variants: - arch_i386: - only latest6, 5_11, win7, win8, win8_1, win10, debian + only latest6, win10 vm_arch = "i386" - arch_x86_64: vm_arch = "x86_64" @@ -38,64 +38,55 @@ - boot_uefi: vm_boot = "-efi" boottype = 3 - only 8_0.linux.latest9_dev, 8_0.linux.latest8_dev, 8_0.linux.latest9, 8_0.linux.latest8, 8_0.linux.8_7, 8_0.linux.8_6, 8_0.linux.ubuntu_lts, 8_0.linux.sles_latest, 8_0.windows.win2022, 8_0.windows.win11, 8_0.windows.win2016 + only 8_0.linux.latest10_dev, 8_0.linux.latest10, 8_0.linux.latest9_dev, 8_0.linux.latest9, 8_0.linux.latest8, 8_0.linux.ubuntu_lts, 8_0.linux.sles_lts, 8_0.linux.opensuse_latest, 8_0.windows.win2022, 8_0.windows.win11, 8_0.windows.win10, 8_0.windows.win2016, 8_0.windows.win2019, 8_0.windows.win2025 variants: - linux: os_type = "linux" vm_user = ${username} vm_pwd = ${password} variants: + - latest10_dev: + os_short_id = "RHEL10_DEV_SHORT_ID" + os_version = "LATEST_DEV_10" + - latest10: + os_short_id = "RHEL10_SHORT_ID" + os_version = "LATEST10" - latest9_dev: os_short_id = "RHEL9_DEV_SHORT_ID" os_version = "LATEST_DEV_9" - - latest8_dev: - os_short_id = "RHEL8_DEV_SHORT_ID" - os_version = "LATEST_DEV_8" - latest9: os_short_id = "RHEL9_SHORT_ID" os_version = "LATEST9" - latest8: os_short_id = "RHEL8_SHORT_ID" os_version = "LATEST8" - - 8_7: - os_version = "rhel8.7" - - 8_6: - os_version = "rhel8.6" + - 9_4: + os_version = "rhel9.4" - latest7: os_short_id = "RHEL7_SHORT_ID" os_version = "LATEST7" - latest6: os_version = "LATEST6" enable_legacy_policy = yes - - 5_11: - os_version = "rhel5.11" - enable_legacy_policy = yes - - debian: + - debian_lts: only source_esx.esx_80 #os_short_id = "DEBIAN_SHORT_ID" - os_version = "DEBIAN_VERSION" + os_version = "DEBIAN_LTS_VERSION" - ubuntu_lts: only source_esx.esx_80 os_short_id = "UBUNTU_LTS_SHORT_ID" os_version = "UBUNTU_LTS_VERSION" - - sles12sp4: - only source_esx.esx_67, source_esx.esx_70 - os_short_id = "sles12sp4" - os_version = "sles12sp4" - sles12sp5: only source_esx.esx_80 os_short_id = "sles12sp5" os_version = "sles12sp5" - - sles_latest: + - sles_lts: only source_esx.esx_80 os_version = "SLES_LATEST_VERSION" - opensuse_latest: - only source_esx.esx_67, source_esx.esx_70, source_esx.esx_80 + only source_esx.esx_80 os_short_id = "OPENSUSE_LATEST_SHORT_ID" os_version = "OPENSUSE_LATEST_VERSION" - - opensuse15_4: - only source_esx.esx_67, source_esx.esx_70 - os_version = "opensuse15.4" - windows: no pv os_type = "windows" @@ -117,20 +108,6 @@ vm_user = "Administrator" vm_pwd = DEFAULT_WIN_VM_PASSWORD variants: - - win2008r2: - os_version = "win2008r2" - - win8: - only esx - os_version = "win8" - - win8_1: - only esx - os_version = "win8.1" - - win2012: - only esx - os_version = "win2012" - - win2012r2: - only esx - os_version = "win2012r2" - win10: only esx os_version = "win10" @@ -147,6 +124,9 @@ - win11: only esx os_version = "win11" + - win2025: + only esx + os_version = "win2025" variants: - xen: only source_xen @@ -177,16 +157,6 @@ - 7_0: only source_esx.esx_70 esx_version = "esx7.0" - - 6_7: - only source_esx.esx_67 - esx_version = "esx6.7" - - 6_5: - only source_esx.esx_65 - esx_version = "esx6.5" - - 6_0: - only source_esx.esx_60 - esx_version = "esx6.0" - no win11,win2022,latest9 hostname = ${esx_hostname} variants: - vm: diff --git a/v2v/tests/cfg/convert_vm_to_ovirt.cfg b/v2v/tests/cfg/convert_vm_to_ovirt.cfg index 6292337d521..1e62fa76055 100644 --- a/v2v/tests/cfg/convert_vm_to_ovirt.cfg +++ b/v2v/tests/cfg/convert_vm_to_ovirt.cfg @@ -81,23 +81,25 @@ - boot_uefi: vm_boot = "-efi" boottype = 3 - only 8_0.linux.latest9_dev, 8_0.linux.latest8_dev, 8_0.linux.latest9, 8_0.linux.latest8, 8_0.linux.8_7, 8_0.linux.8_6, 8_0.linux.ubuntu_lts, 8_0.linux.sles_latest, 8_0.windows.win2022, 8_0.windows.win11, 8_0.windows.win2016 + only 8_0.linux.latest10_dev, 8_0.linux.latest10, 8_0.linux.latest9_dev, 8_0.linux.latest9, 8_0.linux.latest8, 8_0.linux.8_8, 8_0.linux.8_6, 8_0.linux.ubuntu22_04, 8_0.linux.ubuntu_lts, 8_0.linux.sles15sp5, 8_0.linux.sles_lts, 8_0.linux.opensuse15_5, 8_0.linux.opensuse_latest, 8_0.windows.win2022, 8_0.windows.win11, 8_0.windows.win2016, 8_0.windows.win2025 variants: - linux: os_type = "linux" vm_user = ${username} vm_pwd = GENERAL_GUEST_PASSWORD variants: + - latest10_dev: + os_version = "LATEST_DEV_10" + - latest10: + os_version = "LATEST10" - latest9_dev: os_version = "LATEST_DEV_9" - - latest8_dev: - os_version = "LATEST_DEV_8" - latest9: os_version = "LATEST9" - latest8: os_version = "LATEST8" - - 8_7: - os_version = "rhel8.7" + - 8_8: + os_version = "rhel8.8" - 8_6: os_version = "rhel8.6" - latest7: @@ -108,27 +110,39 @@ - 5_11: os_version = "rhel5.11" enable_legacy_policy = yes - - debian: + - debian11_7: only source_esx.esx_80 - os_version = "DEBIAN_VERSION" + #os_short_id = "debian11" + os_version = "debian11.7.0" + - debian_lts: + only source_esx.esx_80 + os_version = "DEBIAN_LTS_VERSION" + - ubuntu22_04: + only source_esx.esx_80 + os_short_id = "ubuntu22.04" + os_version = "ubuntu22.04" - ubuntu_lts: only source_esx.esx_80 os_version = "UBUNTU_LTS_VERSION" - - sles12sp4: - only source_esx.esx_67, source_esx.esx_70 - os_version = "sles12sp4" - sles12sp5: only source_esx.esx_80 os_version = "sles12sp5" - - sles_latest: + - sles15sp5: + only source_esx.esx_80 + os_short_id = "sles15sp5" + os_version = "sles15sp5" + - sles_lts: only source_esx.esx_80 os_version = "SLES_LATEST_VERSION" - opensuse_latest: - only source_esx.esx_67, source_esx.esx_70, source_esx.esx_80 + only source_esx.esx_80 os_version = "OPENSUSE_LATEST_VERSION" - - opensuse15_4: - only source_esx.esx_67, source_esx.esx_70 - os_version = "opensuse15.4" + - opensuse42_3: + only source_esx.esx_70, source_esx.esx_80 + os_version = "opensuse42.3" + - opensuse15_5: + only source_esx.esx_80 + os_version = "opensuse15.5" - windows: no pv os_type = "windows" @@ -179,6 +193,9 @@ - win11: no xen os_version = "win11" + - win2025: + no xen + os_version = "win2025" variants: - xen: only source_xen @@ -209,16 +226,6 @@ - 7_0: only source_esx.esx_70 esx_version = "esx7.0" - - 6_7: - only source_esx.esx_67 - esx_version = "esx6.7" - - 6_5: - only source_esx.esx_65 - esx_version = "esx6.5" - - 6_0: - only source_esx.esx_60 - no win11,win2022,latest9 - esx_version = "esx6.0" hostname = ${vpx_hostname} variants: - vm: diff --git a/v2v/tests/cfg/function_test_esx.cfg b/v2v/tests/cfg/function_test_esx.cfg index e32fc289a86..796186d5501 100644 --- a/v2v/tests/cfg/function_test_esx.cfg +++ b/v2v/tests/cfg/function_test_esx.cfg @@ -55,7 +55,6 @@ only uefi.win2019 - libvirt: only dest_libvirt - only uefi,GPO_AV,special_name,suse,local_storage,unset,lvm_multiple_disks,genid_xml - rhev: only dest_rhev.NFS variants: @@ -66,13 +65,8 @@ rhv_upload_opts = "-oc ${ovirt_engine_url} -op ${rhv_upload_passwd_file} -oo rhv-cafile=${local_ca_file_path} -oo rhv-cluster=${cluster_name}" - rhv: output_method = "rhev" + no uefi,GPO_AV,special_name,suse,local_storage,unset,lvm_multiple_disks,genid_xml variants: - - esx_60: - only source_esx.esx_60 - - esx_65: - only source_esx.esx_65 - - esx_67: - only source_esx.esx_67 - esx_70: only source_esx.esx_70 - esx_80: @@ -105,13 +99,13 @@ msg_content_yes = "windows: skipping qemufwcfg stub driver in favor of fwcfg driver" v2v_debug = force_on - program_files_2: - only esx_67 + only esx_70 os_version = 'PROGRAM_FILES_2_OS_VERSION_V2V_EXAMPLE' main_vm = 'PROGRAM_FILES_2_VM_NAME_V2V_EXAMPLE' expect_msg = 'no' msg_content = '.*case_sensitive_path: v2v: no file or directory.*' - rhev_file: - only esx_67 + only esx_70 no libvirt checkpoint = 'rhev_file' os_version = OS_VERSION_RHEV_FILE_V2V_EXAMPLE @@ -122,38 +116,30 @@ boottype = 3 variants: - win2019: - only esx_67 + only esx_70 main_vm = VM_NAME_ESX_UEFI_WINDOWS_V2V_EXAMPLE os_version = "win2019" checkpoint = 'fstrim_warning' msg_content = 'virt-v2v: warning: fstrim on guest filesystem /dev/.*? failed. Usually' expect_msg = yes - - schtask: - only esx_70 - checkpoint = "ogac" - virtio_win_path = "/usr/share/virtio-win/" - os_version = VM_VERSION_WIN_SCHTASKS_V2V_EXAMPLE - main_vm = VM_NAME_WIN_SCHTASKS_V2V_EXAMPLE - - OGAC: - only esx_67 - checkpoint = "ogac" - virtio_win_path = EXPORT_VIRTIO_WIN_PATH_V2V_EXAMPLE + - OGAC_balloon: + only esx_80 + only dest_libvirt + checkpoint = "ogac_balloon" + #Not use virtio_win_path due to bug RHEL-69035 + #virtio_win_path = EXPORT_VIRTIO_WIN_PATH_V2V_EXAMPLE variants: - - win2008r2: - os_version = "win2008r2" - main_vm = VM_NAME_WIN2008R2_V2V_EXAMPLE - - win8: - os_version = "win8" - main_vm = VM_NAME_WIN8_V2V_EXAMPLE - - win8_1: - os_version = "win8.1" - main_vm = VM_NAME_WIN81_V2V_EXAMPLE - - win2012: - os_version = "win2012" - main_vm = VM_NAME_WIN2012_V2V_EXAMPLE - - win2012r2: - os_version = "win2012r2" - main_vm = VM_NAME_WIN2012R2_V2V_EXAMPLE + - win2022: + os_version = "win2022" + main_vm = "VM_NAME_WIN2022_V2V_EXAMPLE" + - win2025: + os_version = "win2025" + main_vm = "VM_NAME_WIN2025_EFI_V2V_EXAMPLE" + boottype = 3 + - win11: + os_version = "win11" + main_vm = "VM_NAME_WIN11_EFI_V2V_EXAMPLE" + boottype = 3 - win10: os_version = "win10" main_vm = VM_NAME_WIN10_V2V_EXAMPLE @@ -161,10 +147,11 @@ main_vm = VM_NAME_WIN2016_V2V_EXAMPLE os_version = "win2016" - win2019: - main_vm = VM_NAME_WIN2019_V2V_EXAMPLE + main_vm = VM_NAME_WIN2019_EFI_V2V_EXAMPLE os_version = "win2019" + boottype = 3 - virtio_win: - only esx_67 + only esx_70 main_vm = 'ESX_VM_NAME_VIRTIO_WIN_V2V_EXAMPLE' os_version = 'OS_VERSION_VIRTIO_WIN_V2V_EXAMPLE' virtio_win_dir = '/usr/share/virtio-win/' @@ -173,7 +160,7 @@ variants: - unset: checkpoint += 'unset' - missing = 'Red Hat VirtIO SCSI,Red Hat VirtIO Ethernet Adapte' + missing = 'Red Hat VirtIO SCSI,Red Hat VirtIO Ethernet Adapte,VirtIO RNG,VirtIO Balloon' only dest_libvirt - custom: checkpoint += 'custom' @@ -182,37 +169,95 @@ - iso_file: checkpoint += 'iso_file' - virtio_iso_blk: - only esx_67 + only esx_80 checkpoint = "virtio_iso_blk" virtio_win_path = '/usr/share/virtio-win/virtio-win.iso' - main_vm = VM_NAME_WIN2019_V2V_EXAMPLE + main_vm = VM_NAME_ESX80_WIN2019_V2V_EXAMPLE os_version = "win2019" - mac_ip: + only libvirt checkpoint = 'mac_ip' variants: - - 1_dhcp: - only esx_67 - main_vm = VM_NAME_WIN_1_DHCP_IP_V2V_EXAMPLE - v2v_opts = VM_NAME_WIN_1_DHCP_IP_MAC_CONF_V2V_EXAMPLE - - 1_static: - only esx_65 - main_vm = VM_NAME_WIN_1_STATIC_IP_V2V_EXAMPLE - v2v_opts = VM_NAME_WIN_1_STATIC_IP_MAC_CONF_V2V_EXAMPLE - - 3_dhcp: - only esx_70 - main_vm = VM_NAME_WIN_3_DHCP_IP_V2V_EXAMPLE - v2v_opts = VM_NAME_WIN_3_DHCP_IP_MAC_CONF_V2V_EXAMPLE + - 3_static_ip: + only esx_80 + variants: + - win10: + main_vm = VM_NAME_WIN10_3_STATIC_IP_V2V_EXAMPLE + boottype = 3 + v2v_opts = VM_NAME_WIN10_3_STATIC_IP_MAC_CONF_V2V_EXAMPLE + - empty_gw: + only esx_80 + variants: + - win11: + main_vm = VM_NAME_WIN11_ONLINE_DISKS_V2V_EXAMPLE + v2v_opts = VM_NAME_WIN11_EMPTY_GW_IP_MAC_CONF_V2V_EXAMPLE + - win2022: + main_vm = VM_NAME_WIN2022_ONLINE_DISKS_V2V_EXAMPLE + v2v_opts = VM_NAME_WIN2022_EMPTY_GW_IP_MAC_CONF_V2V_EXAMPLE + - 1_static_ip: + only esx_80 + variants: + - win2019: + main_vm = VM_NAME_WIN2019_ONLINE_DISKS_V2V_EXAMPLE + boottype = 3 + v2v_opts = VM_NAME_WIN2019_1_STATIC_IP_MAC_CONF_V2V_EXAMPLE + - win2025: + main_vm = VM_NAME_WIN2025_ONLINE_DISKS_V2V_EXAMPLE + boottype = 3 + v2v_opts = VM_NAME_WIN2025_1_STATIC_IP_MAC_CONF_V2V_EXAMPLE - vmware_tools: - only esx_70 + only esx_80 + only dest_libvirt checkpoint = 'vmware_tools' - main_vm = VM_NAME_WIN_VMWARE_TOOLS_V2V_EXAMPLE + variants: + - win2022: + os_version = "win2022" + main_vm = "VM_NAME_WIN2022_V2V_EXAMPLE" + - win2025: + os_version = "win2025" + main_vm = "VM_NAME_WIN2025_EFI_V2V_EXAMPLE" + boottype = 3 + - win11: + os_version = "win11" + main_vm = VM_NAME_WIN11_EFI_V2V_EXAMPLE + boottype = 3 + - win10: + os_version = "win10" + main_vm = VM_NAME_WIN10_EFI_V2V_EXAMPLE + boottype = 3 + - win2016: + main_vm = VM_NAME_WIN2016_V2V_EXAMPLE + os_version = "win2016" + - win2019: + main_vm = VM_NAME_WIN2019_EFI_V2V_EXAMPLE + os_version = "win2019" + boottype = 3 + - multiple_online_disks: + only esx_80 + only dest_libvirt + checkpoint = 'check_online_disks' + variants: + - win2022: + os_version = "win2022" + main_vm = VM_NAME_WIN2022_ONLINE_DISKS_V2V_EXAMPLE + - win2025: + os_version = "win2025" + main_vm = VM_NAME_WIN2025_ONLINE_DISKS_V2V_EXAMPLE + boottype = 3 + - win11: + os_version = "win11" + main_vm = VM_NAME_WIN11_ONLINE_DISKS_V2V_EXAMPLE + - win2019: + main_vm = VM_NAME_WIN2019_ONLINE_DISKS_V2V_EXAMPLE + os_version = "win2019" + boottype = 3 - rhsrvany_md5: - only esx_67 + only esx_80 checkpoint = 'rhsrvany_checksum' - main_vm = VM_NAME_WIN2019_V2V_EXAMPLE + main_vm = VM_NAME_ESX80_WIN2019_V2V_EXAMPLE os_version = 'win2019' - external_poweroff: - only esx_67 + only esx_70 only negative_test main_vm = VM_NAME_WIN_EXTERNAL_POWEROFF_V2V_EXAMPLE msg_content = "virt-v2v: error: filesystem was mounted read-only, even though we asked for it to be mounted read-write." @@ -257,6 +302,7 @@ expect_msg = no - vddk_errors_41_disks: only negative_test + only rhev only esx_70 #add required version due to bug2051564 version_requried = "[virt-v2v-2.0.7-1,)" @@ -266,15 +312,12 @@ msg_content_no = "VDDK_PhoneHome" msg_content_yes = "virt-v2v: error: this output module doesn't support copying more than 23 disks" - migrated_vm: - only esx_67 + only esx_70 main_vm = 'VM_NAME_ESX_MIGRATED_V2V_EXAMPLE' libguestfs_backend = 'direct' - local_storage: only esx_70 main_vm = "VM_NAME_ESX_LOCALSTORAGE_V2V_EXAMPLE" - - multiple_disks: - only esx_70 - main_vm = 'VM_NAME_ESX_MULDISKS_V2V_EXAMPLE' - multiple_cpus: only esx_70 main_vm = 'VM_NAME_ESX_MULCPUS_V2V_EXAMPLE' @@ -294,7 +337,7 @@ boottype = 3 main_vm = 'VM_NAME_ESX_TEMPLATE_V2V_EXAMPLE' - esx_snapshot: - only esx_65 + only esx_70 checkpoint = snapshot main_vm = VM_NAME_ESX_SNAPSHOT_V2V_EXAMPLE removed_file = ESX_REMOVED_FILE_V2V_EXAMPLE @@ -305,23 +348,23 @@ - ovmf: variants: - rhel7: - only esx_67 + only esx_70 main_vm = VM_NAME_ESX_UEFI_RHEL7_V2V_EXAMPLE - raid: variants: - bios: - only esx_60 + only esx_80 main_vm = VM_NAME_ESX_RAID_V2V_EXAMPLE - uefi: boottype = 3 version_required = "[libguestfs-1.40,)" - only source_esx.esx_67 + only source_esx.esx_70 main_vm = VM_NAME_ESX_UEFI_RAID_V2V_EXAMPLE - iscsi_storage: only esx_70 main_vm = "VM_NAME_ISCSI_STORAGE_V2V_EXAMPLE" - GPO_AV: - only esx_60 + only esx_70 main_vm = 'VM_NAME_GPO_AV_V2V_EXAMPLE' checkpoint = 'GPO_AV' msg_content = 'virt-v2v: warning: this guest has Windows Group Policy Objects%virt-v2v: warning: this guest has Anti-Virus \(AV\) software' @@ -329,7 +372,7 @@ skip_vm_check = yes skip_reason = 'guest version is too old' - AV_WIN7: - only esx_67 + only esx_70 main_vm = 'VM_NAME_AV_WIN7_V2V_EXAMPLE' msg_content = 'virt-v2v: warning: this guest has Anti-Virus \(AV\) software' expect_msg = yes @@ -343,13 +386,13 @@ checkpoint = vmtools removed_pkgs = vmware-tools-libraries-nox,vmware-tools-foundation,vmware-tools-libraries-x - service: - only esx_60 + only esx_70 main_vm = VM_NAME_VMTOOLS_SERVICE_V2V_EXAMPLE checkpoint = "vmtools,service service_name = vmware-tools - modprobe: - only esx_60 - main_vm = VM_NAME_RHEL5_V2V_EXAMPLE + only esx_70 + main_vm = VM_NAME_RHEL6_V2V_EXAMPLE enable_legacy_policy = yes checkpoint = modprobe cfg_content = 'alias eth0 virtio_net' @@ -357,11 +400,12 @@ only esx_70 main_vm = VM_NAME_DEVICE_PASSTHRU_V2V_EXAMPLE - empty_cdrom: - only esx_60 - main_vm = VM_NAME_EMPTY_CDROM_V2V_EXAMPLE - checkpoint = empty_cdrom + only esx_80 + version_required = "[libvirt-10.8.0-1,)" + boottype = 3 + main_vm = VM_NAME_EMPTY_IDE_SATA_CDROM_V2V_EXAMPLE skip_vm_check = yes - skip_reason = "No vm is created in this case" + skip_reason = 'bug RHEL-38633 is not fixed' - option_root: main_vm = VM_NAME_MULTIPLE_LINUX_V2V_EXAMPLE checkpoint = root @@ -376,36 +420,33 @@ msg_content = 'virt-v2v: warning: fstrim on guest filesystem' expect_msg = no - first: - only esx_67 + only esx_70 root_option = first skip_vm_check = yes skip_reason = "Can't boot into first os without selecting by user during booting after v2v conversion" - single: - only esx_67 + only esx_70 root_option = single only negative_test - dev_sdx: - only esx_67 + only esx_70 root_option = '/dev/sda1' skip_vm_check = yes skip_reason = "/dev/sda1 belongs to the first OS which can't boot into without selecting by user during booting after v2v conversion" - dev_vglv: - only esx_67 + only esx_70 root_option = '/dev/rhel/root' checkpoint += ,${root_option} - device_map: - only esx_67 + only esx_70 checkpoint = device_map main_vm = VM_NAME_ESX_RHEL7_V2V_EXAMPLE device_map_path = /boot/grub2/device.map - fstab_comma: - only esx_65 - checkpoint = fstab_comma + only esx_70 main_vm = VM_NAME_ESX_FSTAB_SEPBY_COMMA - msg_content = 'virt-v2v: warning: mount: mount exited with status 32: mount:.*? already mounted .*?\(ignored\)' - expect_msg = yes - with_proxy: - only esx_60 + only esx_70 no libvirt main_vm = VM_NAME_ESX_WITH_PROXY checkpoint = with_proxy @@ -422,39 +463,40 @@ expect_msg = yes v2v_debug = force_on - lvm_multiple_disks: - only esx_65 + only esx_70 only libvirt main_vm = VM_NAME_LVM_MULTIPLE_DISKS_V2V_EXAMPLE skip_vm_check = yes skip_reason = 'bz#1990808' - resume_rhel7: - only esx_65 + only esx_80 + only dest_libvirt os_version = OS_VERSION_RESUME_RHEL7_V2V_EXAMPLE checkpoint = resume_swap main_vm = VM_NAME_RESUME_RHEL7_V2V_EXAMPLE - resume_rhel6: - only esx_67 + only esx_70 enable_legacy_policy = yes os_version = OS_VERSION_RESUME_RHEL6_V2V_EXAMPLE checkpoint = resume_swap main_vm = VM_NAME_RESUME_RHEL6_V2V_EXAMPLE - resume_mapper: - only esx_67 + only esx_70 msg_content = 'unknown device "mapper"' expect_msg = no main_vm = VM_NAME_RESUME_MAPPER_V2V_EXAMPLE - epoch: - only esx_67 + only esx_70 main_vm = 'VM_NAME_ESX_EPOCH_V2V_EXAMPLE' version_required = "[libguestfs-1.40.2-1,)" enable_legacy_policy = yes - without_file_architecture: - only esx_67 + only esx_70 main_vm = 'VM_NAME_NO_FILE_ARCHITECTURE_V2V_EXAMPLE' checkpoint = file_architecture version_required = "[libguestfs-1.40.2-4,)" - invalid_rhv_pem: - only esx_67 + only esx_70 only negative_test..rhev.rhv_upload main_vm = VM_NAME_RHEL7_V2V_EXAMPLE checkpoint = 'invalid_pem' @@ -462,7 +504,7 @@ msg_content = 'virt-v2v: error: failed server prechecks, see earlier errors' expect_msg = yes - no-copy-illegal: - only esx_67 + only esx_70 main_vm = VM_NAME_RHEL7_V2V_EXAMPLE only negative_test..rhev.rhv_upload expect_msg = yes @@ -495,7 +537,7 @@ v2v_opts = "" msg_content = "Disk with the UUID .*? already exists" - no-copy: - only esx_67 + only esx_70 only rhev.rhv_upload # Means version >= libguestfs-1.40.2-15 version_required = "[libguestfs-1.40.2-15,)" @@ -513,60 +555,45 @@ # ovirt-guest-agent-common - OGAC: checkpoint = "ogac" - virtio_win_path = EXPORT_VIRTIO_WIN_PATH_V2V_EXAMPLE - implementation_change_ver = "[virt-v2v-2.0.6-3,)" variants: - rhel6: - only esx_67 - enable_legacy_policy = yes - qa_path = 'linux/el6' - qa_url = QEMU_GUEST_AGENT_EL6_DOWNLOAD_URL_V2V_EXAMPLE - main_vm = VM_NAME_RHEL6_V2V_EXAMPLE + only esx_70 + enable_legacy_policy = yes + main_vm = VM_NAME_ESX_BUGGY_SELINUX_CONTEXT_V2V_EXAMPLE - rhel7: - only esx_67 - qa_path = 'linux/el7' - qa_url = QEMU_GUEST_AGENT_EL7_DOWNLOAD_URL_V2V_EXAMPLE - main_vm = VM_NAME_RHEL7_V2V_EXAMPLE + only esx_80 + main_vm = VM_NAME_RHEL7_REPO_V2V_EXAMPLE - rhel8: - only esx_67 - qa_path = 'linux/el8' - qa_url = QEMU_GUEST_AGENT_EL8_DOWNLOAD_URL_V2V_EXAMPLE - main_vm = VM_NAME_RHEL8_V2V_EXAMPLE + only esx_80 + main_vm = VM_NAME_RHEL8_REPO_V2V_EXAMPLE + boottype = 3 - rhel9: - only esx_70 - version_required = "[libguestfs-1.45.6-2,)" - qa_path = 'linux/el9' - qa_url = QEMU_GUEST_AGENT_EL9_DOWNLOAD_URL_V2V_EXAMPLE - main_vm = VM_NAME_ESX70_RHEL9_V2V_EXAMPLE + only esx_80 + main_vm = VM_NAME_RHEL9_REPO_V2V_EXAMPLE + boottype = 3 + - rhel10: + only esx_80 + main_vm = VM_NAME_RHEL10_REPO_V2V_EXAMPLE - ubuntu: - only esx_67 - version_required = "[virt-v2v-2.0.6-3,)" - qa_path = 'linux/debian' - qa_url = QEMU_GUEST_AGENT_DEBIAN_DOWNLOAD_URL_V2V_EXAMPLE - main_vm = VM_NAME_UBUNTU_V2V_EXAMPLE + only esx_70 + main_vm = VM_NAME_UBUNTU_REPO_V2V_EXAMPLE - debian: - only esx_67 - version_required = "[virt-v2v-2.0.6-3,)" - qa_path = 'linux/debian' - qa_url = QEMU_GUEST_AGENT_DEBIAN_DOWNLOAD_URL_V2V_EXAMPLE - main_vm = VM_NAME_DEBIAN_V2V_EXAMPLE + only esx_80 + main_vm = VM_NAME_DEBIAN_REPO_V2V_EXAMPLE - sles: - only esx_67 - qa_path = 'linux/lp151' - qa_url = QEMU_GUEST_AGENT_SUSE_DOWNLOAD_URL_V2V_EXAMPLE - main_vm = VM_NAME_SLES_V2V_EXAMPLE + only esx_80 + main_vm = VM_NAME_SLES_INSTALL_KERNEL_SOURCE_PKG_V2V_EXAMPLE + boottype = 3 + os_version = "sles" - opensuse: - only esx_67 - boottype = 2 - qa_path = 'linux/lp151' - qa_url = QEMU_GUEST_AGENT_SUSE_DOWNLOAD_URL_V2V_EXAMPLE - main_vm = VM_NAME_OPENSUSE_V2V_EXAMPLE + only esx_80 + main_vm = VM_NAME_OPENSUSE_REPO_V2V_EXAMPLE - ubuntu-openvm-tools: - only esx_67 + only esx_70 main_vm = VM_NAME_UBUNTUTOOS_V2V_EXAMPLE checkpoint = "ubuntu_tools" - system_rhv_pem: - only esx_67 + only esx_70 only rhev.rhv_upload # Means version >= libguestfs-1.40.2-21 version_required = "[libguestfs-1.40.2-21,)" @@ -581,13 +608,14 @@ expect_msg = no - without_default_net: only esx_70 + only rhev main_vm = VM_NAME_ESX70_RHEL7_V2V_EXAMPLE checkpoint = "without_default_net" v2v_debug = force_on expect_msg = 'no' msg_content = 'Cannot remove Virtual Disk. Related operation is currently in progress' - log_size_decrease: - only esx_67 + only esx_70 version_requried = "[virt-v2v-1.42.0-3,);[nbdkit-server-1.17.4,)" v2v_debug = force_on checkpoint = 'log decrease' @@ -601,9 +629,9 @@ msg_content = 'v2v: add_drive.*?copyonread:true' main_vm = VM_NAME_ESX70_RHEL7_V2V_EXAMPLE - env_leak: - only esx_67 + only esx_80 only dest_json,local - main_vm = VM_NAME_WIN2019_V2V_EXAMPLE + main_vm = VM_NAME_ESX80_WIN2019_V2V_EXAMPLE env_settings = 'HOME=/root LIBGUESTFS_BACKEND=direct' unprivileged_user = 'USER_UNPRIVILEGED_V2V_EXAMPLE' os_directory = '/home/${unprivileged_user}' @@ -623,12 +651,12 @@ - large: block_count = 1800 - without_ip_option: - only esx_67 + only esx_70 main_vm = VM_NAME_RHEL7_V2V_EXAMPLE cmd_has_ip = 'no' interaction_run = 'yes' - vmx_filename: - only esx_67 + only esx_70 main_vm = VM_NAME_VMX_FILENAME_OPTIONAL_V2V_EXAMPLE - luks: interaction_run = 'yes' @@ -641,20 +669,20 @@ main_vm = VM_NAME_ONLY_ROOT_LUKS_V2V_EXAMPLE luks_password = LUKS_PASSWORD1 - swap_3luks: - only esx_67 + only esx_70 main_vm = VM_NAME_SWAP_3LUKS_V2V_EXAMPLE luks_password = LUKS_PASSWORD1 - swap_luks: - only esx_67 + only esx_70 main_vm = VM_NAME_SWAP_LUKS_V2V_EXAMPLE luks_password = LUKS_PASSWORD1 - root_swap_2luks: - only esx_67 + only esx_70 main_vm = VM_NAME_ROOT_SWAP_2LUKS_V2V_EXAMPLE luks_password = LUKS_PASSWORD1 # set interaction to 'no' will fail because it requires to run in shell env. - keys_from_stdin: - only esx_67 + only esx_70 main_vm = VM_NAME_SWAP_3LUKS_V2V_EXAMPLE luks_password = LUKS_PASSWORD1 v2v_opts = ' --keys-from-stdin' @@ -666,9 +694,9 @@ version_required = "[virt-v2v-2.0.7-2,)" main_vm = VM_NAME_CLEVIS_LUKS_V2V_EXAMPLE luks_partition = VM_LUKS_PARTITION_EXAMPLE - v2v_opts = "--key "${luks_partition}":clevis" + v2v_opts = "--key ${luks_partition}:clevis" - logs: - only esx_67 + only esx_70 main_vm = VM_NAME_ESX_DEFAULT_V2V_EXAMPLE variants: - open_source: @@ -697,7 +725,7 @@ v2v_opts = "--bandwidth-file ${bandwidth_file}" main_vm = VM_NAME_ESX70_RHEL8_V2V_EXAMPLE - buggy_selinux_context: - only esx_67 + only esx_70 enable_legacy_policy = yes main_vm = VM_NAME_ESX_BUGGY_SELINUX_CONTEXT_V2V_EXAMPLE - admin_account: @@ -707,7 +735,7 @@ expect_msg = 'no' msg_content = 'nbdkit:.*?503 Service Unavailable' - keys: - only esx_67 + only esx_70 main_vm = VM_NAME_SWAP_3LUKS_V2V_EXAMPLE checkpoint = 'luks_dev_keys' variants: @@ -728,6 +756,19 @@ luks_keys = LUkS_DEV_INVALID_KEYS_FILE expect_msg = 'yes' msg_content = 'virt-v2v: fopen: \S+: No such file or directory' + - keys_all: + only esx_70 + version_required = "[virt-v2v-2.3.7-2,)" + main_vm = VM_NAME_ROOT_SWAP_2LUKS_V2V_EXAMPLE + checkpoint = 'luks_dev_keys' + skip_vm_check = yes + skip_reason = 'luks encryped, cannot boots up without password' + variants: + - luks_all_key: + luks_keys = LUKS_ALL_KEYS + - luks_clevis: + luks_keys = LUKS_UUID_KEYS + v2v_opts += "--key all:clevis" - win_bitlocker: only esx_70 version_required = "[virt-v2v-1.42.0-15,)" @@ -744,17 +785,17 @@ main_vm = VM_NAME_WIN_BITLOCKER_V2V_EXAMPLE luks_keys = LUKS_WIN_BIT_LOCKER_DEV_KEYS - invalid_mac_ip: - only esx_67 + only esx_70 only negative_test version_required = "[virt-v2v-1.42.0-6,)" main_vm = VM_NAME_RHEL8_V2V_EXAMPLE variants: - addr: - v2v_opts = '--mac 00:50:56:ac:cd:56:ip:invalid_ip_addr' + v2v_opts = '--mac 00:50:56:b4:35:f0:ip:invalid_ip_addr' expect_msg = 'yes' msg_content = 'cannot parse --mac ip .*?: doesn’t look like .*? is an IP address' - prefix: - v2v_opts = '--mac 00:50:56:ac:cd:56:ip:192.168.1.1,192.168.1.2,129,10.1.1.1' + v2v_opts = '--mac 00:50:56:b4:35:f0:ip:192.168.1.1,192.168.1.2,129,10.1.1.1' expect_msg = 'yes' msg_content = 'virt-v2v: error: --mac ip prefix length field is out of range' - no_space: @@ -778,7 +819,7 @@ only esx_70 main_vm = 'VM_NAME_ESX_GT_16_DISKS_V2V_EXAMPLE' - must_ip: - only esx_67 + only esx_70 only it_default only negative_test version_required = "[virt-v2v-1.45.98-1,)" @@ -791,20 +832,20 @@ version_requried = "[libvirt-7.0.0-1,)" main_vm = VM_NAME_ESX70_NONEXIST_ISO_V2V_EXAMPLE - no_useless_info: - only esx_67 + only esx_70 version_required = '[nbdkit-server-1.12.5-1,)' main_vm = VM_NAME_RESUME_MAPPER_V2V_EXAMPLE expect_msg = 'no' msg_content = 'Exception AttributeError' - partionless_dev: - only esx_67 - main_vm = VM_NAME_ESX67_PARTIONLESS_DEV_V2V_EXAMPLE + only esx_70 + main_vm = VM_NAME_ESX70_PARTIONLESS_DEV_V2V_EXAMPLE msg_content = "virt-v2v: error: .*? inspect_os:" expect_msg = no skip_vm_check = yes skip_reason = 'special guest pariton and cannot get IP automatically' - no_ovirtsdk4_pkg: - only esx_67 + only esx_70 only negative_test only rhev.rhv_upload checkpoint = 'ovirtsdk4_pkg' @@ -812,18 +853,20 @@ msg_content = "virt-v2v: error: the Python module ‘ovirtsdk4’ could not be loaded" expect_msg = yes - rpmsave: - only esx_67 - main_vm = VM_NAME_ESX67_RPMSAVE_V2V_EXAMPLE + only esx_70 + main_vm = VM_NAME_ESX70_RPMSAVE_V2V_EXAMPLE - invalid_vddk_thumbprint: only esx_70 only negative_test only it_vddk - version_required = "[nbdkit-1.30.8-1,)" + version_required = "[virt-v2v-2.5.4-1,)" main_vm = VM_NAME_ESX70_RHEL8_V2V_EXAMPLE vddk_thumbprint = 'AA:2B:AD' - msg_content_yes = "error: Please verify whether the "thumbprint" parameter" + #bug RHEL-37682 was closed as NOTABUG + msg_content_yes = "server reported: VDDK "Unknown error" can be caused by several problems" - non_admin_user: only esx_80 + boottype = 3 main_vm = VM_NAME_NON_ADMIN_V2V_EXAMPLE vpx_username = VMWARE_NON_ADMIN_USER_EXAMPLE - rocky_linux: @@ -840,7 +883,6 @@ main_vm = VM_NAME_ESX80_MULTI_SPEC_V2V_EXAMPLE - no_vpx_username: only esx_80 - only it_default only negative_test version_required = "[libvirt-9.3.0-1.el9,)" main_vm = VM_NAME_NON_ADMIN_V2V_EXAMPLE @@ -856,6 +898,7 @@ checkpoint = 'invalid_os_storage' - verify_certificate: only esx_80 + boottype = 3 main_vm = VM_NAME_NON_ADMIN_V2V_EXAMPLE checkpoint = 'verify_certificate' certs_src_dir = 'CERTS_DIR_V2V_EXAMPLE' @@ -871,6 +914,7 @@ skip_reason = 'luks encryped, cannot boots up without password' - default_vsphere: only esx_80 + boottype = 3 main_vm = VM_NAME_NON_ADMIN_V2V_EXAMPLE interaction_run = 'yes' vpx_no_username = True @@ -884,8 +928,9 @@ checkpoint = 'large_disk' v2v_debug = false - cpu_topology: - only esx_67 + only esx_70 only it_vddk + only rhev main_vm = VM_NAME_CPU_TOPOLOGY_V2V_EXAMPLE checkpoint = 'cpu_topology' v2v_debug = force_on @@ -896,6 +941,45 @@ main_vm = VM_NAME_NO_ENTRY_NETWORKNAME_V2V_EXAMPLE skip_vm_check = yes skip_reason = 'The VM doesn\'t have a network' + - dvs_net_no_portid_connectionid: + only esx_80 + main_vm = VM_NAME_DVS_NET_NO_PORTID_CONNECTIONID_V2V_EXAMPLE + skip_vm_check = yes + skip_reason = 'Bug RHEL-732 is not fixed' + - non_int_disk: + only esx_80 + main_vm = VM_NAME_NON_INT_DISK_V2V_EXAMPLE + version_required = "[nbdkit-1.36.2-2,)" + - sles_btrfs: + only esx_80 + version_required = "[libguestfs-fssupport-10.1-2,)" + variants: + - default: + variants: + - sles15sp6: + main_vm = VM_NAME_SLES_BTRFS_DEFAULT_SLES15SP6_V2V_EXAMPLE + boottype = 3 + - sles12sp5: + main_vm = VM_NAME_SLES_BTRFS_DEFAULT_SLES12SP5_V2V_EXAMPLE + - raid: + main_vm = VM_NAME_SLES_BTRFS_RAID_V2V_EXAMPLE + skip_vm_check = yes + skip_reason = 'bug RHEL-97179 is not fixed' + boottype = 3 + - encrypted: + main_vm = VM_NAME_SLES_BTRFS_ENCRYPTED_SLES12SP5_V2V_EXAMPLE + skip_vm_check = yes + skip_reason = 'bug RHEL-93583 is not fixed and cannot boot into OS without password automatically' + checkpoint = 'luks_dev_keys' + luks_keys = LUKS_ALL_KEYS + - print_blkhash: + only esx_70 + only libvirt + v2v_debug = force_on + version_required = "[virt-v2v-2.8.1-1,)" + checkpoint = "print_blkhash" + msg_content_yes = "nbdcopy.*--blkhash" + variants: - positive_test: status_error = 'no' diff --git a/v2v/tests/cfg/nbdkit/nbdkit.cfg b/v2v/tests/cfg/nbdkit/nbdkit.cfg index cb3eb820af6..143d60fd4da 100644 --- a/v2v/tests/cfg/nbdkit/nbdkit.cfg +++ b/v2v/tests/cfg/nbdkit/nbdkit.cfg @@ -57,6 +57,30 @@ - protect: version_required = "[nbdkit-server-1.30.8-1,)" checkpoint = 'test_protect_filter' + - ip: + variants: + - security_label: + version_required = "[nbdkit-server-1.36.1-1,)" + checkpoint = 'security_label' + - partition: + variants: + - partition_sectorsize: + sector_size = '512 4k' + version_required = "[nbdkit-server-1.36.2-1,)" + checkpoint = 'partition_sectorsize' + guest_images = 'SECTORSIZE_IMAGES_NFS_V2V_EXAMPLE' + - evil: + version_required = "[nbdkit-server-1.36.1-1,)" + option_evil = 'cosmic-rays stuck-bits stuck-wires' + option_evil_probability = '0.001 1e-6 1:1000000 3.33:100000 1%' + option_evil_seed = '0 1 10000000' + option_evil_stuck_probability = '0.01 0.5 1 20% 100%' + checkpoint = 'test_evil_filter' + - tar: + version_required = "[nbdkit-server-1.36.1-1,)" + option_tar_limit = '0 100K 100G' + option_tar_entry = '0 latest-rhel9.img fake-entry' + checkpoint = 'test_tar_filter' - plugin: variants: - file: @@ -72,7 +96,7 @@ version_required = "[nbdkit-server-1.32.5-4,)" filters = 'cow cacheextents rate readahead scan readahead blocksize' checkpoint = 'check_vddk_filters_thread_model' - - create_options: + - create_options_7: vddk_libdir_src = 'MOUNT_SRC_VDDK70_LIB_DIR_V2V_EXAMPLE' version_required = "[nbdkit-server-1.30.8-1,)" # create_types: vmfs-thin and vmfs-sparse aren't supported @@ -80,6 +104,14 @@ create_adapter_types = 'ide scsi-buslogic scsi-lsilogic' create_hwversions = 'workstation4 workstation5 workstation6 esx30 esx4x esx50 esx51 esx55 esx60 esx65 20' checkpoint = 'check_vddk_create_options' + - create_options_8: + vddk_libdir_src = 'MOUNT_SRC_VDDK80_LIB_DIR_V2V_EXAMPLE' + version_required = "[nbdkit-server-1.38.0-1,)" + # create_types: vmfs-thin and vmfs-sparse aren't supported + create_types = 'monolithic-sparse monolithic-flat split-sparse split-flat vmfs-flat stream-optimized' + create_adapter_types = 'ide scsi-buslogic scsi-lsilogic' + create_hwversions = 'workstation4 workstation5 workstation6 esx30 esx4x esx50 esx51 esx55 esx60 esx65 20' + checkpoint = 'check_vddk_create_options' - ssh: only source_xen..dest_none xen_host_user = 'root' @@ -89,14 +121,28 @@ - create_options: version_required = "[nbdkit-server-1.32.5-4,)" checkpoint = 'test_ssh_create_option' + - ones: + only source_none..dest_none + variants: + - byte: + byte_size = '1 0xff 256' + version_required = "[nbdkit-server-1.36.1-1,)" + checkpoint = 'ones_byte' + - curl: + only source_none..dest_none + variants: + - time: + version_required = "[nbdkit-server-1.36.1-1,)" + checkpoint = 'check_curl_time_option' + external_image_url = EXTERNAL_IMAGE_FAKE_URL - run: variants: - vddk7_0: only source_esx.esx_70..dest_none version_required = "[nbdkit-server-1.20.4-2,)" - checkpoint = 'has_run_againt_vddk7_0' + checkpoint = 'has_run_againt_vddk' vpx_passwd_file = "/tmp/v2v_vpx_passwd" - main_vm = VM_NAME_ESX_NBDKIT_V2V_EXAMPLE + main_vm = VM_NAME_ESX70_NBDKIT_V2V_EXAMPLE variants: - vpx: vsphere_host = ${vpx_hostname} @@ -124,6 +170,35 @@ vsphere_host = ${esx_hostname} vsphere_user = 'root' vsphere_pwd = ${esxi_password} + - vddk8_0: + only source_esx.esx_80..dest_none + version_required = "[nbdkit-server-1.38.0-1,)" + checkpoint = 'has_run_againt_vddk' + vpx_passwd_file = "/tmp/v2v_vpx_passwd" + main_vm = VM_NAME_ESX80_NBDKIT_V2V_EXAMPLE + variants: + - vpx: + vsphere_host = ${vpx_hostname} + vsphere_user = 'root' + vsphere_pwd = ${vpx_password} + variants: + - vddk_stats_1: + checkpoint = 'vddk_stats' + vddk_stats = 1 + - vddk_stats_0: + checkpoint = 'vddk_stats' + vddk_stats = 0 + - no_vddk_stats: + - datapath_controlpath: + checkpoint = 'backend_datapath_controlpath' + - scan_readahead_blocksize: + checkpoint = 'scan_readahead_blocksize' + - delay_close_open_options: + checkpoint = 'vddk_with_delay_close_open_option' + - esx: + vsphere_host = ${esx_hostname} + vsphere_user = 'root' + vsphere_pwd = ${esxi_password} - memory: only source_none..dest_none variants: @@ -150,9 +225,7 @@ - annocheck_test_nbdkit: only source_none..dest_none checkpoint = 'annocheck_test_nbdkit' - rhel9_debug_repo_url = 'RHEL9_DEBUG_REPO_URL' - cve_starttls: only source_none..dest_none checkpoint = 'cve_starttls' - rhel9_appsource_repo_url = RHEL9_APP_SOURCE_URL' - version_required = "[nbdkit-server-1.26.5-1,)" \ No newline at end of file + version_required = "[nbdkit-1.26.5-1,nbdkit-1.40)" diff --git a/v2v/tests/cfg/pyvmomi/query_changed_disk_areas.cfg b/v2v/tests/cfg/pyvmomi/query_changed_disk_areas.cfg deleted file mode 100644 index 944a82c70c3..00000000000 --- a/v2v/tests/cfg/pyvmomi/query_changed_disk_areas.cfg +++ /dev/null @@ -1,18 +0,0 @@ -- query_changed_disk_areas: - type = "query_changed_disk_areas" - vms = '' - only source_esx.esx_67 - only dest_none - - main_vm = VM_NAME_ESX_PYVMOMI_V2V_EXAMPLE - vsphere_host = ${vpx_hostname} - vsphere_user = 'root' - vsphere_pwd = ${vpx_password} - - vm_client = "ssh" - vm_port = 22 - vm_user = 'root' - vm_pwd = GENERAL_GUEST_PASSWORD - vm_prompt = "^\w:\\.*>\s*$|^\[.*\][\#\$]\s*$" - - diff --git a/v2v/tests/cfg/specific_kvm.cfg b/v2v/tests/cfg/specific_kvm.cfg index df25bcfb04c..b3d5763157f 100644 --- a/v2v/tests/cfg/specific_kvm.cfg +++ b/v2v/tests/cfg/specific_kvm.cfg @@ -73,27 +73,21 @@ variants: - default: - sata_disk: - only source_esx.esx_65 + only source_esx.esx_70 version_required = "[libvirt-7.8.0-1,)" main_vm = 'VM_SATA_DISK_V2V_EXAMPLE' libguestfs_backend = 'direct' - multi_disks: variants: - linux: - only source_esx.esx_67 + only source_esx.esx_70 os_type = 'linux' checkpoint = 'multi_disks' vm_user = 'root' vm_pwd = GENERAL_GUEST_PASSWORD main_vm = "VM_MULTI_DISKS_V2V_EXAMPLE" - - windows: - os_type = 'windows' - checkpoint = 'multi_disks' - os_version = 'OS_VERSION_MULTI_DISK_WIN_V2V_EXAMPLE' - main_vm = 'VM_MULTI_DISK_WIN_V2V_EXAMPLE' - only source_esx.esx_65 - multi_kernel: - only source_esx.esx_67 + only source_esx.esx_70 # this case requires '-v -x' v2v_debug = force_on expect_msg = 'yes' @@ -101,10 +95,10 @@ checkpoint = 'multi_kernel' main_vm = 'VM_MULTI_KERNEL_V2V_EXAMPLE' - noyumrepo-rhn: - only esx_67 + only esx_70 main_vm = 'VM_NOYUMREPO_V2V_EXAMPLE' - kdump: - only esx_67 + only esx_70 checkpoint = 'kdump' main_vm = 'VM_KDUMP_V2V_EXAMPLE' expect_msg = 'no' @@ -112,28 +106,28 @@ - fstab: variants: - cdrom: - only source_esx.esx_65 + only source_esx.esx_70 msg_content = 'warning: /files/etc/fstab.*? references unknown device "cdrom"' expect_msg = 'no' main_vm = 'VM_FSTAB_WITH_CDROM_V2V_EXAMPLE' - label: - only source_esx.esx_65 + only source_esx.esx_70 msg_content = 'unknown filesystem label.*' expect_msg = 'no' main_vm = 'VM_FSTAB_WITH_LABEL_V2V_EXAMPLE' - uuid: - only source_esx.esx_65 + only source_esx.esx_70 msg_content = 'unknown filesystem UUID.*' expect_msg = 'no' main_vm = 'VM_FSTAB_WITH_UUID_V2V_EXAMPLE' - sr0: - only source_esx.esx_67 + only source_esx.esx_70 main_vm = 'VM_FSTAB_WITH_SR0_V2V_EXAMPLE' msg_content = 'virt-v2v: warning: /files/etc/fstab/.*? references unknown device "sr"' expect_msg = no skip_vm_check = yes - invalid: - only source_esx.esx_67 + only source_esx.esx_70 msg_content = 'virt-v2v: error: libguestfs error: inspect_os: .*?: augeas parse failure:' expect_msg = 'yes' main_vm = 'VM_INVALID_FSTAB_V2V_EXAMPLE' @@ -143,28 +137,22 @@ expect_msg = 'no' msg_content = 'error: rpmdb' - bogus_kernel: - only esx_67 + only esx_70 main_vm = 'VM_BOGUS_KERNEL_V2V_EXAMPLE' msg_content = 'kernel [\s\S]* in bootloader, as it does not exist' expect_msg = 'yes' enable_legacy_policy = yes - - unclean_fs: - only source_kvm - checkpoint = 'unclean_fs' - main_vm = 'VM_WIN_8_V2V_EXAMPLE' - msg_content = '.*Windows Hibernation or Fast Restart.*' - expect_msg = 'yes' - network: variants: - multi_netcards: - only source_esx.esx_67 + only source_esx.esx_70 main_vm = 'VM_NAME_ESX_MULTI_NETCARDS_V2V_EXAMPLE' checkpoint = 'multi_netcards' - rtl8139: only source_xen main_vm = 'VM_NET_RTL8139_V2V_EXAMPLE' - e1000: - only source_esx.esx_65 + only source_esx.esx_70 os_version = 'OS_VERSION_NET_E1000_V2V_EXAMPLE' main_vm = 'VM_NET_E1000_V2V_EXAMPLE' - only_net: @@ -212,7 +200,7 @@ - vm_disable: checkpoint = 'selinux_disabled' - selinuxtype: - only esx.esx_65 + only esx.esx_70 variants: - min: checkpoint = 'check_selinuxtype' @@ -245,15 +233,12 @@ checkpoint = 'ntpd_on' - sync_ntp: checkpoint = 'sync_ntp' - - no_space: - only esx.esx_67 - checkpoint = 'host_no_space_setcache' + - set_cache_dir: + only esx.esx_70 + checkpoint = 'set_cache_dir' main_vm = 'VM_ESX_DEFAULT_NAME_V2V_EXAMPLE' - - mem_alloc: - only source_kvm - main_vm = VM_MEM_ACCLOC_V2V_EXAMPLE - no_libguestfs_backend: - only esx.esx_67 + only esx.esx_70 main_vm = 'VM_ESX_DEFAULT_NAME_V2V_EXAMPLE' checkpoint = no_libguestfs_backend - file_image: @@ -286,6 +271,41 @@ only source_esx.esx_80 boottype = 2 main_vm = 'VM_NON_EXIST_NETWORK_V2V_EXAMPLE' + - partial_efi: + only source_esx.esx_80 + version_required = "[virt-v2v-2.5.5-1.el9,)" + boottype = 2 + main_vm = 'VM_NAME_80_UBUNTU_PARTIAL_EFI_V2V_EXAMPLE' + skip_vm_check = yes + skip_reason = "Special configuration. No console available" + - serial_port: + only esx_80 + version_required = "[libvirt-10.5.0-4.el9,)" + variants: + - chars_telnet: + only libvirt + boottype = 2 + main_vm = VM_NAME_SERVIAL_PORT_CHARACTERS_TELNET_URL_V2V_EXAMPLE + - empty_info: + boottype = 2 + main_vm = VM_NAME_SERVIAL_PORT_EMPTY_V2V_EXAMPLE + - vmx_char: + only esx_80 + only libvirt + boottype = 2 + main_vm = VM_NAME_VMX_CONTAINS_CHAR_V2V_EXAMPLE + - efi_devicemap: + only esx_80 + boottype = 2 + main_vm = VM_NAME_EFI_GUEST_DEVICE_MAP_FILE_V2V_EXAMPLE + - cmd_output_4M: + only esx_80 + only libvirt + boottype = 2 + main_vm = VM_NAME_SLES_INSTALL_KERNEL_SOURCE_PKG_V2V_EXAMPLE + - vmtools_spausedd: + only esx_70 + main_vm = VM_NAME_OPEM_VM_TOOLS_DEPEND_SPAUSEDD_V2V_EXAMPLE variants: - positive_test: status_error = 'no' @@ -293,14 +313,12 @@ variants: - linux: no default - no unclean_fs no multi_disks.windows no network.e1000 no fstab.invalid no display.mix no win_rootonlinux no non_exist_network - only output_mode.rhev - windows: os_type = 'windows' shutdown_command = 'shutdown /s /f /t 0' @@ -320,14 +338,13 @@ restart_network = 'ipconfig /renew' vm_user = 'Administrator' vm_pwd = DEFAULT_WIN_VM_PASSWORD - only output_mode.rhev variants: - multi_disks: only multi_disks.windows - network: only network.e1000,non_exist_network - to_libvirt: - only display.mix,display.listen,mem_alloc,80_chars + only display.mix,display.listen,80_chars only output_mode.libvirt - to_local: only win_rootonlinux @@ -338,7 +355,7 @@ - not_shutdown: only default.kvm only output_mode.local - msg_content = 'virt-v2v: error:.*is running or paused.*must be shut down' + msg_content = 'virt-v2v: warning:.*Converting a live guest will result in corrupted output.' expect_msg = 'yes' variants: - running: @@ -348,23 +365,21 @@ vm_state = 'paused' checkpoint = ${vm_state} - serial_terminal: - only default.esx.esx_65 - only output_mode.rhev + only default.esx.esx_70 msg_content = 'virt-v2v: error: no kernels were found in the bootloader configuration' expect_msg = 'yes' main_vm = "VM_GUEST_SERIAL_TERMINAL_V2V_EXAMPLE" - no_space: - only output_mode.rhev expect_msg = 'yes' variants: - host: - only default.esx.esx_65 + only default.esx.esx_70 main_vm = "VM_GUEST_NO_SPACE_V2V_EXAMPLE" checkpoint = 'host_no_space' msg_content = 'virt-v2v: error: insufficient free space in the conversion server' - - unclean_file_system: - only unclean_fs - only output_mode.rhev + - guest: + only default.esx.esx_70 + main_vm = "VM_GUEST_NO_SPACE_V2V_EXAMPLE" + msg_content = 'virt-v2v: error: not enough free space for conversion on filesystem' - fstab_invalid: only fstab.invalid - only output_mode.rhev diff --git a/v2v/tests/cfg/v2v_options.cfg b/v2v/tests/cfg/v2v_options.cfg index c8d4b61e78a..d919a164167 100644 --- a/v2v/tests/cfg/v2v_options.cfg +++ b/v2v/tests/cfg/v2v_options.cfg @@ -111,11 +111,6 @@ main_vm = "VM_NAME_ESX_DEFAULT_V2V_EXAMPLE" checkpoint = 'tail_log' msg_content = 'cannot list vcpu pinning for an inactive domain' - - esx_67: - only source_esx.esx_67 - main_vm = "VM_NAME_ESX67_DEFAULT_V2V_EXAMPLE" - variants: - - default: - libvirtxml: only source_none input_mode = "libvirtxml" @@ -141,6 +136,7 @@ only input_mode.none only output_mode.none v2v_options = "--version" + checkpoint = check_version - option_help: only input_mode.none only output_mode.none @@ -240,16 +236,6 @@ mount_point = /vmx_mnt nfs_vmx = NFS_VMX_V2V_EXAMPLE vmx = ${mount_point}/${main_vm}/${main_vm}.vmx - - vmx_ssh: - only input_mode.none - only output_mode.libvirt - esx_ip = ESX_65_HOSTNAME_V2V_EXAMPLE - esx_host_user = "root" - esx_host_passwd = RHV_NODE_PASSWORD - checkpoint = vmx_ssh - main_vm = VM_NAME_VMX_SSH_V2V_EXAMPLE - output_format = qcow2 - vmx = ssh://root@${esx_ip}/vmfs/volumes/esx6.5-function/${main_vm}/${main_vm}.vmx - qemu_session: only input_mode.libvirt.kvm.default only output_mode.libvirt @@ -282,7 +268,7 @@ in_man = 'colours-option' - compress: only output_mode.libvirt - only input_mode.libvirt.esx.esx_67 + only input_mode.libvirt.esx.esx_70 checkpoint = compress new_vm_name = ${main_vm}_compress v2v_options = -of qcow2 --compressed -on ${new_vm_name} @@ -298,7 +284,7 @@ - br: checkpoint += _bridge - rhev_snapshot_id: - only input_mode.libvirt.esx.esx_67 + only input_mode.libvirt.esx.esx_70 only output_mode.rhev - format_convert: only input_mode.libvirtxml @@ -336,9 +322,13 @@ checkpoint = 'weak_dendency' expect_msg = yes msg_content = "Remove 1 Package" + - required_patch: + version_required = "[virt-v2v-2.4.0-1,)" + check_command = "rpm -q --changelog %s" + checkpoint = check_patch - print_estimate: only output_mode.none - only input_mode.libvirt.esx.esx_67 + only input_mode.libvirt.esx.esx_70 v2v_options = '--print-estimate' version_required = "[libguestfs-1.40.1-1,)" variants: @@ -347,12 +337,6 @@ - default: expect_msg = yes msg_content = "disk \d+: \d+%total: \d+" - - remote_libvirt_conn: - only output_mode.null - only input_mode.libvirt.kvm.default - checkpoint = 'remote_libvirt_conn' - expect_msg = yes - msg_content = "no support for remote libvirt connections" - copy_to_local: cmd_free = yes only input_mode.libvirt.xen @@ -364,9 +348,20 @@ only output_mode.none input_disk_image = '/DISK_IMAGE_PATH_V2V_EXAMPLE/IMAGE_WITH_IMMUTABLE_BITS_V2V_EXAMPLE' v2v_options = '-i disk ${input_disk_image} -o null' + - mem_alloc: + only input_mode.none + only output_mode.none + input_disk_image = '/DISK_IMAGE_PATH_V2V_EXAMPLE/IMAGE_WITH_MEM_ALLOC_V2V_EXAMPLE' + v2v_options = '-i disk ${input_disk_image} -o null' - negative_test: status_error = "yes" variants: + - remote_libvirt_conn: + only output_mode.null + only input_mode.libvirt.kvm.default + checkpoint = 'remote_libvirt_conn' + expect_msg = yes + msg_content = "no support for remote libvirt connections" - conflict_options: only input_mode.none only output_mode.none diff --git a/v2v/tests/src/convert_from_file.py b/v2v/tests/src/convert_from_file.py index bc2975aa27f..2338528163a 100644 --- a/v2v/tests/src/convert_from_file.py +++ b/v2v/tests/src/convert_from_file.py @@ -265,8 +265,9 @@ def vm_check(): shutil.copy(src_dir, dest_dir) LOG.info('Copy ova from %s to %s', src_dir, dest_dir) if checkpoint == 'cpu_topology': - dest_ova = os.path.join(dest_dir, input_file) - process.run('tar xvf %s -C %s' % (dest_ova, dest_dir), shell=True) + ova_file = params.get('ova_file_name') + dest_ova = os.path.join(dest_dir, ova_file) + process.run('tar xvf %s -C %s' % (input_file, dest_dir), shell=True) with open(dest_ova[:-1] + 'f') as fd: buf = fd.read() res = re.search('(\d+) virtual CPU', buf) @@ -287,6 +288,11 @@ def vm_check(): log_fail('fail to download guest image from libvirt-ci resource') image_name = re.search(r'RHEL-\S*\w*.qcow2', params.get('image_url')).group() v2v_params.update({'input_file': os.path.join(tmp_path, image_name)}) + if checkpoint == 'virt_v2v_in_place': + output = utils_v2v.cmd_run('/usr/libexec/virt-v2v-in-place -i disk %s/%s' % (tmp_path, image_name)) + log_check = utils_v2v.check_log(params, output.stdout_text) + if log_check: + log_fail(log_check) if output_format: v2v_params.update({'of_format': output_format}) # Create libvirt dir pool @@ -316,13 +322,28 @@ def vm_check(): if checkpoint == 'permission': os.environ['LIBGUESTFS_BACKEND'] = '' process.run('echo $LIBGUESTFS_BACKEND', shell=True) - - v2v_result = utils_v2v.v2v_cmd(v2v_params) + if checkpoint == 'special_character': + v2v_result = utils_v2v.cmd_run(str(utils_v2v.v2v_cmd(v2v_params, cmd_only=True)).replace('.vmx', '.vm*'), + params.get('v2v_dirty_resources')) + elif checkpoint == 'wrong_vmx': + esxi_passwd_file = "/tmp/v2v_esxi_passwd" + with open(esxi_passwd_file, 'w') as f: + f.write(esxi_password) + v2v_cmd = str(utils_v2v.v2v_cmd(v2v_params, cmd_only=True) + ' -ip %s' % esxi_passwd_file) + v2v_result = utils_v2v.cmd_run(v2v_cmd.replace('.vmx', '.vmdk'), params.get('v2v_dirty_resources')) + elif checkpoint == 'no_ssh_agent': + esxi_passwd_file = "/tmp/v2v_esxi_passwd" + with open(esxi_passwd_file, 'w') as f: + f.write(esxi_password) + v2v_cmd = str(utils_v2v.v2v_cmd(v2v_params, cmd_only=True) + ' -ip %s' % esxi_passwd_file) + v2v_result = utils_v2v.cmd_run(v2v_cmd, params.get('v2v_dirty_resources')) + else: + v2v_result = utils_v2v.v2v_cmd(v2v_params) if 'new_name' in v2v_params: vm_name = params['main_vm'] = v2v_params['new_name'] - - check_result(v2v_result, status_error) + if checkpoint != 'virt_v2v_in_place': + check_result(v2v_result, status_error) finally: # Cleanup constant files utils_v2v.cleanup_constant_files(params) diff --git a/v2v/tests/src/function_test_esx.py b/v2v/tests/src/function_test_esx.py index 4e7dcb5f81b..20e81227302 100644 --- a/v2v/tests/src/function_test_esx.py +++ b/v2v/tests/src/function_test_esx.py @@ -4,7 +4,7 @@ import uuid import shutil import tempfile -import ovirtsdk4 +import time import xml.etree.ElementTree as ET from virttest import data_dir @@ -18,7 +18,6 @@ from virttest.utils_test import libvirt from virttest.utils_v2v import params_get from avocado.utils import process -from avocado.utils import download from aexpect.exceptions import ShellProcessTerminatedError, ShellTimeoutError, ShellStatusError from provider.v2v_vmcheck_helper import VMChecker @@ -233,18 +232,34 @@ def check_windows_vmware_tools(vmcheck): :param vmcheck: VMCheck object for vm checking """ - def _get_vmware_info(cmd): + def _get_vmtools_info(cmd): _, res = vmcheck.run_cmd(cmd) - if res and not re.search('vmtools', res, re.I): - return True - return False + vmtools_info = re.search(r'uninstalling VMware Tools\s+.*exit code\s+(\d+)', res) + if vmtools_info: + exit_code = vmtools_info.group(1) + return int(exit_code) - cmds = ['tasklist', 'sc query vmtools'] - for cmd in cmds: - res = utils_misc.wait_for( - lambda: _get_vmware_info(cmd), 600, step=30) - if not res: - test.fail("Failed to verification vmtools uninstallation") + cmd = r'type "C:\Program Files\Guestfs\Firstboot\log.txt"' + + try: + res = utils_misc.wait_for(lambda: _get_vmtools_info(cmd), 900, step=30) + except (ShellProcessTerminatedError, ShellStatusError): + # Windows guest may reboot after installing qemu-ga service + LOG.debug('Windows guest is rebooting') + if vmcheck.session: + vmcheck.session.close() + vmcheck.session = None + # VM boots up is extremely slow when all testing in running on + # rhv server simultaneously, so set timeout to 1200. + vmcheck.create_session(timeout=1200) + res = utils_misc.wait_for(lambda: _get_vmtools_info(cmd), 900, step=30) + + if res: + if os_version in ['win2025', 'win2019'] and str(res) == '1603': + #Some windows guests fail to uninstall vmware tools due to bug RHEL-51169 + LOG.info('%s guest fail to unintall VMware tools with exit code 1603 which is known issue' % os_version) + else: + test.fail("Fail to uninstall VMware-tools with exit code %s" % res) def check_windows_service(vmcheck, service_name): """ @@ -259,7 +274,7 @@ def check_windows_service(vmcheck, service_name): 'running', vmcheck.get_service_info(service_name), re.I), - 600, + 900, step=30) except (ShellProcessTerminatedError, ShellStatusError): # Windows guest may reboot after installing qemu-ga service @@ -275,7 +290,7 @@ def check_windows_service(vmcheck, service_name): 'running', vmcheck.get_service_info(service_name), re.I), - 600, + 900, step=30) if not res: @@ -292,7 +307,10 @@ def get_service_info(): Get qemu-guest-agent service info """ status_ptn = r'Active: active \((running|exited)\)|qemu-ga \(pid +[0-9]+\) is running' - cmd = 'service qemu-ga status;systemctl status qemu-guest-agent;systemctl status qemu-ga*' + if os_version == 'sles': + cmd = 'systemctl status qemu-guest-agent' + else: + cmd = 'service qemu-ga status;systemctl status qemu-guest-agent;systemctl status qemu-ga*' _, output = vmcheck.run_cmd(cmd) if not re.search(status_ptn, output): return False @@ -414,12 +432,14 @@ def _static_ip_check(): # IP address if i == 0: ip_addr = r'IPv4 Address.*?: %s' % value + LOG.info('static ip addr: %s', re.search(ip_addr, ipconfig, re.S)) if not re.search(ip_addr, ipconfig, re.S): LOG.debug('Found IP addr failed') return False # Default gateway if i == 1: ip_gw = r'Default Gateway.*?: .*?%s' % value + LOG.info('static gateway: %s', re.search(ip_gw, ipconfig, re.S)) if not re.search(ip_gw, ipconfig, re.S): LOG.debug('Found Gateway failed') return False @@ -430,12 +450,14 @@ def _static_ip_check(): cidr = '.'.join( [str(int(bin_mask[i * 8:i * 8 + 8], 2)) for i in range(4)]) sub_mask = r'Subnet Mask.*?: %s' % cidr + LOG.info('static subnet mask: %s', re.search(sub_mask, ipconfig, re.S)) if not re.search(sub_mask, ipconfig, re.S): LOG.debug('Found subnet mask failed') return False # DNS server list if i >= 3: dns_server = r'DNS Servers.*?:.*?%s' % value + LOG.info('static DNS: %s', re.search(dns_server, ipconfig, re.S)) if not re.search(dns_server, ipconfig, re.S): LOG.debug('Found DNS Server failed') return False @@ -499,7 +521,7 @@ def _get_real_checksums(algorithm, file): test.fail('%s of rhsrvany.exe is not correct' % key) def verify_certificate(certs_src_dir, certs_dest_dir, vcenter_fdqn, vcenter_ip): - process.run('yum install ca-certificates -y | update-ca-trust enable', shell=True) + process.run('yum install ca-certificates -y | update-ca-trust', shell=True) mount_cert_dir = utils_v2v.v2v_mount(certs_src_dir, 'certs_src_dir') if not os.path.exists(certs_dest_dir): os.makedirs(certs_dest_dir) @@ -509,6 +531,40 @@ def verify_certificate(certs_src_dir, certs_dest_dir, vcenter_fdqn, vcenter_ip): with open('/etc/hosts', "w") as f: f.write('%s %s' % (vcenter_ip, vcenter_fdqn)) + def check_online_disks(vmcheck): + """ + Check if status of disks are online in VM + + :param vmcheck: VMCheck object for vm checking + """ + def _get_disk_status(cmd): + + for i in range(9): + _, res = vmcheck.run_cmd(cmd) + if re.search('Offline', res): + time.sleep(100) + else: + return res + return res + + cmd = r'cmd /c echo list disk^> "%temp%\answer.tmp" ^& (diskpart ^< "%temp%\answer.tmp") ^& ' \ + r'del "%temp%\answer.tmp"' + try: + res = utils_misc.wait_for(lambda: _get_disk_status(cmd), 900) + except (ShellProcessTerminatedError, ShellStatusError): + # Windows guest may reboot after installing qemu-ga service + LOG.debug('Windows guest is rebooting') + if vmcheck.session: + vmcheck.session.close() + vmcheck.session = None + # VM boots up is extremely slow when all testing in running on + # rhv server simultaneously, so set timeout to 1200. + vmcheck.create_session(timeout=1200) + res = utils_misc.wait_for(lambda: _get_disk_status(cmd), 900) + LOG.info('disk status is %s', res) + if re.search('Offline', res): + test.fail("there is offline additional disk") + def check_result(result, status_error): """ Check virt-v2v command result @@ -550,7 +606,7 @@ def vm_check(status_error): # Check guest following the checkpoint document after conversion LOG.info('Checking common checkpoints for v2v') - if 'ogac' in checkpoint: + if checkpoint[0].startswith('ogac'): # windows guests will reboot at any time after qemu-ga is # installed. The process cannot be controlled. In order to # don't break vmchecker.run() process, It's better to put @@ -558,10 +614,7 @@ def vm_check(status_error): # check_windows_ogac, it waits until rebooting completes. vmchecker.checker.create_session() if os_type == 'windows': - services = ['qemu-ga'] - virtio_win_env = os.getenv('VIRTIO_WIN') - if virtio_win_env and 'rhv-guest-tools' in virtio_win_env: - services.append('spice-ga') + services = ['qemu-ga', 'balloon'] for ser in services: check_windows_service(vmchecker.checker, ser) else: @@ -590,6 +643,8 @@ def vm_check(status_error): check_ubuntools(vmchecker.checker) if 'vmware_tools' in checkpoint: check_windows_vmware_tools(vmchecker.checker) + if 'check_online_disks' in checkpoint: + check_online_disks(vmchecker.checker) if 'without_default_net' in checkpoint: if virsh.net_state_dict()[net_name]['active']: log_fail("Bridge virbr0 already started during conversion") @@ -635,7 +690,7 @@ def vm_check(status_error): time_info = re.search(r'.*\d.*Finishing.*off', output).group(0) usetime = re.search(r'\d+\.\d+', str(time_info)).group(0).split('.')[0] LOG.info('use time is %s' % usetime) - if int(usetime) > 300: + if int(usetime) > 800: test.fail("conversion time is too long, please check v2v performance") # Log checking log_check = utils_v2v.check_log(params, output) @@ -646,6 +701,12 @@ def vm_check(status_error): (len(error_list), error_list)) try: + # Added version_required condition due to different versions of v2v for RHEL9 and RHEL10 + # RHEL9 V2V version - "[virt-v2v-2.7.1-12,)" + # RHEL10 V2V version - "[virt-v2v-2.8.1-1,)" + if "print_blkhash" in checkpoint and "el9" in process.run("uname -r", shell=True).stdout_text: + version_required = "[virt-v2v-2.7.1-12,)" + if version_required and not utils_v2v.multiple_versions_compare( version_required): test.cancel("Testing requires version: %s" % version_required) @@ -750,26 +811,10 @@ def vm_check(status_error): os.environ['http_proxy'] = http_proxy os.environ['https_proxy'] = https_proxy if 'ovirtsdk4_pkg' in checkpoint: + import ovirtsdk4 ovirt4_path = os.path.dirname(ovirtsdk4.__file__) dst_ovirt4_path = ovirt4_path + '.bak' os.rename(ovirt4_path, dst_ovirt4_path) - if 'ogac' in checkpoint: - os.environ['VIRTIO_WIN'] = virtio_win_path - if os_type == 'linux' and not utils_v2v.multiple_versions_compare(implementation_change_ver) and os.path.isdir(os.getenv('VIRTIO_WIN')): - export_path = os.getenv('VIRTIO_WIN') - qemu_guest_agent_dir = os.path.join(export_path, qa_path) - if not os.path.exists(qemu_guest_agent_dir) and os.access( - export_path, os.W_OK) and qa_url: - LOG.debug( - 'Not found qemu-guest-agent in virtio-win or rhv-guest-tools-iso,' - ' Try to prepare it manually. This is not a permanent step, once' - ' the official build includes it, this step should be removed.') - os.makedirs(qemu_guest_agent_dir) - rpm_name = os.path.basename(qa_url) - download.get_file( - qa_url, os.path.join( - qemu_guest_agent_dir, rpm_name)) - if 'vddk_error' in checkpoint: fqdn_record = params_get(params, 'fqdn_record') with open('/etc/hosts', 'r+') as fd: @@ -897,8 +942,7 @@ def vm_check(status_error): params['msg_content_yes'] += '' + res_cpu_topology.get('sockets') + '%' params['msg_content_yes'] += '' + res_cpu_topology.get('cores') + '%' params['msg_content_yes'] += '' + res_cpu_topology.get('threads') - if 'empty_cdrom' in checkpoint: - v2v_result = raw_dumpxml + v2v_result = utils_v2v.v2v_cmd(v2v_params) else: if 'exist_uuid' in checkpoint: auto_clean = False diff --git a/v2v/tests/src/install.py b/v2v/tests/src/install.py index c3930e955be..9c7db511e63 100644 --- a/v2v/tests/src/install.py +++ b/v2v/tests/src/install.py @@ -23,7 +23,7 @@ def run(test, params, env): minor_failure = False minor_failure_reasons = [] - sm = software_manager.SoftwareManager() + sm = software_manager.manager.SoftwareManager() for name in params.get("installers", "").split(): installer_obj = installer.make_installer(name, params, test) diff --git a/v2v/tests/src/nbdkit/nbdkit.py b/v2v/tests/src/nbdkit/nbdkit.py index 34d858cf056..5a0f7dddcaf 100644 --- a/v2v/tests/src/nbdkit/nbdkit.py +++ b/v2v/tests/src/nbdkit/nbdkit.py @@ -11,6 +11,7 @@ from virttest.utils_v2v import multiple_versions_compare from virttest.utils_v2v import params_get from virttest import utils_v2v +from virttest.utils_conn import update_crypto_policy LOG = logging.getLogger('avocado.v2v.' + __name__) @@ -26,6 +27,7 @@ def test_filter_stats_fd_leak(): """ check if nbdkit-stats-filter leaks an fd """ + process.run('yum install nbdkit-stats-filter -y', shell=True, ignore_status=True) tmp_logfile = os.path.join(data_dir.get_tmp_dir(), "nbdkit-test.log") cmd = """ nbdkit -U - --filter=log --filter=stats sh - \ @@ -53,7 +55,7 @@ def test_filter_stats_fd_leak(): if count > 0: test.fail('nbdkit-stats-filter leaks %d fd' % count) - def test_has_run_againt_vddk7_0(): + def test_has_run_againt_vddk(): """ check if nbdkit --run + vddk + esx7.0 works. """ @@ -88,12 +90,15 @@ def test_has_run_againt_vddk7_0(): vddk_libdir_src = params_get(params, "vddk_libdir_src") with tempfile.TemporaryDirectory(prefix='vddklib_') as vddk_libdir: utils_misc.mount(vddk_libdir_src, vddk_libdir, 'nfs') + process.run('mkdir /home/vddk_libdir;cp -R %s/* %s' % (vddk_libdir, '/home/vddk_libdir'), + shell=True, ignore_status=True) + utils_misc.umount(vddk_libdir_src, vddk_libdir, 'nfs') vddk_thumbprint = '11' nbdkit_cmd = """ nbdkit -rfv -U - --exportname / \ --filter=cacheextents --filter=retry vddk server=%s user=%s password=+%s vm=%s \ - file='%s' libdir=%s --run 'nbdinfo $uri' thumbprint=%s -""" % (vsphere_host, vsphere_user, vsphere_passwd_file, nbdkit_vm_name, nbdkit_file, vddk_libdir, vddk_thumbprint) + file='%s' libdir=/home/vddk_libdir --run 'nbdinfo $uri' thumbprint=%s +""" % (vsphere_host, vsphere_user, vsphere_passwd_file, nbdkit_vm_name, nbdkit_file, vddk_thumbprint) # get thumbprint by a trick cmd_result = process.run( nbdkit_cmd, shell=True, ignore_status=True) @@ -118,11 +123,10 @@ def test_has_run_againt_vddk7_0(): ' scan-ahead=true scan-clock=true scan-size=2048 scan-forever=true' LOG.info('nbdkit command with scan, readahead and blocksize filters:\n%s' % nbdkit_cmd) if checkpoint == 'vddk_with_delay_close_open_option': - nbdkit_cmd = nbdkit_cmd + ' --filter=delay delay-close=40000ms delay-open=40000ms' + nbdkit_cmd = nbdkit_cmd + ' --filter=delay delay-close=400ms delay-open=400ms' LOG.info('nbdkit command with delay-close and delay-open options:\n%s' % nbdkit_cmd) # Run the final nbdkit command output = process.run(nbdkit_cmd, shell=True).stdout_text - utils_misc.umount(vddk_libdir_src, vddk_libdir, 'nfs') if checkpoint == 'vddk_stats': if vddk_stats == 1 and not re.search( r'VDDK function stats', output): @@ -130,9 +134,9 @@ def test_has_run_againt_vddk7_0(): if vddk_stats == 0 and re.search( r'VDDK function stats', output): test.fail('failed to test vddk_stats') - if checkpoint == 'has_run_againt_vddk7_0' and not re.search( + if checkpoint == 'has_run_againt_vddk' and not re.search( r'export-size', output): - test.fail('failed to test has_run_againt_vddk7_0') + test.fail('failed to test has_run_againt_vddk') if checkpoint == 'backend_datapath_controlpath' and re.search(r'vddk: (open|pread)', output): test.fail('fail to test nbdkit.backend.datapath and nbdkit.backend.controlpath option') if checkpoint == 'scan_readahead_blocksize' and re.search('error', output): @@ -209,7 +213,7 @@ def get_size(h): def pread(h, count, offset): raise RuntimeError("pread") """ - + process.run('yum install nbdkit-python-plugin -y', shell=True, ignore_status=True) python_file_path = os.path.join(data_dir.get_tmp_dir(), "python_check.py") with open(python_file_path, "w") as f: f.write(lines) @@ -361,19 +365,6 @@ def check_vddk_create_options(): utils_misc.umount(vddk_libdir_src, vddk_libdir, 'nfs') def annocheck_test_nbdkit(): - lines = """ -[rhel9-debug] -baseurl = pattern -enabled = 1 -gpgcheck = 0 -name = rhel9-debug - """ - rhel9_debug_repo = os.path.join('/etc/yum.repos.d', 'rhel9-debug.repo') - with open(rhel9_debug_repo, "w") as f: - f.write(lines) - rhel9_debug_repo_url = params.get('rhel9_debug_repo_url') - process.run("sed -i 's/pattern/%s/' /etc/yum.repos.d/rhel9-debug.repo" % rhel9_debug_repo_url, - shell=True, ignore_status=True) tmp_path = data_dir.get_tmp_dir() process.run('yum download nbdkit-server nbdkit-server-debuginfo --destdir=%s' % tmp_path, shell=True, ignore_status=True) @@ -387,9 +378,9 @@ def annocheck_test_nbdkit(): cmd_3_result = process.run(cmd_3, shell=True, ignore_status=True) if re.search('FAIL', cmd_3_result.stdout_text) and len(cmd_3_result.stdout_text) == 0: test.fail('fail to test ndbkit-server rpm package with annocheck tool') - process.run('rm -rf /etc/yum.repos.d/rhel9-debug.repo', shell=True, ignore_status=True) def statsfile_option(): + process.run('yum install nbdkit-stats-filter -y', shell=True, ignore_status=True) tmp_path = data_dir.get_tmp_dir() process.run('nbdkit --filter=exitlast --filter=stats memory 2G statsfile=%s/example.txt' % tmp_path, shell=True, ignore_status=True) @@ -405,11 +396,43 @@ def test_rate_filter(): if re.search('error', cmd.stdout_text): test.fail('fail to test rate filter') + def enable_legacy_cryptography(hostname): + """ + Enable the legacy sha1 algorithm. + """ + ssh_config = ("Host %s\n" + " KexAlgorithms +diffie-hellman-group14-sha1\n" + " MACs +hmac-sha1\n" + " HostKeyAlgorithms +ssh-rsa\n" + " PubkeyAcceptedKeyTypes +ssh-rsa\n" + " PubkeyAcceptedAlgorithms +ssh-rsa") % hostname + + openssl_cnf = (".include /etc/ssl/openssl.cnf\n" + "[openssl_init]\n" + "alg_section = evp_properties\n" + "[evp_properties]\n" + "rh-allow-sha1-signatures = yes") + + with open(os.path.expanduser('~/.ssh/config'), 'w') as fd: + fd.write(ssh_config) + + with open(os.path.expanduser('~/openssl-sha1.cnf'), 'w') as fd: + fd.write(openssl_cnf) + + # export the environment variable + os.environ['OPENSSL_CONF'] = os.path.expanduser('~/openssl-sha1.cnf') + LOG.debug('OPENSSL_CONF is %s' % os.getenv('OPENSSL_CONF')) + def test_ssh_create_option(): xen_host_user = params_get(params, "xen_host_user") xen_host_passwd = params_get(params, "xen_host_passwd") xen_host = params_get(params, "xen_host") # Setup ssh-agent access to xen hypervisor + support_ver = '[virt-v2v-2.0.7-4,)' + if utils_v2v.multiple_versions_compare(support_ver): + enable_legacy_cryptography(xen_host) + else: + update_crypto_policy("LEGACY") LOG.info('set up ssh-agent access ') xen_pubkey, xen_session = utils_v2v.v2v_setup_ssh_key( xen_host, xen_host_user, xen_host_passwd, auto_close=False) @@ -436,11 +459,11 @@ def delay_close_delay_open_options(): if not re.search('0m0', cmd_pass.stderr_text): test.fail('fail to test delay-close option when nbdkit clients are not shutdown') #Set invalid number for delay option - values = ['10secs', '40SECS', '10s', '10MS', '1:'] + values = ['10secs', '40SECS', '10MS', '1:'] for value in values: cmd_num = process.run("nbdkit null --filter=delay delay-open=%s --run 'nbdinfo $uri'" % value, shell=True, ignore_status=True) - if not re.search('could not parse number', cmd_num.stderr_text): + if not re.search('could not parse', cmd_num.stderr_text): test.fail('get unexpected result when set invalid value for nbdkit delay options)') #Check error when nbdkit aborts early cmd_aborts = process.run("nbdkit --filter=delay null delay-close=3 --run 'nbdinfo --size $uri; " @@ -479,8 +502,9 @@ def cow_on_read_path(): shell=True, ignore_status=True) time_2 = process.run("nbdkit file %s --filter=cow --filter=delay rdelay=200ms --run '%s' > %s/time2.log" % (image_path, cmd_inspect, tmp_path), shell=True, ignore_status=True) - if not (int(''.join(filter(str.isdigit, re.search(r'real.*m', time_1.stderr_text).group(0)))) < - int(''.join(filter(str.isdigit, re.search(r'real.*m', time_2.stderr_text).group(0))))): + match_1 = re.search(r'real\s+(\d+)m([\d.]+)s', time_1.stderr_text) + match_2 = re.search(r'real\s+(\d+)m([\d.]+)s', time_2.stderr_text) + if not (int(match_1.group(1))*60+float(match_1.group(2))) < (int(match_2.group(1))*60+float(match_2.group(2))): test.fail('fail to test cow-on-read=/path option') def cow_block_size(): @@ -541,26 +565,13 @@ def cache_min_block_size(): test.fail('fail to test cache-min-block-size option') def cve_starttls(): - lines = """ -[rhel9-appsource] -baseurl = pattern -enabled = 1 -gpgcheck = 0 -name = rhel9-appsource - """ - rhel9_appsource_repo = os.path.join('/etc/yum.repos.d', 'rhel9-appsource.repo') - with open(rhel9_appsource_repo, "w") as f: - f.write(lines) - rhel9_appsource_repo_url = params.get('rhel9_appsource_repo_url') - process.run("sed -i 's/pattern/%s/' /etc/yum.repos.d/rhel9-appsource.repo" % rhel9_appsource_repo_url, - shell=True, ignore_status=True) tmp_path = data_dir.get_tmp_dir() + process.run("yum install libtool rpm-build 'dnf-command(download)' -y", shell=True, ignore_status=True) process.run('yum download --source nbdkit --destdir=%s' % tmp_path, shell=True, ignore_status=True) - process.run('yum install libtool -y', shell=True, ignore_status=True) process.run('cd %s ; rpmbuild -rp %s' % (tmp_path, (process.run('ls %s/nbdkit*.src.rpm' % tmp_path, shell=True). stdout_text.split('/'))[-1].strip('\n')), shell=True) - check_file = process.run('ls /root/rpmbuild/BUILD/nbdkit-*/server/protocol-handshake-newstyle.c', + check_file = process.run('ls /rpmbuild/BUILD/nbdkit-*/server/protocol-handshake-newstyle.c', shell=True).stdout_text.strip('\n') count = 0 with open(check_file, "r") as ff: @@ -574,13 +585,13 @@ def cve_starttls(): def test_protect_filter(): from subprocess import Popen, PIPE, STDOUT protect_data = '"AB" * 32768' - p1 = Popen("nbdkit -f --filter=protect data '%s' protect=0-1023 --run 'nbdsh -u nbd://localhost'" % + p1 = Popen("nbdkit -f --filter=protect data '%s' protect=0-1023 --run 'nbdsh -u $uri'" % protect_data, shell=True, stdout=PIPE, stdin=PIPE, stderr=STDOUT) grep_stdout_1 = p1.communicate(input=b"buf=b'01'*256\nh.pwrite(buf,32768)\nprint(h.pread(512,32768))\n")[0] if re.search('AB', grep_stdout_1.decode()): test.fail('the data is incorrect when write data with protect filter') - p2 = Popen("nbdkit -f --filter=protect data '%s' protect=0-1023 --run 'nbdsh -u nbd://localhost'" % + p2 = Popen("nbdkit -f --filter=protect data '%s' protect=0-1023 --run 'nbdsh -u $uri'" % protect_data, shell=True, stdout=PIPE, stdin=PIPE, stderr=STDOUT) grep_stdout_2 = p2.communicate(input=b"buf=b'01'*256\nh.pwrite(buf,32768)\nprint(h.pread(512,32768))\n" @@ -588,15 +599,111 @@ def test_protect_filter(): if not re.search('Operation not permitted ', grep_stdout_2.decode()): test.fail('fail to test protect filter') + def security_label(): + tmp_path = data_dir.get_tmp_dir() + image_path = os.path.join(tmp_path, 'latest-rhel9.img') + process.run('qemu-img convert -f qcow2 -O raw /var/lib/avocado/data/avocado-vt/images/jeos-27-x86_64.qcow2' + ' %s' % image_path, shell=True) + label = process.run("ps -Z", shell=True, ignore_status=True) + LOG.info("label %s", label) + sec_label = re.search('unconfined_u:unconfined_r:unconfined.*\n', label.stdout_text).group(0).split(' ')[0] + LOG.info("seclabel %s", sec_label) + test_co_label = process.run("nbdkit --filter=ip file %s allow=security:%s deny=all --run 'nbdinfo $uri'" % + (image_path, sec_label), shell=True, ignore_status=True) + test_inco_label = process.run("nbdkit --filter=ip file %s allow=security:%s1 deny=all --run 'nbdinfo $uri'" % + (image_path, sec_label), shell=True, ignore_status=True) + if re.search(" error", test_co_label.stdout_text) or not re.search("error: client not permitted", + test_inco_label.stderr_text): + test.fail('fail to test security label of IP filter') + + def partition_sectorsize(): + sector_size = params_get(params, "sector_size") + guest_images = params_get(params, "guest_images") + with tempfile.TemporaryDirectory(prefix='guestimages_') as images_dir: + utils_misc.mount(guest_images, images_dir, 'nfs') + process.run('cp -R %s/* %s' % (images_dir, '/home'), shell=True, ignore_status=True) + utils_misc.umount(guest_images, images_dir, 'nfs') + image_list = process.run('ls %s/rhel*sector*' % '/home', shell=True).stdout_text.strip(' ').split('\n')[:-1] + for image in image_list: + for size in list(sector_size.split(' ')): + cmd = process.run("nbdkit --filter=partition file %s partition=1 partition-sectorsize=%s --run " + "'nbdinfo $uri'" % (image, size), shell=True, ignore_status=True) + if 'non-efi' not in image and '512' in image and size == '4k' and \ + not re.search('.*try using partition-sectorsize=512', cmd.stderr_text): + test.fail('fail to test 512 image and partition-sectorsize=4k') + if '4k' in image and size == '512' and \ + not re.search('.*try using partition-sectorsize=4k', cmd.stderr_text): + test.fail('fail to test 4k image and partition-sectorsize=512') + elif re.search('nbdkit.*error', cmd.stdout_text): + test.fail('fail to test partition-sectorsize') + + def ones_byte(): + byte_size = params_get(params, "byte_size") + for size in list(byte_size.split(' ')): + cmd = process.run("nbdkit ones size=4M byte=%s --run 'nbdinfo $uri'" % size, shell=True, ignore_status=True) + if size == '1' and not re.search(r'.*\\001\\001', cmd.stdout_text): + test.fail('fail to test ones plugin with byte=1') + if size == 'oxff' and not re.search('ISO-8859 text', cmd.stdout_text): + test.fail('fail to test ones plugin with byte=oxff') + if size == '256' and not re.search('could not parse number', cmd.stderr_text): + test.fail('fail to test ones plugin with byte=256') + + def test_evil_filter(): + tmp_path = data_dir.get_tmp_dir() + image_path = os.path.join(tmp_path, 'latest-rhel9.img') + process.run('qemu-img convert -f qcow2 -O raw /var/lib/avocado/data/avocado-vt/images/jeos-27-x86_64.qcow2' + ' %s' % image_path, shell=True) + option_evil = params_get(params, "option_evil") + option_evil_probability = params_get(params, "option_evil_probability") + option_evil_seed = params_get(params, "option_evil_seed") + option_evil_stuck_probability = params_get(params, "option_evil_stuck_probability") + for mode in list(option_evil.split(' ')): + for probability in list(option_evil_probability.split(' ')): + for seed in list(option_evil_seed.split(' ')): + for stuck_probability in list(option_evil_stuck_probability.split(' ')): + cmd = process.run("nbdkit --filter=evil file %s evil=%s evil-probability=%s evil-seed=%s " + "evil-stuck-probability=%s --run 'nbdcopy -p $uri null:'" % + (image_path, mode, probability, seed, stuck_probability), + shell=True, ignore_status=True) + output = cmd.stdout_text + cmd.stderr_text + if re.search('nbdkit.*error', output): + test.fail('fail to test evil filter') + + def test_tar_filter(): + process.run('yum install nbdkit-tar-filter -y', shell=True, ignore_status=True) + tmp_path = data_dir.get_tmp_dir() + image_path = os.path.join(tmp_path, 'latest-rhel9.img') + process.run('qemu-img convert -f qcow2 -O raw /var/lib/avocado/data/avocado-vt/images/jeos-27-x86_64.qcow2' + ' %s' % image_path, shell=True) + process.run('cd %s ; tar cvf latest-rhel9-image.tar latest-rhel9.img' % tmp_path, shell=True) + option_tar_limit = params_get(params, "option_tar_limit") + option_tar_entry = params_get(params, "option_tar_entry") + for limit in list(option_tar_limit.split(' ')): + for entry in list(option_tar_entry.split(' ')): + cmd = process.run(" nbdkit file %s/latest-rhel9-image.tar --filter=tar tar-entry=%s tar-limit=%s " + "--run 'nbdcopy -p $uri null:'" % (tmp_path, entry, limit), shell=True, ignore_status=True) + output = cmd.stdout_text + cmd.stderr_text + if entry == 'latest-rhel9.img' and re.search('nbdkit.*error', output): + test.fail('fail to test tar filter') + elif entry != 'latest-rhel9.img' and not re.search('nbdkit.*error', output): + test.fail('fail to test tar filter') + + def check_curl_time_option(): + image_url = params_get(params, 'external_image_url') + cmd = process.run("nbdkit -rvf -U - curl %s -D curl.times=1 -D curl.verbose=1 -D curl.verbose.ids=1 " + "--run 'nbdcopy -p $uri null:'" % image_url, shell=True, ignore_status=True) + if not re.search(r'nbdkit: debug: times .*-D curl.times=1.*', cmd.stderr_text): + test.fail('fail to test curl.time option') + if version_required and not multiple_versions_compare( version_required): test.cancel("Testing requires version: %s" % version_required) if checkpoint == 'filter_stats_fd_leak': test_filter_stats_fd_leak() - elif checkpoint in ['has_run_againt_vddk7_0', 'vddk_stats', 'backend_datapath_controlpath', + elif checkpoint in ['has_run_againt_vddk', 'vddk_stats', 'backend_datapath_controlpath', 'scan_readahead_blocksize', 'vddk_with_delay_close_open_option']: - test_has_run_againt_vddk7_0() + test_has_run_againt_vddk() elif checkpoint == 'memory_max_disk_size': test_memory_max_disk_size() elif checkpoint == 'data_corruption': @@ -647,5 +754,17 @@ def test_protect_filter(): cve_starttls() elif checkpoint == 'test_protect_filter': test_protect_filter() + elif checkpoint == 'security_label': + security_label() + elif checkpoint == 'partition_sectorsize': + partition_sectorsize() + elif checkpoint == 'ones_byte': + ones_byte() + elif checkpoint == 'test_evil_filter': + test_evil_filter() + elif checkpoint == 'test_tar_filter': + test_tar_filter() + elif checkpoint == 'check_curl_time_option': + check_curl_time_option() else: test.error('Not found testcase: %s' % checkpoint) diff --git a/v2v/tests/src/pyvmomi/query_changed_disk_areas.py b/v2v/tests/src/pyvmomi/query_changed_disk_areas.py deleted file mode 100644 index 746baffe59e..00000000000 --- a/v2v/tests/src/pyvmomi/query_changed_disk_areas.py +++ /dev/null @@ -1,124 +0,0 @@ -import logging - -from virttest.utils_pyvmomi import VSphere, vim -from virttest.remote import wait_for_login -from virttest.utils_misc import wait_for - -LOG = logging.getLogger('avocado.v2v.' + __name__) - - -def run(test, params, env): - """ - Basic pyvmomi test - - 1) create a snapshot - 2) power on the VM, write some fixed length data to - the second disk. - 3) power off the VM, query the changes and compare - the length of changed area. - """ - - def safe_power_off(conn): - """ - Power off safely - - If the VM is poweroff state, the power_off call - will fail, this function checks the state before - power off operation. - """ - power_state = conn.get_vm_summary()['power_state'] - if power_state != 'poweredOff': - conn.power_off() - - vm_name = params.get("main_vm") - if not vm_name: - test.error('No VM specified') - - # vsphere server's host name or IP address - vsphere_host = params.get("vsphere_host") - # vsphere user - vsphere_user = params.get("vsphere_user") - # vsphere password - vsphere_pwd = params.get("vsphere_pwd") - - # vm boots up timeout value, default is 5 mins - vm_bootup_timeout = params.get("vm_bootup_timeout ", 300) - # vm user - vm_user = params.get("vm_user", 'root') - # vm password - vm_pwd = params.get("vm_pwd") - - # vm remote login client arguments setting - vm_client = params.get("vm_client", 'ssh') - vm_port = params.get("vm_port", 22) - vm_prompt = params.get("vm_prompt", r"[\#\$\[\]%]") - - try: - connect_args = { - 'host': vsphere_host, - 'user': vsphere_user, - 'pwd': vsphere_pwd} - conn = VSphere(**connect_args) - conn.target_vm = vm_name - - # Poweroff the guest first if it is Up. - safe_power_off(conn) - # Remove all snapshots first - conn.remove_all_snapshots() - - # Get disk counts of the VM - if len( - conn.get_hardware_devices( - dev_type=vim.vm.device.VirtualDisk)) < 2: - test.error('The main_vm must have at least two disks') - - # Create a snapshot - conn.create_snapshot() - # Poweron the guest - conn.power_on() - # Wait for VM totally boots up to get the IP address - vm_ipaddr = wait_for( - lambda: conn.get_vm_summary()['ip_address'], - vm_bootup_timeout) - if not vm_ipaddr: - test.fail('Get VM IP address failed') - - LOG.info("VM's (%s) IP address is %s", vm_name, vm_ipaddr) - - conn_kwargs = { - 'client': vm_client, - 'host': vm_ipaddr, - 'port': vm_port, - 'username': vm_user, - 'password': vm_pwd, - 'prompt': vm_prompt} - - vm_session = wait_for_login(**conn_kwargs) - - # Write some fixed length of data - cmd = 'dd if=/dev/urandom of=/dev/sdb bs=6000 count=10000 seek=1000' - res = vm_session.cmd_output(cmd) - LOG.debug('Session outputs:\n%s', res) - - # Power off at once - conn.power_off() - - # Query the changed area - disk_change_info = conn.query_changed_disk_areas( - disk_label='Hard disk 2') - if not disk_change_info.changedArea: - test.fail('Not found any changes') - - total = 0 - for change in disk_change_info.changedArea: - total += change.length - - LOG.info('total change length is %s', total) - if not 60000000 <= total <= 61000000: - test.fail('Unexpected change size') - - finally: - safe_power_off(conn) - # Remove all snapshots first - conn.remove_all_snapshots() - conn.close() diff --git a/v2v/tests/src/specific_kvm.py b/v2v/tests/src/specific_kvm.py index 29ea3d34b41..db126ccd15c 100644 --- a/v2v/tests/src/specific_kvm.py +++ b/v2v/tests/src/specific_kvm.py @@ -2,6 +2,7 @@ import re import logging import string +import time import aexpect import xml.etree.ElementTree as ET @@ -520,8 +521,18 @@ def check_time_keep(vmcheck): Check time drift after conversion. """ LOG.info('Check time drift') - output = vmcheck.session.cmd('chronyc tracking') - LOG.debug(output) + + def chronyc_output(): + for i in range(3): + output = vmcheck.session.cmd('chronyc tracking') + LOG.debug(output) + if 'Not synchronised' in output: + time.sleep(20) + else: + return output + return output + + output = chronyc_output() if 'Not synchronised' in output: log_fail('Time not synchronised') lst_offset = re.search('Last offset *?: *(.*) ', output).group(1) @@ -765,9 +776,9 @@ def check_result(result, status_error): if checkpoint.startswith('host_no_space'): session = aexpect.ShellSession('sh') large_file = create_large_file(session, 800) - if checkpoint == 'host_no_space_setcache': - LOG.info('Set LIBGUESTFS_CACHEDIR=/home') - os.environ['LIBGUESTFS_CACHEDIR'] = '/home' + if checkpoint == 'set_cache_dir': + LOG.info('Set LIBGUESTFS_CACHEDIR=/home') + os.environ['LIBGUESTFS_CACHEDIR'] = '/home' if checkpoint.startswith('network'): change_network_model(checkpoint[8:]) if checkpoint == 'multi_netcards': @@ -835,12 +846,14 @@ def check_result(result, status_error): LOG.info('Set service chronyd on') cmd = ['yum -y install chrony', 'systemctl start chronyd', + 'systemctl enable chronyd', 'chronyc add server %s' % ntp_server] vm_cmd(cmd) if checkpoint == 'sync_ntp': LOG.info('Sync time with %s', ntp_server) cmd = ['yum -y install chrony', 'systemctl start chronyd', + 'systemctl enable chronyd', 'chronyc add server %s' % ntp_server, 'chronyc waitsync'] vm_cmd(cmd) diff --git a/v2v/tests/src/v2v_options.py b/v2v/tests/src/v2v_options.py index 1cedbb26827..f0bc2990c85 100644 --- a/v2v/tests/src/v2v_options.py +++ b/v2v/tests/src/v2v_options.py @@ -477,7 +477,7 @@ def check_alloc(): if output_mode == "libvirt": if "qemu:///session" not in v2v_options and not no_root: virsh.start(vm_name, debug=True, ignore_status=False) - if checkpoint in ['vmx', 'vmx_ssh']: + if checkpoint == 'vmx': vmchecker = VMChecker(test, params, env) params['vmchecker'] = vmchecker params['vmcheck_flag'] = True @@ -515,6 +515,9 @@ def check_alloc(): if checkpoint == 'no_dcpath': if '--dcpath' in output: test.fail('"--dcpath" is not removed') + if checkpoint == 'check_patch': + if not re.search('Fix off-by-one error causing rare crash.*', output): + test.fail('required patch not found') if checkpoint == 'debug_overlays': search = re.search('Overlay saved as(.*)', output) if not search: @@ -582,6 +585,14 @@ def check_alloc(): if not check_result: test.fail( 'Not found disk or xml created by virt-v2v-copy-to-local') + if checkpoint == 'check_version': + get_v2v_version = process.run('rpm -q virt-v2v', shell=True, ignore_status=True) + get_rpm_version = re.search(r'(\d+\.\d+\.\d+-\d+\.el\d+)', str(get_v2v_version.stdout)) + rpm_version = get_rpm_version.group(1) + get_virt_v2v_version = re.search(r'(\d+\.\d+\.\d+).*(\d+\.el\d+)', str(output_stdout)) + virt_v2v_version = get_virt_v2v_version.group(1) + '-' + get_virt_v2v_version.group(2) + if (rpm_version != virt_v2v_version): + test.fail('v2v version is incorrect in v2v version option') log_check = utils_v2v.check_log(params, output) if log_check: @@ -810,18 +821,6 @@ def check_alloc(): input_option = '-i vmx %s' % vmx v2v_options += " -b %s -n %s" % (params.get("output_bridge"), params.get("output_network")) - - if checkpoint == 'vmx_ssh': - esx_user = params.get("esx_host_user", "root") - esx_pwd = params.get("esx_host_passwd") - vmx = params.get('vmx') - esx_pubkey, esx_session = utils_v2v.v2v_setup_ssh_key( - esx_ip, esx_user, esx_pwd, server_type='esx', auto_close=False) - utils_misc.add_identities_into_ssh_agent() - input_option = '-i vmx -it ssh %s' % vmx - v2v_options += " -b %s -n %s" % (params.get("output_bridge"), - params.get("output_network")) - if checkpoint == 'simulate_nfs': simulate_images = params.get("simu_images_path") simulate_vms = params.get("simu_vms_path") @@ -860,6 +859,9 @@ def check_alloc(): # only set error to 'ignore' to avoid exception for RHEL7-84978 if "guestfish" in cmd: error_flag = "replace" + if "changelog" in cmd: + get_v2v_version = process.run('rpm -q virt-v2v', shell=True, ignore_status=True) + cmd = cmd % to_text(get_v2v_version.stdout, errors=error_flag) # Set timeout to kill v2v process before conversion succeed if checkpoint == 'disk_not_exist': @@ -927,9 +929,6 @@ def check_alloc(): if checkpoint == 'vmx': utils_misc.umount(params['nfs_vmx'], params['mount_point'], 'nfs') os.rmdir(params['mount_point']) - if checkpoint == 'vmx_ssh': - utils_v2v.v2v_setup_ssh_key_cleanup(esx_session, esx_pubkey, 'esx') - process.run("ssh-agent -k") if checkpoint == 'simulate_nfs': process.run('rm -rf /tmp/rhv/') if os.path.exists(estimate_file): diff --git a/virttools/tests/cfg/bootc_image_builder/bootc_disk_image_build.cfg b/virttools/tests/cfg/bootc_image_builder/bootc_disk_image_build.cfg new file mode 100644 index 00000000000..4adb7423abb --- /dev/null +++ b/virttools/tests/cfg/bootc_image_builder/bootc_disk_image_build.cfg @@ -0,0 +1,232 @@ +- bootc_image_builder.bib.disk_image_generation: + type = bootc_disk_image_build + only x86_64, aarch64, s390x, ppc64le + start_vm = False + take_regular_screendumps = "no" + start_vm = "no" + output_base_folder = "/var/lib/libvirt/images/output" + # vCenter information + GOVC_URL = "example_url" + GOVC_USERNAME = "username" + GOVC_PASSWORD = "userpassword" + DATA_CENTER = "example_datacenter" + DATA_STORE = "example_datastore" + bib_image_url = "quay.io/centos-bootc/bootc-image-builder:latest" + registry = "quay.io" + config_file_path = "/var/lib/libvirt/images" + variants: + - tls_verify_enable: + enable_tls_verify="true" + - tls_verify_disable: + enable_tls_verify="false" + variants config_json: + - use_config_json: + os_username = "alice" + os_password = "bob" + qcow..upstream_bib: + filesystem_size_set = "yes" + file_dir_set = "yes" + anaconda-iso..upstream_bib..fedora_40: + kickstart = "yes" + use_toml_config = "yes" + anaconda-iso..rhel_9.5_nightly_bib..local_image, anaconda-iso..rhel_9.6_nightly_bib..local_image: + kickstart = "yes" + filesystem_size_set = "yes" + - unuse_config_json: + variants image_ref: + - centos: + variants centos_bootc_image: + - centos9: + container_url = "quay.io/centos-bootc/centos-bootc:stream9" + only use_config_json..tls_verify_disable + x86_64, aarch64: + anaconda-iso.upstream_bib: + signed_container = "yes" + local_container = "yes" + - centos10: + container_url = "quay.io/centos-bootc/centos-bootc:stream10" + only upstream_bib..use_config_json..tls_verify_enable, rhel_10.0_bib..use_config_json..tls_verify_enable, rhel_9.6_nightly_bib..use_config_json..tls_verify_enable, rhel_9.4_nightly_bib..use_config_json..tls_verify_enable + roofs = "xfs" + rhel_9.4_nightly_bib..use_config_json..tls_verify_enable: + roofs = "" + - fedora: + variants fedora_bootc_image: + - fedora_40: + no s390-virtio + only upstream_bib..tls_verify_enable + ownership ="107:107" + container_url = "quay.io/fedora/fedora-bootc:40" + roofs = "ext4" + qcow..upstream_bib: + roofs = "xfs" + - fedora_latest: + only upstream_bib..tls_verify_disable + container_url = "quay.io/fedora/fedora-bootc:latest" + roofs = "xfs" + raw..upstream_bib: + roofs = "ext4" + enable_lvm_disk_partitions = "yes" + anaconda-iso..upstream_bib: + enable_plain_disk_partitions = "yes" + s390-virtio: + container_url = "quay.io/fedora/fedora-bootc:41" + - local_image: + container_base_folder = "/var/lib/libvirt/images" + container_url = "localhost/bootc:eln" + local_container = "yes" + build_container = "registry.stage.redhat.io/rhel9/rhel-bootc:rhel-9.4" + rhel_9.5_nightly_bib: + build_container = "registry.stage.redhat.io/rhel9/rhel-bootc:9.5" + rhel_9.6_nightly_bib, upstream_bib: + build_container = "registry.stage.redhat.io/rhel9/rhel-bootc:9.6" + rhel_10.0_bib: + build_container = "registry.stage.redhat.io/rhel10/rhel-bootc:10.0" + - rhel_9.4: + build_container = "registry.redhat.io/rhel9-eus/rhel-9.4-bootc:9.4" + container_url = "quay.io/wenbaoxin/rhel9test" + only rhel_9.4_bib + - rhel_9.5: + build_container = "registry.redhat.io/rhel9/rhel-bootc:9.5" + container_url = "quay.io/wenbaoxin/rhel9-rhel_bootc" + only rhel_9.5_bib + - rhel_9.5_nightly: + container_url = "registry.stage.redhat.io/rhel9/rhel-bootc:9.5" + only rhel_9.5_nightly_bib + qcow..rhel_9.6_nightly_bib: + enable_lvm_disk_partitions = "yes" + redhat_version_id = "9.5" + no anaconda-iso + - rhel_9.6_nightly: + container_url = "registry.stage.redhat.io/rhel9/rhel-bootc:9.6" + only rhel_9.6_nightly_bib + redhat_version_id = "9.6" + no anaconda-iso + - rhel_10.0_nightly: + container_url = "registry.stage.redhat.io/rhel10/rhel-bootc:10.0" + enable_tls_verify = "false" + redhat_version_id = "10.0" + only rhel_10.0_bib + no anaconda-iso + - cross_build: + local_container = "yes" + manifest = "manifest-test" + container_base_folder = "/var/lib/libvirt/images" + build_container = "quay.io/centos-bootc/centos-bootc-dev:stream9" + container_url = "localhost/manifest-test" + target_arch = "aarch64" + roofs = "btrfs" + enable_btrf_disk_partitions = "yes" + filesystem_size_set = "no" + only qcow..upstream_bib..use_config_json..tls_verify_enable + variants bib_ref: + - upstream_bib: + registry_stage_key = "example_stage_key" + redhat_stage_registry = "registry.stage.redhat.io" + bib_image_url = "quay.io/centos-bootc/bootc-image-builder:latest" + podman_stage_username = "11009103|stage" + podman_stage_password = "example_stage_password" + - rhel_9.4_bib: + podman_redhat_username = "podman_redhat_username" + podman_redhat_password = "podman_redhat_password" + redhat_registry = "registry.redhat.io" + container_base_folder = "/var/lib/libvirt/images" + bib_image_url = "registry.redhat.io/rhel9/bootc-image-builder:9.4" + podman_quay_username = "podman_quay_username" + podman_quay_password = "podman_quay_password" + only rhel_9.4..use_config_json..tls_verify_enable + anaconda-iso..rhel_9.4: + custom_repo = "rhel-9.4.repo" + - rhel_9.4_nightly_bib: + registry_stage_key = "example_stage_key" + redhat_stage_registry = "registry.stage.redhat.io" + bib_image_url = "registry.stage.redhat.io/rhel9/bootc-image-builder:9.4" + key_store_mounted = "/etc/pki:/etc/pki" + podman_stage_username = "11009103|stage" + podman_stage_password = "example_stage_password" + anaconda-iso..local_image: + custom_repo = "rhel-9.4.repo" + compose_url = "example_compose_url" + no cross_build + - rhel_9.5_bib: + podman_redhat_username = "podman_redhat_username" + podman_redhat_password = "podman_redhat_password" + redhat_registry = "registry.redhat.io" + container_base_folder = "/var/lib/libvirt/images" + bib_image_url = "registry.redhat.io/rhel9/bootc-image-builder:9.5" + podman_quay_username = "podman_quay_username" + podman_quay_password = "podman_quay_password" + only rhel_9.5..use_config_json..tls_verify_enable + anaconda-iso..rhel_9.5: + custom_repo = "rhel-9.5.repo" + - rhel_9.5_nightly_bib: + registry_stage_key = "example_stage_key" + redhat_stage_registry = "registry.stage.redhat.io" + bib_image_url = "registry.stage.redhat.io/rhel9/bootc-image-builder:9.5" + key_store_mounted = "/etc/pki:/etc/pki" + podman_stage_username = "11009103|stage" + podman_stage_password = "example_stage_password" + anaconda-iso..local_image: + custom_repo = "rhel-9.5.repo" + compose_url = "example_compose_url" + - rhel_9.6_nightly_bib: + registry_stage_key = "example_stage_key" + redhat_stage_registry = "registry.stage.redhat.io" + bib_image_url = "registry.stage.redhat.io/rhel9/bootc-image-builder:9.6" + key_store_mounted = "/etc/pki:/etc/pki" + podman_stage_username = "11009103|stage" + podman_stage_password = "example_stage_password" + anaconda-iso..local_image: + custom_repo = "rhel-9.6.repo" + compose_url = "example_compose_url" + - rhel_10.0_bib: + registry_stage_key = "example_stage_key" + redhat_stage_registry = "registry.stage.redhat.io" + bib_image_url = "registry.stage.redhat.io/rhel10/bootc-image-builder:10.0" + key_store_mounted = "/etc/pki:/etc/pki" + podman_stage_username = "11009103|stage" + podman_stage_password = "example_stage_password" + anaconda-iso..local_image: + custom_repo = "rhel-10.0.repo" + compose_url = "https://download.eng.bos.redhat.com/rhel-10/nightly/RHEL-10-Public-Beta/RHEL-10.0-20240522.76" + variants: + - ami: + disk_image_type = "ami" + no s390-virtio + output_sub_folder = "image" + output_name = "disk.raw" + aws_secret_folder = "/var/lib/libvirt/images" + aws_access_key_id = "example_aws_access_key_id" + aws_access_key = "example_aws_access_key" + aws_region = "us-east-1" + aws_ami_name = "build_${bib_ref}-${image_ref}-component-bootc-${disk_image_type}" + rhel_9.5_nightly_bib..use_config_json..tls_verify_enable, rhel_9.5_nightly_bib..use_config_json..tls_verify_enable, upstream_bib.centos.centos10.use_config_json.tls_verify_enable: + aws_config_dict = "{'aws.secrets':'${aws_secret_folder}/aws.secrets','aws_ami_name':'${aws_ami_name}','aws_bucket':'bib-component-test','aws_region':'${aws_region}'}" + - qcow: + disk_image_type = "qcow2" + output_sub_folder = "qcow2" + output_name = "disk.qcow2" + - vmdk: + disk_image_type = "vmdk" + output_sub_folder = "vmdk" + output_name = "disk.vmdk" + no s390-virtio + - anaconda-iso: + disk_image_type = "anaconda-iso" + output_sub_folder = "bootiso" + output_name = "install.iso" + - raw: + disk_image_type = "raw" + output_sub_folder = "image" + output_name = "disk.raw" + - vhd: + disk_image_type = "vhd" + output_sub_folder = "vpc" + output_name = "disk.vhd" + no s390-virtio + only upstream_bib, rhel_9.6_nightly_bib, rhel_10.0_bib + - gce: + disk_image_type = "gce" + output_sub_folder = "gce" + output_name = "image.tar.gz" + no s390-virtio + only upstream_bib, rhel_9.6_nightly_bib, rhel_10.0_bib diff --git a/virttools/tests/cfg/bootc_image_builder/bootc_disk_image_install.cfg b/virttools/tests/cfg/bootc_image_builder/bootc_disk_image_install.cfg new file mode 100644 index 00000000000..21aab0d59b6 --- /dev/null +++ b/virttools/tests/cfg/bootc_image_builder/bootc_disk_image_install.cfg @@ -0,0 +1,239 @@ +- bootc_image_builder.bib.disk_image_install: + type = bootc_disk_image_install + only x86_64, aarch64, s390x, ppc64le + start_vm = False + take_regular_screendumps = "no" + start_vm = "no" + output_base_folder = "/var/lib/libvirt/images/output" + libvirt_base_folder = "/var/lib/libvirt/images" + # vCenter information + GOVC_URL = "example_url" + GOVC_USERNAME = "username" + GOVC_PASSWORD = "userpassword" + DATA_CENTER = "example_datacenter" + DATA_STORE = "example_datastore" + bib_image_url = "quay.io/centos-bootc/bootc-image-builder:latest" + registry = "quay.io" + ownership ="107:107" + config_file_path = "/var/lib/libvirt/images" + os_username = "alice" + os_password = "bob" + variants: + - efi: + controller = "scsi" + firmware = "efi" + aws_instance_type = "t3.medium" + aarch64: + aws_instance_type = "c7g.medium" + - bios: + controller = "ide" + firmware = "bios" + aws_instance_type = "m4.large" + aarch64: + aws_instance_type = "m6g.medium" + variants image_ref: + - centos: + variants centos_bootc_image: + - centos9: + container_url = "quay.io/centos-bootc/centos-bootc:stream9" + only bios + - centos10: + container_url = "quay.io/centos-bootc/centos-bootc:stream10" + only efi + only upstream_bib, rhel_10.0_bib, rhel_9.6_nightly_bib, rhel_9.4_nightly_bib + roofs = "ext4" + rhel_9.4_nightly_bib: + roofs = "" + anaconda-iso..upstream_bib: + check_squashfs = "yes" + - fedora: + variants fedora_bootc_image: + - fedora_40: + only upstream_bib + only bios + container_url = "quay.io/fedora/fedora-bootc:40" + roofs = "ext4" + qcow..upstream_bib: + roofs = "xfs" + anaconda-iso..upstream_bib: + kickstart = "yes" + raw..upstream_bib: + filesystem_size_set = "yes" + no s390-virtio + - fedora_latest: + only upstream_bib + only efi + container_url = "quay.io/fedora/fedora-bootc:latest" + roofs = "xfs" + raw..upstream_bib: + roofs = "ext4" + s390-virtio: + container_url = "quay.io/fedora/fedora-bootc:41" + - rhel_9.4: + build_container = "registry.redhat.io/rhel9-eus/rhel-9.4-bootc:9.4" + container_url = "quay.io/wenbaoxin/rhel9test" + only rhel_9.4_bib + - local_image: + container_base_folder = "/var/lib/libvirt/images" + container_url = "localhost/bootc:eln" + local_container = "yes" + build_container = "registry.stage.redhat.io/rhel9/rhel-bootc:rhel-9.4" + rhel_9.5_nightly_bib: + build_container = "registry.stage.redhat.io/rhel9/rhel-bootc:9.5" + fips_enable = "yes" + enable_fips_enable_repo = "yes" + rhel_9.6_nightly_bib, upstream_bib: + build_container = "registry.stage.redhat.io/rhel9/rhel-bootc:9.6" + fips_enable = "yes" + enable_fips_enable_repo = "yes" + anaconda-iso..upstream_bib, anaconda-iso..rhel_9.5_nightly_bib: + fips_enable = "yes" + use_toml_config = "yes" + kickstart = "yes" + enable_fips_enable_repo = "no" + rhel_10.0_bib: + build_container = "registry.stage.redhat.io/rhel10/rhel-bootc:10.0" + - rhel_9.5: + build_container = "registry.redhat.io/rhel9/rhel-bootc:9.5" + container_url = "quay.io/wenbaoxin/rhel9-rhel_bootc" + only rhel_9.5_bib + - rhel_9.5_nightly: + container_url = "registry.stage.redhat.io/rhel9/rhel-bootc:9.5" + enable_tls_verify = "false" + only rhel_9.5_nightly_bib + no anaconda-iso + - rhel_9.6_nightly: + container_url = "registry.stage.redhat.io/rhel9/rhel-bootc:9.6" + enable_tls_verify = "false" + only rhel_9.6_nightly_bib + no anaconda-iso + - rhel_10.0_nightly: + container_url = "registry.stage.redhat.io/rhel10/rhel-bootc:10.0" + enable_tls_verify = "false" + only rhel_10.0_bib + no anaconda-iso + variants bib_ref: + - upstream_bib: + registry_stage_key = "example_stage_key" + redhat_stage_registry = "registry.stage.redhat.io" + bib_image_url = "quay.io/centos-bootc/bootc-image-builder:latest" + podman_stage_username = "11009103|stage" + podman_stage_password = "example_stage_password" + - rhel_9.4_bib: + podman_redhat_username = "podman_redhat_username" + podman_redhat_password = "podman_redhat_password" + redhat_registry = "registry.redhat.io" + container_base_folder = "/var/lib/libvirt/images" + bib_image_url = "registry.redhat.io/rhel9/bootc-image-builder:9.4" + podman_quay_username = "podman_quay_username" + podman_quay_password = "podman_quay_password" + anaconda-iso..rhel_9.4: + custom_repo = "rhel-9.4.repo" + only rhel_9.4 + - rhel_9.4_nightly_bib: + registry_stage_key = "example_stage_key" + redhat_stage_registry = "registry.stage.redhat.io" + bib_image_url = "registry.stage.redhat.io/rhel9/bootc-image-builder:9.4" + key_store_mounted = "/etc/pki:/etc/pki" + podman_stage_username = "11009103|stage" + podman_stage_password = "example_stage_password" + anaconda-iso..local_image: + custom_repo = "rhel-9.4.repo" + compose_url = "example_compose_url" + - rhel_9.5_bib: + podman_redhat_username = "11080659|chwen" + podman_redhat_password = "podman_redhat_password" + redhat_registry = "registry.redhat.io" + container_base_folder = "/var/lib/libvirt/images" + bib_image_url = "registry.redhat.io/rhel9/bootc-image-builder:9.5" + podman_quay_username = "wenbaoxin" + podman_quay_password = "doudou303" + anaconda-iso..rhel_9.5: + custom_repo = "rhel-9.5.repo" + only rhel_9.5 + - rhel_9.5_nightly_bib: + registry_stage_key = "example_stage_key" + redhat_stage_registry = "registry.stage.redhat.io" + bib_image_url = "registry.stage.redhat.io/rhel9/bootc-image-builder:9.5" + key_store_mounted = "/etc/pki:/etc/pki" + podman_stage_username = "11009103|stage" + podman_stage_password = "example_stage_password" + anaconda-iso..local_image: + custom_repo = "rhel-9.5.repo" + compose_url = "example_compose_url" + - rhel_9.6_nightly_bib: + registry_stage_key = "example_stage_key" + redhat_stage_registry = "registry.stage.redhat.io" + bib_image_url = "registry.stage.redhat.io/rhel9/bootc-image-builder:9.6" + key_store_mounted = "/etc/pki:/etc/pki" + podman_stage_username = "11009103|stage" + podman_stage_password = "example_stage_password" + anaconda-iso..local_image: + custom_repo = "rhel-9.6.repo" + compose_url = "example_compose_url" + - rhel_10.0_bib: + registry_stage_key = "example_stage_key" + redhat_stage_registry = "registry.stage.redhat.io" + bib_image_url = "registry.stage.redhat.io/rhel10/bootc-image-builder:10.0" + key_store_mounted = "/etc/pki:/etc/pki" + podman_stage_username = "11009103|stage" + podman_stage_password = "example_stage_password" + anaconda-iso..local_image: + custom_repo = "rhel-10.0.repo" + compose_url = "https://download.eng.bos.redhat.com/rhel-10/nightly/RHEL-10-Public-Beta/RHEL-10.0-20240522.76" + variants: + - ami: + disk_image_type = "ami" + no s390-virtio + output_sub_folder = "image" + output_name = "disk.raw" + aws_secret_folder = "/var/lib/libvirt/images" + aws_access_key_id = "example_aws_access_key_id" + aws_access_key = "example_aws_access_key" + aws_region = "us-east-1" + aws_ami_name = "install_${bib_ref}-${image_ref}-component-bootc-${disk_image_type}" + aws_key_name = "component-bootc-key" + aws_security_group = "example_sg" + aws_vpc_id = "example_vpc" + aws_subnet_id = "example_subnet" + aws_config_dict = "{'aws.secrets':'${aws_secret_folder}/aws.secrets','aws_ami_name':'${aws_ami_name}','aws_bucket':'bib-component-test','aws_region':'${aws_region}'}" + rhel_9.5_nightly_bib..centos.centos9, rhel_9.5_nightly_bib..local_image: + aws_config_dict = {} + rhel_9.6_nightly_bib..centos.centos9, rhel_9.6_nightly_bib..local_image: + aws_config_dict = {} + upstream_bib..centos, upstream_bib..local_image, upstream_bib..fedora.fedora_40: + aws_config_dict = {} + - qcow: + disk_image_type = "qcow2" + output_sub_folder = "qcow2" + output_name = "disk.qcow2" + - vmdk: + disk_image_type = "vmdk" + output_sub_folder = "vmdk" + output_name = "disk.vmdk" + no s390-virtio + local_image: + add_vmware_tool = "yes" + rhel_9.4: + add_vmware_tool = "yes" + - anaconda-iso: + wait_boot_time = 240 + disk_image_type = "anaconda-iso" + output_sub_folder = "bootiso" + output_name = "install.iso" + - raw: + disk_image_type = "raw" + output_sub_folder = "image" + output_name = "disk.raw" + - vhd: + disk_image_type = "vhd" + output_sub_folder = "vpc" + output_name = "disk.vhd" + no s390-virtio + only upstream_bib, rhel_9.6_nightly_bib, rhel_10.0_bib + - gce: + disk_image_type = "gce" + output_sub_folder = "gce" + output_name = "image.tar.gz" + no s390-virtio + only upstream_bib, rhel_9.6_nightly_bib, rhel_10.0_bib diff --git a/virttools/tests/cfg/virt_install/blk_installation.cfg b/virttools/tests/cfg/virt_install/blk_installation.cfg index 8993db76700..93e49f61560 100644 --- a/virttools/tests/cfg/virt_install/blk_installation.cfg +++ b/virttools/tests/cfg/virt_install/blk_installation.cfg @@ -4,4 +4,4 @@ start_vm = False install_tree_url = INSTALL_TREE_URL kickstart_url = KICKSTART_URL - devid = + devid = dasd diff --git a/virttools/tests/cfg/virt_install/hostdev_mdev.cfg b/virttools/tests/cfg/virt_install/hostdev_mdev.cfg index c6b9cf38ccf..a4c8a50cda8 100644 --- a/virttools/tests/cfg/virt_install/hostdev_mdev.cfg +++ b/virttools/tests/cfg/virt_install/hostdev_mdev.cfg @@ -4,4 +4,4 @@ - check_present_inside_guest: only s390-virtio mdev_type = vfio_ccw-io - devid = + devid = dasd diff --git a/virttools/tests/cfg/virt_install/vfio_installation.cfg b/virttools/tests/cfg/virt_install/vfio_installation.cfg index f794d43184b..449721da51f 100644 --- a/virttools/tests/cfg/virt_install/vfio_installation.cfg +++ b/virttools/tests/cfg/virt_install/vfio_installation.cfg @@ -4,4 +4,4 @@ start_vm = False install_tree_url = INSTALL_TREE_URL kickstart_url = KICKSTART_URL - devid = + devid = dasd diff --git a/virttools/tests/src/bootc_image_builder/bootc_disk_image_build.py b/virttools/tests/src/bootc_image_builder/bootc_disk_image_build.py new file mode 100644 index 00000000000..594a5100256 --- /dev/null +++ b/virttools/tests/src/bootc_image_builder/bootc_disk_image_build.py @@ -0,0 +1,153 @@ +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Copyright Red Hat +# +# SPDX-License-Identifier: GPL-2.0 + +# Author: Chunfu Wen +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +import logging +import re +import os + +from avocado.utils import distro +from provider.bootc_image_builder import bootc_image_build_utils as bib_utils + +LOG = logging.getLogger('avocado.' + __name__) +cleanup_files = [] + + +def validate_bib_output(params, test): + """ + Common method to check whether image build output exists + + :param params: class params representing the test parameters + :param test: test object + """ + base_folder = params.get("output_base_folder") + output_sub_folder = params.get("output_sub_folder") + output_name = params.get("output_name") + ownership = params.get("ownership") + full_path = os.path.join(base_folder, output_sub_folder, output_name) + if not os.path.exists(full_path): + test.fail("bootc image build fail to generate outputs for image type: %s" % params.get("disk_image_type")) + if ownership: + formatted_group_user = ':'.join([f"{item}" for item in bib_utils.get_group_and_user_ids(base_folder)]) + if formatted_group_user != ownership: + test.fail(f"The output folder:{base_folder} has wrong setting in group and user ids: {formatted_group_user}") + + # bib_utils.check_bootc_image_version_id(params) + + +def prepare_env_and_execute_bib(params, test): + """ + One method to prepare environment for image build + + :param params: class params representing the test parameters + :param test: test object + """ + disk_image_type = params.get("disk_image_type") + bib_image_url = params.get("bib_image_url", "quay.io/centos-bootc/bootc-image-builder:latest") + image_ref = params.get("image_ref") + bib_ref = params.get("bib_ref") + container_url = params.get("container_url") + local_container = "yes" == params.get("local_container") + build_container = params.get("build_container") + signed_container = "yes" == params.get("signed_container") + + enable_tls_verify = params.get("enable_tls_verify") + config_json = params.get("config_json") + config_json_file = None + use_toml_config = "yes" == params.get("use_toml_config") + + ownership = params.get("ownership") + key_store_mounted = params.get("key_store_mounted") + target_arch = params.get("target_arch") + roofs = params.get("roofs") + + aws_config_dict = eval(params.get("aws_config_dict", '{}')) + options = None + + if image_ref in ['cross_build'] and distro.detect().name in ['rhel']: + test.cancel("rhel doesn't support cross build, it is supported on fedora only") + + bib_utils.install_bib_packages() + if config_json == "use_config_json": + if use_toml_config: + config_json_file = bib_utils.create_config_toml_file(params) + else: + config_json_file = bib_utils.create_config_json_file(params) + if disk_image_type in ["ami"]: + bib_utils.prepare_aws_env(params) + + if bib_ref in ["upstream_bib", "rhel_9.4_nightly_bib", "rhel_9.5_nightly_bib", "rhel_9.6_nightly_bib", "rhel_10.0_bib"]: + auth_file = bib_utils.create_auth_json_file(params) + bib_utils.podman_login_with_auth(auth_file, params.get("redhat_stage_registry")) + options = " -v %s:/run/containers/0/auth.json " % auth_file + bib_utils.podman_login(params.get("podman_stage_username"), params.get("podman_stage_password"), + params.get("redhat_stage_registry")) + + # pull base image and build local image after change + if build_container: + if bib_ref in ["rhel_9.4_bib", "rhel_9.5_bib"]: + bib_utils.podman_login(params.get("podman_redhat_username"), params.get("podman_redhat_password"), + params.get("redhat_registry")) + bib_utils.create_and_build_container_file(params) + + if bib_ref in ["rhel_9.4_bib", "rhel_9.5_bib"]: + bib_utils.podman_push(params.get("podman_quay_username"), params.get("podman_quay_password"), + params.get("registry"), container_url) + + # sign the container image if needed + if signed_container: + LOG.debug(f"Begin sign container image: {container_url}") + container_url = bib_utils.sign_image(params) + LOG.debug(f"End sign container image: {container_url}") + if options is None: + options = " " + root_dir = params.get("config_file_path") + options += f" -v {root_dir}/policy.json:/etc/containers/policy.json -v {root_dir}/bib_lookaside.yaml:/etc/containers/registries.d/bib_lookaside.yaml " + options += f" -v /var/lib/containers/sigstore:/var/lib/containers/sigstore -v {root_dir}/key.gpg:{root_dir}key.gpg " + + # Pull images first + if "local" not in container_url: + bib_utils.podman_pull(container_url) + + result = bib_utils.podman_command_build(bib_image_url, disk_image_type, container_url, config_json_file, + local_container, enable_tls_verify, ownership, + key_store_mounted, target_arch, roofs, options, **aws_config_dict) + if disk_image_type in ['ami'] and len(aws_config_dict) != 0: + match_ami_id_obj = re.search(r'AMI registered:\s(.*)', result.stdout_text) + if match_ami_id_obj is None: + test.fail("Failed to get AWS AMI id") + aws_ami_id = match_ami_id_obj.group(1).strip() + LOG.debug(f"aws_ami_id is: {aws_ami_id}") + params.update({"aws_ami_id": aws_ami_id}) + match_aws_ami_snapshot_id_obj = re.search(r'Snapshot ID:\s(.*)', result.stdout_text) + if match_aws_ami_snapshot_id_obj is None: + test.fail("Failed to get AWS AMI snapshot id") + aws_ami_snapshot_id = match_aws_ami_snapshot_id_obj.group(1).strip() + LOG.debug(f"aws_ami_snapshot_id is: {aws_ami_snapshot_id}") + params.update({"aws_ami_snapshot_id": aws_ami_snapshot_id}) + bib_utils.cleanup_aws_ami_and_snapshot(params) + + +def run(test, params, env): + """ + Test boot container image builder. + Add existing BOOTABLE image to PODMAN (cover RHEL, FEDORA) + Build image from BOOTABLE image with PODMAAN (AWS, QCOW2,RAW, ISO). + Validate PODMAN build image command output. + """ + try: + prepare_env_and_execute_bib(params, test) + # validate build output + validate_bib_output(params, test) + except Exception as ex: + raise ex + finally: + # Clean up files + for file_path in cleanup_files: + if os.path.exists(file_path): + os.remove(file_path) diff --git a/virttools/tests/src/bootc_image_builder/bootc_disk_image_install.py b/virttools/tests/src/bootc_image_builder/bootc_disk_image_install.py new file mode 100644 index 00000000000..f87b6085f1f --- /dev/null +++ b/virttools/tests/src/bootc_image_builder/bootc_disk_image_install.py @@ -0,0 +1,171 @@ +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Copyright Red Hat +# +# SPDX-License-Identifier: GPL-2.0 + +# Author: Chunfu Wen +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +import logging +import re +import os +import platform +import shutil + +from virttest import virsh +from provider.bootc_image_builder import bootc_image_build_utils as bib_utils + +LOG = logging.getLogger('avocado.' + __name__) +cleanup_files = [] + + +def update_bib_env_info(params, test): + """ + Common method to update environment when image build output exists + + :param params: class params representing the test parameters + :param test: test object + """ + base_folder = params.get("output_base_folder") + libvirt_base_folder = params.get("libvirt_base_folder") + output_sub_folder = params.get("output_sub_folder") + output_name = params.get("output_name") + bib_ref = params.get("bib_ref") + firmware = params.get("firmware") + + full_path = os.path.join(base_folder, output_sub_folder, output_name) + if not os.path.exists(full_path): + test.fail("bootc image build fail to generate outputs for image type: %s" % params.get("disk_image_type")) + special_chars = re.sub(r'[.,-]+', '', platform.release()) + converted_disk_image = f"install_{special_chars}_{bib_ref}_{firmware}_{bib_utils.convert_disk_image_name(params)}" + disk_name, _ = os.path.splitext(converted_disk_image) + full_path_dest = os.path.join(libvirt_base_folder, converted_disk_image) + shutil.move(full_path, full_path_dest) + LOG.debug("vm_disk_image_path: %s", full_path_dest) + LOG.debug("vm_name_bootc: %s", disk_name) + cleanup_files.append(full_path_dest) + params.update({'vm_disk_image_path': full_path_dest}) + params.update({'vm_name_bootc': disk_name}) + + if params.get("disk_image_type") == "vhd": + converted_image_from_vhd_qcow2 = bib_utils.convert_vhd_to_qcow2(params) + params.update({'vm_disk_image_path': converted_image_from_vhd_qcow2}) + + if params.get("disk_image_type") == "gce": + untar_raw_image = bib_utils.untar_tgz_to_raw(params) + params.update({'vm_disk_image_path': untar_raw_image}) + cleanup_files.append(untar_raw_image) + + iso_install_path = os.path.join(libvirt_base_folder, f"{disk_name}_{firmware}.qcow2") + params.update({'iso_install_path': iso_install_path}) + cleanup_files.append(iso_install_path) + + +def prepare_env_and_execute_bib(params, test): + """ + One method to prepare environment for image build + + :param params: class params representing the test parameters + :param test: test object + """ + disk_image_type = params.get("disk_image_type") + bib_image_url = params.get("bib_image_url", "quay.io/centos-bootc/bootc-image-builder:latest") + image_ref = params.get("image_ref") + bib_ref = params.get("bib_ref") + container_url = params.get("container_url") + local_container = "yes" == params.get("local_container") + build_container = params.get("build_container") + + enable_tls_verify = params.get("enable_tls_verify", "true") + ownership = params.get("ownership") + key_store_mounted = params.get("key_store_mounted") + roofs = params.get("roofs") + aws_config_dict = eval(params.get("aws_config_dict", '{}')) + options = None + config_json_file = None + use_toml_config = "yes" == params.get("use_toml_config") + + bib_utils.install_bib_packages() + if use_toml_config: + config_json_file = bib_utils.create_config_toml_file(params) + else: + config_json_file = bib_utils.create_config_json_file(params) + if disk_image_type in ["ami"]: + bib_utils.prepare_aws_env(params) + + if bib_ref in ["upstream_bib", "rhel_9.4_nightly_bib", "rhel_9.5_nightly_bib", "rhel_9.6_nightly_bib", "rhel_10.0_bib"]: + auth_file = bib_utils.create_auth_json_file(params) + bib_utils.podman_login_with_auth(auth_file, params.get("redhat_stage_registry")) + options = " -v %s:/run/containers/0/auth.json " % auth_file + bib_utils.podman_login(params.get("podman_stage_username"), params.get("podman_stage_password"), + params.get("redhat_stage_registry")) + + # pull base image and build local image after change + if build_container: + if bib_ref in ["rhel_9.4_bib", "rhel_9.5_bib"]: + bib_utils.podman_login(params.get("podman_redhat_username"), params.get("podman_redhat_password"), + params.get("redhat_registry")) + bib_utils.create_and_build_container_file(params) + if bib_ref in ["rhel_9.4_bib", "rhel_9.5_bib"]: + ownership = None + bib_utils.podman_push(params.get("podman_quay_username"), params.get("podman_quay_password"), + params.get("registry"), container_url) + + # Pull images first + if "local" not in container_url: + bib_utils.podman_pull(container_url) + + result = bib_utils.podman_command_build(bib_image_url, disk_image_type, container_url, config_json_file, + local_container, enable_tls_verify, ownership, + key_store_mounted, None, roofs, options, **aws_config_dict) + if disk_image_type in ['ami'] and len(aws_config_dict) != 0: + match_ami_id_obj = re.search(r'AMI registered:\s(.*)', result.stdout_text) + if match_ami_id_obj is None: + test.fail("Failed to get AWS AMI id") + aws_ami_id = match_ami_id_obj.group(1).strip() + LOG.debug(f"aws_ami_id is: {aws_ami_id}") + params.update({"aws_ami_id": aws_ami_id}) + match_aws_ami_snapshot_id_obj = re.search(r'Snapshot ID:\s(.*)', result.stdout_text) + if match_aws_ami_snapshot_id_obj is None: + test.fail("Failed to get AWS AMI snapshot id") + aws_ami_snapshot_id = match_aws_ami_snapshot_id_obj.group(1).strip() + LOG.debug(f"aws_ami_snapshot_id is: {aws_ami_snapshot_id}") + params.update({"aws_ami_snapshot_id": aws_ami_snapshot_id}) + + +def run(test, params, env): + """ + Test install disk image generated by boot container image builder. + Add existing BOOTABLE image to PODMAN (cover RHEL, FEDORA) + Build image from BOOTABLE image with PODMAAN (AWS, QCOW2,RAW, ISO). + Validate install built out images + """ + disk_image_type = params.get("disk_image_type") + aws_config_dict = eval(params.get("aws_config_dict", '{}')) + try: + prepare_env_and_execute_bib(params, test) + # validate build output + update_bib_env_info(params, test) + if disk_image_type in ["vmdk"]: + bib_utils.create_and_start_vmware_vm(params) + elif disk_image_type in ["qcow2", "raw", "anaconda-iso", "vhd", "gce"]: + # clean up dirty VM if existed + vm_name = params.get("vm_name_bootc") + if vm_name and vm_name in virsh.dom_list().stdout_text: + virsh.undefine(vm_name, options="--nvram", ignore_status=True) + bib_utils.create_qemu_vm(params, env, test) + elif disk_image_type in ["ami"]: + if len(aws_config_dict) != 0: + bib_utils.create_and_start_cloud_vm(params) + else: + bib_utils.create_qemu_vm(params, env, test) + except Exception as ex: + raise ex + finally: + vm_name = params.get("vm_name_bootc") + if vm_name and vm_name in virsh.dom_list().stdout_text: + virsh.undefine(vm_name, options="--nvram", ignore_status=True) + # Clean up files + for file_path in cleanup_files: + if os.path.exists(file_path): + os.remove(file_path) diff --git a/virttools/tests/src/virt_install/blk_installation.py b/virttools/tests/src/virt_install/blk_installation.py index 1f934b9aff7..5fdfefcac1f 100644 --- a/virttools/tests/src/virt_install/blk_installation.py +++ b/virttools/tests/src/virt_install/blk_installation.py @@ -13,6 +13,9 @@ from avocado.utils import process from virttest.utils_misc import cmd_status_output +from virttest.utils_zchannels import SubchannelPaths as paths + +from provider.vfio import ccw logging = log.getLogger("avocado." + __name__) @@ -34,9 +37,9 @@ def run(test, params, env): kickstart_url = params.get("kickstart_url") process.run("curl -k -o /tmp/ks.cfg %s" % kickstart_url) - process.run("chzdev -e %s" % devid) + device = ccw.get_device_info(devid, True) + devid = device[paths.HEADER["Device"]] disk_path = "/dev/disk/by-path/ccw-%s" % devid - cleanup_actions.insert(0, lambda: process.run("chzdev -d %s" % devid)) cmd = ("virt-install --name %s" " --disk %s" diff --git a/virttools/tests/src/virt_install/hostdev_mdev.py b/virttools/tests/src/virt_install/hostdev_mdev.py index 439ddaa5c36..fb3174f5afc 100644 --- a/virttools/tests/src/virt_install/hostdev_mdev.py +++ b/virttools/tests/src/virt_install/hostdev_mdev.py @@ -2,9 +2,12 @@ from avocado.core.exceptions import TestError from provider.vfio.mdev_handlers import MdevHandler +from virttest import virsh from virttest.libvirt_xml.vm_xml import VMXML from virttest.utils_misc import cmd_status_output -from virttest import virsh +from virttest.utils_zchannels import SubchannelPaths as paths + +from provider.vfio import ccw LOG = logging.getLogger('avocado.' + __name__) @@ -76,6 +79,8 @@ def run(test, params, env): try: + device = ccw.get_device_info(devid, True) + devid = device[paths.HEADER["Device"]] vm.undefine() handler = MdevHandler.from_type(mdev_type) disk = get_disk_for_import(vmxml) diff --git a/virttools/tests/src/virt_install/pxe_installation.py b/virttools/tests/src/virt_install/pxe_installation.py index 3c9945ed991..4e1260f616c 100644 --- a/virttools/tests/src/virt_install/pxe_installation.py +++ b/virttools/tests/src/virt_install/pxe_installation.py @@ -1,82 +1,13 @@ import logging as log -import os -from avocado.utils import process - -from virttest import virsh from virttest.utils_misc import cmd_status_output -from virttest.utils_test import libvirt +from provider.virtual_network import tftpboot logging = log.getLogger("avocado." + __name__) cleanup_actions = [] -tftp_dir = "/var/lib/tftpboot" -boot_file = "pxelinux.cfg" -net_name = "tftpnet" - - -def create_tftp_content(install_tree_url, kickstart_url): - """ - Creates the folder for the tftp server, - downloads images assuming they are below /images, - and creates the pxe configuration file - - :param install_tree_url: url of the installation tree - :param kickstart_url: url of the kickstart file - """ - - process.run("mkdir " + tftp_dir, ignore_status=False, shell=True, verbose=True) - cleanup_actions.insert(0, lambda: process.run("rm -rf " + tftp_dir, ignore_status=False, shell=True, verbose=True)) - - pxeconfig_content = """# pxelinux -default linux -label linux -kernel kernel.img -initrd initrd.img -append ip=dhcp inst.repo=%s inst.ks=%s -""" % (install_tree_url, kickstart_url) - - with open(os.path.join(tftp_dir, boot_file), "w") as f: - f.write(pxeconfig_content) - - cmds = [] - - initrd_img_url = install_tree_url + "/images/initrd.img" - kernel_img_url = install_tree_url + "/images/kernel.img" - - cmds.append("curl %s -o %s/initrd.img" % (initrd_img_url, tftp_dir)) - cmds.append("curl %s -o %s/kernel.img" % (kernel_img_url, tftp_dir)) - - cmds.append("chmod -R a+r " + tftp_dir) - cmds.append("chown -R nobody: " + tftp_dir) - cmds.append("chcon -R --reference /usr/sbin/dnsmasq " + tftp_dir) - cmds.append("chcon -R --reference /usr/libexec/libvirt_leaseshelper " + tftp_dir) - - for cmd in cmds: - process.run(cmd, ignore_status=False, shell=True, verbose=True) - - -def create_tftp_network(): - """ - Creates a libvirt network that will serve - the tftp content - """ - - net_params = { - "net_forward": "{'mode':'nat'}", - "net_ip_address": "192.168.150.1", - "dhcp_start_ipv4": "192.168.150.2", - "dhcp_end_ipv4": "192.168.150.254", - "tftp_root": tftp_dir, - "bootp_file": boot_file - } - - net_xml = libvirt.create_net_xml(net_name, net_params) - virsh.net_create(net_xml.xml, debug=True, ignore_status=False) - cleanup_actions.insert(0, lambda: virsh.net_destroy(net_name)) - def run(test, params, env): """ @@ -89,8 +20,8 @@ def run(test, params, env): try: install_tree_url = params.get("install_tree_url") kickstart_url = params.get("kickstart_url") - create_tftp_content(install_tree_url, kickstart_url) - create_tftp_network() + tftpboot.create_tftp_content(install_tree_url, kickstart_url, arch="s390x") + tftpboot.create_tftp_network() cmd = ("virt-install --pxe --name %s" " --disk size=10" @@ -100,7 +31,7 @@ def run(test, params, env): " --wait 10" " --noreboot" " --network network=%s" % - (vm_name, net_name)) + (vm_name, tftpboot.net_name)) cmd_status_output(cmd, shell=True, timeout=600) logging.debug("Installation finished") @@ -117,6 +48,7 @@ def run(test, params, env): finally: if vm and vm.is_alive(): vm.destroy() + tftpboot.cleanup() for action in cleanup_actions: try: action() diff --git a/virttools/tests/src/virt_install/vfio_installation.py b/virttools/tests/src/virt_install/vfio_installation.py index ae8a890c663..1b18bd66c6e 100644 --- a/virttools/tests/src/virt_install/vfio_installation.py +++ b/virttools/tests/src/virt_install/vfio_installation.py @@ -14,6 +14,9 @@ from provider.vfio.mdev_handlers import MdevHandler from virttest.utils_misc import cmd_status_output +from virttest.utils_zchannels import SubchannelPaths as paths + +from provider.vfio import ccw logging = log.getLogger("avocado." + __name__) @@ -37,6 +40,8 @@ def run(test, params, env): process.run("curl -k -o /tmp/ks.cfg %s" % kickstart_url) + device = ccw.get_device_info(devid, True) + devid = device[paths.HEADER["Device"]] handler = MdevHandler.from_type("vfio_ccw-io") mdev_nodedev = handler.create_nodedev(devid=devid) target_address = handler.get_target_address()