def test_dump(): # test virsh_dump cmd_result = virsh.dump(vm_name, dump_file, option="--memory-only", **dargs) if cmd_result.exit_status: test.fail("Failed to virsh dump of domain %s" % vm_name)
def run(test, params, env): """ Test command: virsh dump. This command can dump the core of a domain to a file for analysis. 1. Positive testing 1.1 Dump domain with valid options. 1.2 Avoid file system cache when dumping. 1.3 Compress the dump images to valid/invalid formats. 2. Negative testing 2.1 Dump domain to a non-exist directory. 2.2 Dump domain with invalid option. 2.3 Dump a shut-off domain. """ vm_name = params.get("main_vm", "vm1") vm = env.get_vm(vm_name) options = params.get("dump_options") dump_file = params.get("dump_file", "vm.core") if os.path.dirname(dump_file) is "": dump_file = os.path.join(test.tmpdir, dump_file) dump_image_format = params.get("dump_image_format") 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" timeout = int(params.get("timeout", "5")) qemu_conf = "/etc/libvirt/qemu.conf" def check_domstate(actual, options): """ Check the domain status according to dump options. """ if options.find('live') >= 0: domstate = "running" if options.find('crash') >= 0 or options.find('reset') > 0: domstate = "running" if paused_after_start_vm: domstate = "paused" elif options.find('crash') >= 0: domstate = "shut off" if options.find('reset') >= 0: domstate = "running" elif options.find('reset') >= 0: domstate = "running" if paused_after_start_vm: domstate = "paused" else: domstate = "running" if paused_after_start_vm: domstate = "paused" if not start_vm: domstate = "shut off" logging.debug("Domain should %s after run dump %s", domstate, options) return (domstate == actual) def check_dump_format(dump_image_format, dump_file): """ Check the format of dumped file. If 'dump_image_format' is not specified or invalid in qemu.conf, then the file shoule be normal raw file, otherwise it shoud be compress to specified format, the supported compress format including: lzop, gzip, bzip2, and xz. """ valid_format = ["lzop", "gzip", "bzip2", "xz"] if len(dump_image_format) == 0 or dump_image_format not in valid_format: logging.debug("No need check the dumped file format") return True else: file_cmd = "file %s" % dump_file (status, output) = commands.getstatusoutput(file_cmd) if status: logging.error("Fail to check dumped file %s", 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(): logging.error("Compress dumped file to %s fail: %s" % (dump_image_format, actual_format)) return False else: return True # Configure dump_image_format in /etc/libvirt/qemu.conf. if len(dump_image_format): conf_cmd = ("echo dump_image_format = \\\"%s\\\" >> %s" % (dump_image_format, qemu_conf)) if os.system(conf_cmd): logging.error("Config dump_image_format to %s fail", dump_image_format) utils_libvirtd.libvirtd_restart() if not utils_libvirtd.libvirtd_is_running(): raise error.TestNAError("libvirt service is not running!") # Deal with bypass-cache option child_pid = 0 if options.find('bypass-cache') >= 0: pid = os.fork() if pid: # Guarantee check_bypass function has run before dump child_pid = pid try: wait_pid_active(pid, timeout) finally: os.kill(child_pid, signal.SIGUSR1) else: check_bypass(dump_file) # Wait for parent process over while True: time.sleep(1) # Run virsh command cmd_result = virsh.dump(vm_name, dump_file, options, ignore_status=True, debug=True) status = cmd_result.exit_status try: logging.info("Start check result") if not check_domstate(vm.state(), options): raise error.TestFail("Domain status check fail.") if status_error: if not status: raise error.TestFail("Expect fail, but run successfully") else: if status: raise error.TestFail("Expect succeed, but run fail") if not os.path.exists(dump_file): raise error.TestFail("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: raise error.TestFail("The format of dumped file is wrong.") finally: if child_pid: os.kill(child_pid, signal.SIGUSR1) if os.path.isfile(dump_file): os.remove(dump_file) if len(dump_image_format): clean_qemu_conf = "sed -i '$d' %s " % qemu_conf if os.system(clean_qemu_conf): raise error.TestFail("Fail to recover %s", qemu_conf)
% dump_guest_core) else: logging.info("Find dump-guest-core=%s in qemum cmdline", dump_guest_core) # Deal with bypass-cache option if options.find('bypass-cache') >= 0: vm.wait_for_login() result_dict = multiprocessing.Manager().dict() child_process = multiprocessing.Process(target=check_bypass, 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") else: if status: test.fail("Expect succeed, but run fail")
def run(test, params, env): """ Test command: virsh dump. This command can dump the core of a domain to a file for analysis. 1. Positive testing 1.1 Dump domain with valid options. 1.2 Avoid file system cache when dumping. 1.3 Compress the dump images to valid/invalid formats. 2. Negative testing 2.1 Dump domain to a non-exist directory. 2.2 Dump domain with invalid option. 2.3 Dump a shut-off domain. """ vm_name = params.get("main_vm", "vm1") vm = env.get_vm(vm_name) options = params.get("dump_options") dump_file = params.get("dump_file", "vm.core") dump_dir = params.get("dump_dir", data_dir.get_tmp_dir()) if os.path.dirname(dump_file) is "": dump_file = os.path.join(dump_dir, dump_file) dump_image_format = params.get("dump_image_format") 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" check_bypass_timeout = int(params.get("check_bypass_timeout", "120")) memory_dump_format = params.get("memory_dump_format", "") uri = params.get("virsh_uri") unprivileged_user = params.get('unprivileged_user') if unprivileged_user: if unprivileged_user.count('EXAMPLE'): unprivileged_user = '******' if not libvirt_version.version_compare(1, 1, 1): if params.get('setup_libvirt_polkit') == 'yes': test.cancel("API acl test not supported in current" " libvirt version.") def check_flag(file_flags): """ Check if file flag include O_DIRECT. :param file_flags: The flags of dumped file Note, O_DIRECT(direct disk access hint) is defined as: on x86_64: #define O_DIRECT 00040000 on ppc64le or arch64: #define O_DIRECT 00200000 """ arch = platform.machine() file_flag_check = int('00040000', 16) if 'ppc64' in arch or 'aarch64' in arch: file_flag_check = int('00200000', 16) if int(file_flags, 16) & file_flag_check == file_flag_check: logging.info("File flags include O_DIRECT") return True else: logging.error("File flags doesn't include O_DIRECT") return False def check_bypass(dump_file, result_dict): """ Get the file flags of domain core dump file and check it. """ error = '' cmd1 = "lsof -w %s" % dump_file while True: if not os.path.exists(dump_file) or process.system(cmd1): time.sleep(0.1) continue cmd2 = ("cat /proc/$(%s |awk '/libvirt_i/{print $2}')/fdinfo/1" "|grep flags|awk '{print $NF}'" % cmd1) ret = process.run(cmd2, allow_output_check='combined', shell=True) status, output = ret.exit_status, ret.stdout_text.strip() if status: error = "Fail to get the flags of dumped file" logging.error(error) break if not len(output): continue try: logging.debug("The flag of dumped file: %s", output) if check_flag(output): logging.info("Bypass file system cache " "successfully when dumping") break else: error = "Bypass file system cache fail when dumping" logging.error(error) break except (ValueError, IndexError) as detail: error = detail logging.error(error) break result_dict['bypass'] = error def check_domstate(actual, options): """ Check the domain status according to dump options. """ if options.find('live') >= 0: domstate = "running" if options.find('crash') >= 0 or options.find('reset') > 0: domstate = "running" if paused_after_start_vm: domstate = "paused" elif options.find('crash') >= 0: domstate = "shut off" if options.find('reset') >= 0: domstate = "running" elif options.find('reset') >= 0: domstate = "running" if paused_after_start_vm: domstate = "paused" else: domstate = "running" if paused_after_start_vm: domstate = "paused" if not start_vm: domstate = "shut off" logging.debug("Domain should %s after run dump %s", domstate, options) return (domstate == actual) def check_dump_format(dump_image_format, dump_file): """ Check the format of dumped file. If 'dump_image_format' is not specified or invalid in qemu.conf, then the file shoule be normal raw file, otherwise it shoud be compress to specified format, the supported compress format including: lzop, gzip, bzip2, and xz. For memory-only dump, the default dump format is ELF, and it can also specify format by --format option, the result could be 'elf' or 'data'. """ valid_format = ["lzop", "gzip", "bzip2", "xz", 'elf', 'data'] if len(dump_image_format) == 0 or dump_image_format not in valid_format: logging.debug("No need check the dumped file format") return True else: file_cmd = "file %s" % dump_file ret = process.run(file_cmd, allow_output_check='combined', shell=True) status, output = ret.exit_status, ret.stdout_text.strip() if status: logging.error("Fail to check dumped file %s", 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(): logging.error("Compress dumped file to %s fail: %s" % (dump_image_format, actual_format)) return False else: return True # Configure dump_image_format in /etc/libvirt/qemu.conf. qemu_config = utils_config.LibvirtQemuConfig() libvirtd = utils_libvirtd.Libvirtd() # Install lsof pkg if not installed if not utils_package.package_install("lsof"): test.cancel("Failed to install lsof in host\n") if len(dump_image_format): qemu_config.dump_image_format = dump_image_format libvirtd.restart() # Deal with memory-only dump format if len(memory_dump_format): # Make sure libvirt support this option if virsh.has_command_help_match("dump", "--format") is None: test.cancel("Current libvirt version doesn't support" " --format option for dump command") # Make sure QEMU support this format query_cmd = '{"execute":"query-dump-guest-memory-capability"}' qemu_capa = virsh.qemu_monitor_command(vm_name, query_cmd).stdout if (memory_dump_format not in qemu_capa) and not status_error: test.cancel("Unsupported dump format '%s' for" " this QEMU binary" % memory_dump_format) options += " --format %s" % memory_dump_format if memory_dump_format == 'elf': dump_image_format = 'elf' if memory_dump_format in ['kdump-zlib', 'kdump-lzo', 'kdump-snappy']: dump_image_format = 'data' # Back up xml file vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) backup_xml = vmxml.copy() dump_guest_core = params.get("dump_guest_core", "") if dump_guest_core not in ["", "on", "off"]: test.error("invalid dumpCore value: %s" % dump_guest_core) try: # Set dumpCore in guest xml if dump_guest_core: if vm.is_alive(): vm.destroy(gracefully=False) vmxml.dumpcore = dump_guest_core vmxml.sync() vm.start() # check qemu-kvm cmdline vm_pid = vm.get_pid() cmd = "cat /proc/%d/cmdline|xargs -0 echo" % vm_pid cmd += "|grep dump-guest-core=%s" % dump_guest_core result = process.run(cmd, ignore_status=True, shell=True) logging.debug("cmdline: %s" % result.stdout_text) if result.exit_status: test.fail("Not find dump-guest-core=%s in qemu cmdline" % dump_guest_core) else: logging.info("Find dump-guest-core=%s in qemum cmdline", dump_guest_core) # Deal with bypass-cache option if options.find('bypass-cache') >= 0: vm.wait_for_login() result_dict = multiprocessing.Manager().dict() child_process = multiprocessing.Process(target=check_bypass, 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") 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']) finally: backup_xml.sync() qemu_config.restore() libvirtd.restart() if os.path.isfile(dump_file): os.remove(dump_file)
def run(test, params, env): """ Test command: virsh domstate. 1.Prepare test environment. 2.When the libvirtd == "off", stop the libvirtd service. 3.Perform virsh domstate operation. 4.Recover test environment. 5.Confirm the test result. """ vm_name = params.get("main_vm", "avocado-vt-vm1") vm = env.get_vm(vm_name) libvirtd_state = params.get("libvirtd", "on") vm_ref = params.get("domstate_vm_ref") status_error = (params.get("status_error", "no") == "yes") extra = params.get("domstate_extra", "") vm_action = params.get("domstate_vm_action", "") vm_oncrash_action = params.get("domstate_vm_oncrash") reset_action = "yes" == params.get("reset_action", "no") dump_option = params.get("dump_option", "") start_action = params.get("start_action", "normal") kill_action = params.get("kill_action", "normal") check_libvirtd_log = params.get("check_libvirtd_log", "no") err_msg = params.get("err_msg", "") remote_uri = params.get("remote_uri") domid = vm.get_id() domuuid = vm.get_uuid() if vm_ref == "id": vm_ref = domid elif vm_ref == "hex_id": vm_ref = hex(int(domid)) elif vm_ref.find("invalid") != -1: vm_ref = params.get(vm_ref) elif vm_ref == "name": vm_ref = vm_name elif vm_ref == "uuid": vm_ref = domuuid # Back up xml file. vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) backup_xml = vmxml.copy() # Back up qemu.conf qemu_conf = utils_config.LibvirtQemuConfig() libvirtd = utils_libvirtd.Libvirtd() # Config libvirtd log if check_libvirtd_log == "yes": libvirtd_conf = utils_config.LibvirtdConfig() libvirtd_log_file = os.path.join(data_dir.get_tmp_dir(), "libvirtd.log") libvirtd_conf["log_level"] = '1' libvirtd_conf["log_filters"] = ('"1:json 1:libvirt 1:qemu 1:monitor ' '3:remote 4:event"') libvirtd_conf["log_outputs"] = '"1:file:%s"' % libvirtd_log_file logging.debug("the libvirtd config file content is:\n %s" % libvirtd_conf) libvirtd.restart() # Get image file image_source = vm.get_first_disk_devices()['source'] logging.debug("image source: %s" % image_source) new_image_source = image_source + '.rename' dump_path = os.path.join(data_dir.get_tmp_dir(), "dump/") logging.debug("dump_path: %s", dump_path) try: os.mkdir(dump_path) except OSError: # If the path already exists then pass pass dump_file = "" try: # Let's have guest memory less so that dumping core takes # time which doesn't timeout the testcase if vm_oncrash_action in ['coredump-destroy', 'coredump-restart']: memory_value = int(params.get("memory_value", "2097152")) memory_unit = params.get("memory_unit", "KiB") vmxml.set_memory(memory_value) vmxml.set_memory_unit(memory_unit) logging.debug(vmxml) vmxml.sync() if vm_action == "crash": if vm.is_alive(): vm.destroy(gracefully=False) vmxml.on_crash = vm_oncrash_action if not vmxml.xmltreefile.find('devices').findall('panic'): # Add <panic> 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 qemu_conf.auto_dump_path = dump_path libvirtd.restart() if vm_oncrash_action in ['coredump-destroy', 'coredump-restart']: dump_file = dump_path + "*" + vm_name[:20] + "-*" # Start VM and check the panic device virsh.start(vm_name, ignore_status=False) vmxml_new = vm_xml.VMXML.new_from_dumpxml(vm_name) # Skip this test if no panic device find if not vmxml_new.xmltreefile.find('devices').findall('panic'): test.cancel("No 'panic' device in the guest. Maybe your " "libvirt version doesn't support it.") try: if vm_action == "suspend": virsh.suspend(vm_name, ignore_status=False) elif vm_action == "resume": virsh.suspend(vm_name, ignore_status=False) virsh.resume(vm_name, ignore_status=False) elif vm_action == "destroy": virsh.destroy(vm_name, ignore_status=False) elif vm_action == "start": virsh.destroy(vm_name, ignore_status=False) if start_action == "rename": # rename the guest image file to make guest fail to start os.rename(image_source, new_image_source) virsh.start(vm_name, ignore_status=True) else: virsh.start(vm_name, ignore_status=False) if start_action == "restart_libvirtd": libvirtd.restart() elif vm_action == "kill": if kill_action == "stop_libvirtd": libvirtd.stop() utils_misc.kill_process_by_pattern(vm_name) libvirtd.restart() elif kill_action == "reboot_vm": virsh.reboot(vm_name, ignore_status=False) utils_misc.kill_process_tree(vm.get_pid(), signal.SIGKILL) else: utils_misc.kill_process_tree(vm.get_pid(), signal.SIGKILL) elif vm_action == "crash": session = vm.wait_for_login() session.cmd("service kdump stop", ignore_all_errors=True) # Enable sysRq session.cmd("echo 1 > /proc/sys/kernel/sysrq") # Send key ALT-SysRq-c to crash VM, and command will not # return as vm crashed, so fail early for 'destroy' and # 'preserve' action. For 'restart', 'coredump-restart' # and 'coredump-destroy' actions, they all need more time # to dump core file or restart OS, so using the default # session command timeout(60s) try: if vm_oncrash_action in ['destroy', 'preserve']: timeout = 3 else: timeout = 60 session.cmd("echo c > /proc/sysrq-trigger", timeout=timeout) except (ShellTimeoutError, ShellProcessTerminatedError): pass session.close() elif vm_action == "dump": dump_file = dump_path + "*" + vm_name + "-*" virsh.dump(vm_name, dump_file, dump_option, ignore_status=False) except process.CmdError as detail: test.error("Guest prepare action error: %s" % detail) if libvirtd_state == "off": libvirtd.stop() # Timing issue cause test to check domstate before prior action # kill gets completed if vm_action == "kill": utils_misc.wait_for(vm.is_dead, timeout=20) if remote_uri: remote_ip = params.get("remote_ip", "REMOTE.EXAMPLE.COM") remote_pwd = params.get("remote_pwd", None) remote_user = params.get("remote_user", "root") if remote_ip.count("EXAMPLE.COM"): test.cancel("Test 'remote' parameters not setup") ssh_key.setup_ssh_key(remote_ip, remote_user, remote_pwd) result = virsh.domstate(vm_ref, extra, ignore_status=True, debug=True, uri=remote_uri) status = result.exit_status output = result.stdout.strip() # check status_error if status_error: if not status: if libvirtd_state == "off" and libvirt_version.version_compare( 5, 6, 0): logging.info( "From libvirt version 5.6.0 libvirtd is restarted " "and command should succeed.") else: test.fail("Run successfully with wrong command!") else: if status or not output: test.fail("Run failed with right command") if extra.count("reason"): if vm_action == "suspend": # If not, will cost long time to destroy vm virsh.destroy(vm_name) if not output.count("user"): test.fail(err_msg % vm_action) elif vm_action == "resume": if not output.count("unpaused"): test.fail(err_msg % vm_action) elif vm_action == "destroy": if not output.count("destroyed"): test.fail(err_msg % vm_action) elif vm_action == "start": if start_action == "rename": if not output.count("shut off (failed)"): test.fail(err_msg % vm_action) else: if not output.count("booted"): test.fail(err_msg % vm_action) elif vm_action == "kill": if not output.count("crashed"): test.fail(err_msg % vm_action) elif vm_action == "crash": if not check_crash_state(output, vm_oncrash_action, vm_name, dump_file): test.fail(err_msg % vm_action) # VM will be in preserved state, perform virsh reset # and check VM reboots and domstate reflects running # state from crashed state as bug is observed here if vm_oncrash_action == "preserve" and reset_action: virsh_dargs = {'debug': True, 'ignore_status': True} ret = virsh.reset(vm_name, **virsh_dargs) libvirt.check_exit_status(ret) ret = virsh.domstate(vm_name, extra, **virsh_dargs).stdout.strip() if "paused (crashed)" not in ret: test.fail("vm fails to change state from crashed" " to paused after virsh reset") # it will be in paused (crashed) state after reset # and resume is required for the vm to reboot ret = virsh.resume(vm_name, **virsh_dargs) libvirt.check_exit_status(ret) vm.wait_for_login() cmd_output = virsh.domstate(vm_name, '--reason').stdout.strip() if "running" not in cmd_output: test.fail("guest state failed to get updated") if vm_oncrash_action in [ 'coredump-destroy', 'coredump-restart' ]: if not find_dump_file: test.fail("Core dump file is not created in dump " "path: %s" % dump_path) # For cover bug 1178652 if (vm_oncrash_action == "rename-restart" and check_libvirtd_log == "yes"): libvirtd.restart() if not os.path.exists(libvirtd_log_file): test.fail("Expected VM log file: %s not exists" % libvirtd_log_file) cmd = ("grep -nr '%s' %s" % (err_msg, libvirtd_log_file)) if not process.run(cmd, ignore_status=True, shell=True).exit_status: test.fail( "Find error message %s from log file: %s." % (err_msg, libvirtd_log_file)) elif vm_action == "dump": if dump_option == "--live": if not output.count("running (unpaused)"): test.fail(err_msg % vm_action) elif dump_option == "--crash": if not output.count("shut off (crashed)"): test.fail(err_msg % vm_action) if vm_ref == "remote": if not (re.search("running", output) or re.search( "blocked", output) or re.search("idle", output)): test.fail("Run failed with right command") finally: qemu_conf.restore() if check_libvirtd_log == "yes": libvirtd_conf.restore() if os.path.exists(libvirtd_log_file): os.remove(libvirtd_log_file) libvirtd.restart() if vm_action == "start" and start_action == "rename": os.rename(new_image_source, image_source) if vm.is_alive(): vm.destroy(gracefully=False) backup_xml.sync() if os.path.exists(dump_path): shutil.rmtree(dump_path)
def run(test, params, env): """ Test command: virsh dump. This command can dump the core of a domain to a file for analysis. 1. Positive testing 1.1 Dump domain with valid options. 1.2 Avoid file system cache when dumping. 1.3 Compress the dump images to valid/invalid formats. 2. Negative testing 2.1 Dump domain to a non-exist directory. 2.2 Dump domain with invalid option. 2.3 Dump a shut-off domain. """ vm_name = params.get("main_vm", "vm1") vm = env.get_vm(vm_name) options = params.get("dump_options") dump_file = params.get("dump_file", "vm.core") if os.path.dirname(dump_file) is "": dump_file = os.path.join(test.tmpdir, dump_file) dump_image_format = params.get("dump_image_format") 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" timeout = int(params.get("timeout", "5")) memory_dump_format = params.get("memory_dump_format", "") uri = params.get("virsh_uri") unprivileged_user = params.get('unprivileged_user') if unprivileged_user: if unprivileged_user.count('EXAMPLE'): unprivileged_user = '******' if not libvirt_version.version_compare(1, 1, 1): if params.get('setup_libvirt_polkit') == 'yes': raise error.TestNAError("API acl test not supported in current" " libvirt version.") def check_domstate(actual, options): """ Check the domain status according to dump options. """ if options.find('live') >= 0: domstate = "running" if options.find('crash') >= 0 or options.find('reset') > 0: domstate = "running" if paused_after_start_vm: domstate = "paused" elif options.find('crash') >= 0: domstate = "shut off" if options.find('reset') >= 0: domstate = "running" elif options.find('reset') >= 0: domstate = "running" if paused_after_start_vm: domstate = "paused" else: domstate = "running" if paused_after_start_vm: domstate = "paused" if not start_vm: domstate = "shut off" logging.debug("Domain should %s after run dump %s", domstate, options) return (domstate == actual) def check_dump_format(dump_image_format, dump_file): """ Check the format of dumped file. If 'dump_image_format' is not specified or invalid in qemu.conf, then the file shoule be normal raw file, otherwise it shoud be compress to specified format, the supported compress format including: lzop, gzip, bzip2, and xz. For memory-only dump, the default dump format is ELF, and it can also specify format by --format option, the result could be 'elf' or 'data'. """ valid_format = ["lzop", "gzip", "bzip2", "xz", 'elf', 'data'] if len(dump_image_format) == 0 or dump_image_format not in valid_format: logging.debug("No need check the dumped file format") return True else: file_cmd = "file %s" % dump_file (status, output) = commands.getstatusoutput(file_cmd) if status: logging.error("Fail to check dumped file %s", 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(): logging.error("Compress dumped file to %s fail: %s" % (dump_image_format, actual_format)) return False else: return True # Configure dump_image_format in /etc/libvirt/qemu.conf. qemu_config = utils_config.LibvirtQemuConfig() libvirtd = utils_libvirtd.Libvirtd() if len(dump_image_format): qemu_config.dump_image_format = dump_image_format libvirtd.restart() # Deal with bypass-cache option child_pid = 0 if options.find('bypass-cache') >= 0: pid = os.fork() if pid: # Guarantee check_bypass function has run before dump child_pid = pid try: wait_pid_active(pid, timeout) finally: os.kill(child_pid, signal.SIGUSR1) else: check_bypass(dump_file) # Wait for parent process over while True: time.sleep(1) # Deal with memory-only dump format if len(memory_dump_format): # Make sure libvirt support this option if virsh.has_command_help_match("dump", "--format") is None: raise error.TestNAError("Current libvirt version doesn't support" " --format option for dump command") # Make sure QEMU support this format query_cmd = '{"execute":"query-dump-guest-memory-capability"}' qemu_capa = virsh.qemu_monitor_command(vm_name, query_cmd).stdout if (memory_dump_format not in qemu_capa) and not status_error: raise error.TestNAError("Unsupported dump format '%s' for" " this QEMU binary" % memory_dump_format) options += " --format %s" % memory_dump_format if memory_dump_format == 'elf': dump_image_format = 'elf' if memory_dump_format in ['kdump-zlib', 'kdump-lzo', 'kdump-snappy']: dump_image_format = 'data' # Back up xml file vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) backup_xml = vmxml.copy() dump_guest_core = params.get("dump_guest_core", "") if dump_guest_core not in ["", "on", "off"]: raise error.TestError("invalid dumpCore value: %s" % dump_guest_core) try: # Set dumpCore in guest xml if dump_guest_core: if vm.is_alive(): vm.destroy(gracefully=False) vmxml.dumpcore = dump_guest_core vmxml.sync() vm.start() # check qemu-kvm cmdline vm_pid = vm.get_pid() cmd = "cat /proc/%d/cmdline|xargs -0 echo" % vm_pid cmd += "|grep dump-guest-core=%s" % dump_guest_core result = utils.run(cmd, ignore_status=True) logging.debug("cmdline: %s" % result.stdout) if result.exit_status: error.TestFail("Not find dump-guest-core=%s in qemu cmdline" % dump_guest_core) else: logging.info("Find dump-guest-core=%s in qemum cmdline", dump_guest_core) # 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 logging.info("Start check result") if not check_domstate(vm.state(), options): raise error.TestFail("Domain status check fail.") if status_error: if not status: raise error.TestFail("Expect fail, but run successfully") else: if status: raise error.TestFail("Expect succeed, but run fail") if not os.path.exists(dump_file): raise error.TestFail("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: raise error.TestFail("The format of dumped file is wrong.") finally: if child_pid: os.kill(child_pid, signal.SIGUSR1) if os.path.isfile(dump_file): os.remove(dump_file) if vm.is_alive(): vm.destroy(gracefully=False) backup_xml.sync() qemu_config.restore() libvirtd.restart()
def run(test, params, env): """ Test command: virsh dump. This command can dump the core of a domain to a file for analysis. 1. Positive testing 1.1 Dump domain with valid options. 1.2 Avoid file system cache when dumping. 1.3 Compress the dump images to valid/invalid formats. 2. Negative testing 2.1 Dump domain to a non-exist directory. 2.2 Dump domain with invalid option. 2.3 Dump a shut-off domain. """ vm_name = params.get("main_vm", "vm1") vm = env.get_vm(vm_name) options = params.get("dump_options") dump_file = params.get("dump_file", "vm.core") dump_dir = params.get("dump_dir", data_dir.get_tmp_dir()) if os.path.dirname(dump_file) is "": dump_file = os.path.join(dump_dir, dump_file) dump_image_format = params.get("dump_image_format") 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" timeout = int(params.get("check_pid_timeout", "5")) memory_dump_format = params.get("memory_dump_format", "") uri = params.get("virsh_uri") unprivileged_user = params.get('unprivileged_user') if unprivileged_user: if unprivileged_user.count('EXAMPLE'): unprivileged_user = '******' if not libvirt_version.version_compare(1, 1, 1): if params.get('setup_libvirt_polkit') == 'yes': raise error.TestNAError("API acl test not supported in current" " libvirt version.") def check_domstate(actual, options): """ Check the domain status according to dump options. """ if options.find('live') >= 0: domstate = "running" if options.find('crash') >= 0 or options.find('reset') > 0: domstate = "running" if paused_after_start_vm: domstate = "paused" elif options.find('crash') >= 0: domstate = "shut off" if options.find('reset') >= 0: domstate = "running" elif options.find('reset') >= 0: domstate = "running" if paused_after_start_vm: domstate = "paused" else: domstate = "running" if paused_after_start_vm: domstate = "paused" if not start_vm: domstate = "shut off" logging.debug("Domain should %s after run dump %s", domstate, options) return (domstate == actual) def check_dump_format(dump_image_format, dump_file): """ Check the format of dumped file. If 'dump_image_format' is not specified or invalid in qemu.conf, then the file shoule be normal raw file, otherwise it shoud be compress to specified format, the supported compress format including: lzop, gzip, bzip2, and xz. For memory-only dump, the default dump format is ELF, and it can also specify format by --format option, the result could be 'elf' or 'data'. """ valid_format = ["lzop", "gzip", "bzip2", "xz", 'elf', 'data'] if len(dump_image_format ) == 0 or dump_image_format not in valid_format: logging.debug("No need check the dumped file format") return True else: file_cmd = "file %s" % dump_file (status, output) = commands.getstatusoutput(file_cmd) if status: logging.error("Fail to check dumped file %s", 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(): logging.error("Compress dumped file to %s fail: %s" % (dump_image_format, actual_format)) return False else: return True # Configure dump_image_format in /etc/libvirt/qemu.conf. qemu_config = utils_config.LibvirtQemuConfig() libvirtd = utils_libvirtd.Libvirtd() if len(dump_image_format): qemu_config.dump_image_format = dump_image_format libvirtd.restart() # Deal with bypass-cache option child_pid = 0 if options.find('bypass-cache') >= 0: pid = os.fork() if pid: # Guarantee check_bypass function has run before dump child_pid = pid try: wait_pid_active(pid, timeout) finally: os.kill(child_pid, signal.SIGTERM) else: check_bypass(dump_file) # Wait for parent process kills us while True: time.sleep(1) # Deal with memory-only dump format if len(memory_dump_format): # Make sure libvirt support this option if virsh.has_command_help_match("dump", "--format") is None: raise error.TestNAError("Current libvirt version doesn't support" " --format option for dump command") # Make sure QEMU support this format query_cmd = '{"execute":"query-dump-guest-memory-capability"}' qemu_capa = virsh.qemu_monitor_command(vm_name, query_cmd).stdout if (memory_dump_format not in qemu_capa) and not status_error: raise error.TestNAError("Unsupported dump format '%s' for" " this QEMU binary" % memory_dump_format) options += " --format %s" % memory_dump_format if memory_dump_format == 'elf': dump_image_format = 'elf' if memory_dump_format in ['kdump-zlib', 'kdump-lzo', 'kdump-snappy']: dump_image_format = 'data' # Back up xml file vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) backup_xml = vmxml.copy() dump_guest_core = params.get("dump_guest_core", "") if dump_guest_core not in ["", "on", "off"]: raise error.TestError("invalid dumpCore value: %s" % dump_guest_core) try: # Set dumpCore in guest xml if dump_guest_core: if vm.is_alive(): vm.destroy(gracefully=False) vmxml.dumpcore = dump_guest_core vmxml.sync() vm.start() # check qemu-kvm cmdline vm_pid = vm.get_pid() cmd = "cat /proc/%d/cmdline|xargs -0 echo" % vm_pid cmd += "|grep dump-guest-core=%s" % dump_guest_core result = utils.run(cmd, ignore_status=True) logging.debug("cmdline: %s" % result.stdout) if result.exit_status: error.TestFail("Not find dump-guest-core=%s in qemu cmdline" % dump_guest_core) else: logging.info("Find dump-guest-core=%s in qemum cmdline", dump_guest_core) # 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 logging.info("Start check result") if not check_domstate(vm.state(), options): raise error.TestFail("Domain status check fail.") if status_error: if not status: raise error.TestFail("Expect fail, but run successfully") else: if status: raise error.TestFail("Expect succeed, but run fail") if not os.path.exists(dump_file): raise error.TestFail("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: raise error.TestFail("The format of dumped file is wrong.") finally: if child_pid: os.kill(child_pid, signal.SIGTERM) if os.path.isfile(dump_file): os.remove(dump_file) if vm.is_alive(): vm.destroy(gracefully=False) backup_xml.sync() qemu_config.restore() libvirtd.restart()
def run(test, params, env): """ Test command: virsh dump. This command can dump the core of a domain to a file for analysis. 1. Positive testing 1.1 Dump domain with valid options. 1.2 Avoid file system cache when dumping. 1.3 Compress the dump images to valid/invalid formats. 2. Negative testing 2.1 Dump domain to a non-exist directory. 2.2 Dump domain with invalid option. 2.3 Dump a shut-off domain. """ vm_name = params.get("main_vm", "vm1") vm = env.get_vm(vm_name) options = params.get("dump_options") dump_file = params.get("dump_file", "vm.core") if os.path.dirname(dump_file) is "": dump_file = os.path.join(test.tmpdir, dump_file) dump_image_format = params.get("dump_image_format") 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" timeout = int(params.get("timeout", "5")) qemu_conf = "/etc/libvirt/qemu.conf" uri = params.get("virsh_uri") unprivileged_user = params.get('unprivileged_user') if unprivileged_user: if unprivileged_user.count('EXAMPLE'): unprivileged_user = '******' if not libvirt_version.version_compare(1, 1, 1): if params.get('setup_libvirt_polkit') == 'yes': raise error.TestNAError("API acl test not supported in current" + " libvirt version.") def check_domstate(actual, options): """ Check the domain status according to dump options. """ if options.find('live') >= 0: domstate = "running" if options.find('crash') >= 0 or options.find('reset') > 0: domstate = "running" if paused_after_start_vm: domstate = "paused" elif options.find('crash') >= 0: domstate = "shut off" if options.find('reset') >= 0: domstate = "running" elif options.find('reset') >= 0: domstate = "running" if paused_after_start_vm: domstate = "paused" else: domstate = "running" if paused_after_start_vm: domstate = "paused" if not start_vm: domstate = "shut off" logging.debug("Domain should %s after run dump %s", domstate, options) return (domstate == actual) def check_dump_format(dump_image_format, dump_file): """ Check the format of dumped file. If 'dump_image_format' is not specified or invalid in qemu.conf, then the file shoule be normal raw file, otherwise it shoud be compress to specified format, the supported compress format including: lzop, gzip, bzip2, and xz. """ valid_format = ["lzop", "gzip", "bzip2", "xz"] if len(dump_image_format ) == 0 or dump_image_format not in valid_format: logging.debug("No need check the dumped file format") return True else: file_cmd = "file %s" % dump_file (status, output) = commands.getstatusoutput(file_cmd) if status: logging.error("Fail to check dumped file %s", 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(): logging.error("Compress dumped file to %s fail: %s" % (dump_image_format, actual_format)) return False else: return True # Configure dump_image_format in /etc/libvirt/qemu.conf. if len(dump_image_format): conf_cmd = ("echo dump_image_format = \\\"%s\\\" >> %s" % (dump_image_format, qemu_conf)) if os.system(conf_cmd): logging.error("Config dump_image_format to %s fail", dump_image_format) libvirtd_service = utils_libvirtd.Libvirtd() libvirtd_service.restart() if not libvirtd_service.is_running: raise error.TestNAError("libvirt service is not running!") # Deal with bypass-cache option child_pid = 0 if options.find('bypass-cache') >= 0: pid = os.fork() if pid: # Guarantee check_bypass function has run before dump child_pid = pid try: wait_pid_active(pid, timeout) finally: os.kill(child_pid, signal.SIGUSR1) else: check_bypass(dump_file) # Wait for parent process over while True: time.sleep(1) # Back up xml file vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) backup_xml = vmxml.copy() dump_guest_core = params.get("dump_guest_core", "") if dump_guest_core not in ["", "on", "off"]: raise error.TestError("invalid dumpCore value: %s" % dump_guest_core) try: # Set dumpCore in guest xml if dump_guest_core: if vm.is_alive(): vm.destroy(gracefully=False) vmxml.dumpcore = dump_guest_core vmxml.sync() vm.start() # check qemu-kvm cmdline vm_pid = vm.get_pid() cmd = "cat /proc/%d/cmdline|xargs -0 echo" % vm_pid cmd += "|grep dump-guest-core=%s" % dump_guest_core result = utils.run(cmd, ignore_status=True) logging.debug("cmdline: %s" % result.stdout) if result.exit_status: error.TestFail("Not find dump-guest-core=%s in qemu cmdline" % dump_guest_core) else: logging.info("Find dump-guest-core=%s in qemum cmdline", dump_guest_core) # 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 logging.info("Start check result") if not check_domstate(vm.state(), options): raise error.TestFail("Domain status check fail.") if status_error: if not status: raise error.TestFail("Expect fail, but run successfully") else: if status: raise error.TestFail("Expect succeed, but run fail") if not os.path.exists(dump_file): raise error.TestFail("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: raise error.TestFail("The format of dumped file is wrong.") finally: if child_pid: os.kill(child_pid, signal.SIGUSR1) if os.path.isfile(dump_file): os.remove(dump_file) if len(dump_image_format): clean_qemu_conf = "sed -i '$d' %s " % qemu_conf if os.system(clean_qemu_conf): raise error.TestFail("Fail to recover %s", qemu_conf) if vm.is_alive(): vm.destroy(gracefully=False) backup_xml.sync()
def run(test, params, env): """ Test command: virsh domjobinfo. The command returns information about jobs running on a domain. 1.Prepare test environment. 2.When the libvirtd == "off", stop the libvirtd service. 3.Perform virsh domjobinfo operation. 4.Recover test environment. 5.Confirm the test result. """ vm_name = params.get("main_vm") vm = env.get_vm(vm_name) domid = vm.get_id() domuuid = vm.get_uuid() pre_vm_state = params.get("domjobinfo_pre_vm_state", "null") vm_ref = params.get("domjobinfo_vm_ref") status_error = params.get("status_error", "no") libvirtd = params.get("libvirtd", "on") tmp_file = os.path.join(test.tmpdir, '%s.tmp' % vm_name) # prepare the state of vm if pre_vm_state == "dump": virsh.dump(vm_name, tmp_file) elif pre_vm_state == "save": virsh.save(vm_name, tmp_file) elif pre_vm_state == "restore": virsh.save(vm_name, tmp_file) virsh.restore(tmp_file) elif pre_vm_state == "managedsave": virsh.managedsave(vm_name) # run test case if vm_ref == "id": vm_ref = domid elif vm_ref == "hex_id": vm_ref = hex(int(domid)) elif vm_ref == "name": vm_ref = "%s %s" % (vm_name, params.get("domjobinfo_extra")) elif vm_ref == "uuid": vm_ref = domuuid elif vm_ref.find("invalid") != -1: vm_ref = params.get(vm_ref) if libvirtd == "off": utils_libvirtd.libvirtd_stop() status = virsh.domjobinfo(vm_ref, ignore_status=True).exit_status # recover libvirtd service start if libvirtd == "off": utils_libvirtd.libvirtd_start() # check status_error if status_error == "yes": if status == 0: test.fail("Run successfully with wrong command!") elif status_error == "no": if status != 0: test.fail("Run failed with right command")
def run_virsh_domjobinfo(test, params, env): """ Test command: virsh domjobinfo. The command returns information about jobs running on a domain. 1.Prepare test environment. 2.When the libvirtd == "off", stop the libvirtd service. 3.Perform virsh domjobinfo operation. 4.Recover test environment. 5.Confirm the test result. """ vm_name = params.get("main_vm") vm = env.get_vm(vm_name) domid = vm.get_id() domuuid = vm.get_uuid() pre_vm_state = params.get("domjobinfo_pre_vm_state", "null") vm_ref = params.get("domjobinfo_vm_ref") status_error = params.get("status_error", "no") libvirtd = params.get("libvirtd", "on") tmp_file = os.path.join(test.tmpdir, '%s.tmp' % vm_name ) #prepare the state of vm if pre_vm_state == "dump": virsh.dump(vm_name, tmp_file) elif pre_vm_state == "save": virsh.save(vm_name, tmp_file) elif pre_vm_state == "restore": virsh.save(vm_name, tmp_file) virsh.restore(tmp_file) elif pre_vm_state == "managedsave": virsh.managedsave(vm_name) #run test case if vm_ref == "id": vm_ref = domid elif vm_ref == "hex_id": vm_ref = hex(int(domid)) elif vm_ref == "name": vm_ref = "%s %s" % (vm_name, params.get("domjobinfo_extra")) elif vm_ref == "uuid": vm_ref = domuuid elif vm_ref.find("invalid") != -1: vm_ref = params.get(vm_ref) if libvirtd == "off": utils_libvirtd.libvirtd_stop() status = virsh.domjobinfo(vm_ref, ignore_status=True).exit_status #recover libvirtd service start if libvirtd == "off": utils_libvirtd.libvirtd_start() #check status_error if status_error == "yes": if status == 0: raise error.TestFail("Run successfully with wrong command!") elif status_error == "no": if status != 0: raise error.TestFail("Run failed with right command")
def manipulate_vm(vm, operation, params=None): """ Manipulate the VM. :param vm: VM instance :param operation: stress_in_vms, inject_nmi, dump, suspend_resume or save_restore :param params: Test parameters """ err_msg = '' # Special operations for test if operation == "stress": logging.debug("Load stress in VM") err_msg = utils_test.load_stress(operation, params=params, vms=[vm])[0] elif operation == "inject_nmi": inject_times = int(params.get("inject_times", 10)) logging.info("Trying to inject nmi %s times", inject_times) while inject_times > 0: try: inject_times -= 1 virsh.inject_nmi(vm.name, debug=True, ignore_status=False) except process.CmdError as detail: err_msg = "Inject nmi failed: %s" % detail elif operation == "dump": dump_times = int(params.get("dump_times", 10)) logging.info("Trying to dump vm %s times", dump_times) while dump_times > 0: dump_times -= 1 dump_path = os.path.join(data_dir.get_tmp_dir(), "dump.file") try: virsh.dump(vm.name, dump_path, debug=True, ignore_status=False) except (process.CmdError, OSError) as detail: err_msg = "Dump %s failed: %s" % (vm.name, detail) try: os.remove(dump_path) except OSError: pass elif operation == "suspend_resume": paused_times = int(params.get("paused_times", 10)) logging.info("Trying to suspend/resume vm %s times", paused_times) while paused_times > 0: paused_times -= 1 try: virsh.suspend(vm.name, debug=True, ignore_status=False) virsh.resume(vm.name, debug=True, ignore_status=False) except process.CmdError as detail: err_msg = "Suspend-Resume %s failed: %s" % (vm.name, detail) elif operation == "save_restore": save_times = int(params.get("save_times", 10)) logging.info("Trying to save/restore vm %s times", save_times) while save_times > 0: save_times -= 1 save_path = os.path.join(data_dir.get_tmp_dir(), "save.file") try: virsh.save(vm.name, save_path, debug=True, ignore_status=False) virsh.restore(save_path, debug=True, ignore_status=False) except process.CmdError as detail: err_msg = "Save-Restore %s failed: %s" % (vm.name, detail) try: os.remove(save_path) except OSError: pass else: err_msg = "Unsupport operation in this function: %s" % operation return err_msg
inject_times = int(params.get("inject_times", 10)) logging.info("Trying to inject nmi %s times", inject_times) while inject_times > 0: try: inject_times -= 1 virsh.inject_nmi(vm.name, debug=True, ignore_status=False) except error.CmdError, detail: err_msg = "Inject nmi failed: %s" % detail elif operation == "dump": dump_times = int(params.get("dump_times", 10)) logging.info("Trying to dump vm %s times", dump_times) while dump_times > 0: dump_times -= 1 dump_path = os.path.join(data_dir.get_tmp_dir(), "dump.file") try: virsh.dump(vm.name, dump_path, debug=True, ignore_status=False) except (error.CmdError, OSError), detail: err_msg = "Dump %s failed: %s" % (vm.name, detail) try: os.remove(dump_path) except OSError: pass elif operation == "suspend_resume": paused_times = int(params.get("paused_times", 10)) logging.info("Trying to suspend/resume vm %s times", paused_times) while paused_times > 0: paused_times -= 1 try: virsh.suspend(vm.name, debug=True, ignore_status=False) virsh.resume(vm.name, debug=True, ignore_status=False) except error.CmdError, detail:
if options.find('bypass-cache') >= 0: vm.wait_for_login() pid = os.fork() if pid: # Guarantee check_bypass function has run before dump child_pid = pid wait_pid_active(pid, timeout) else: check_bypass(dump_file) # Wait for parent process kills us while True: time.sleep(1) # 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 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") 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):
def run(test, params, env): """ Test command: virsh domstate. 1.Prepare test environment. 2.When the libvirtd == "off", stop the libvirtd service. 3.Perform virsh domstate operation. 4.Recover test environment. 5.Confirm the test result. """ vm_name = params.get("main_vm", "avocado-vt-vm1") vm = env.get_vm(vm_name) libvirtd_state = params.get("libvirtd", "on") vm_ref = params.get("domstate_vm_ref") status_error = (params.get("status_error", "no") == "yes") extra = params.get("domstate_extra", "") vm_action = params.get("domstate_vm_action", "") vm_oncrash_action = params.get("domstate_vm_oncrash") reset_action = "yes" == params.get("reset_action", "no") dump_option = params.get("dump_option", "") start_action = params.get("start_action", "normal") kill_action = params.get("kill_action", "normal") check_libvirtd_log = params.get("check_libvirtd_log", "no") err_msg = params.get("err_msg", "") remote_uri = params.get("remote_uri") domid = vm.get_id() domuuid = vm.get_uuid() if vm_ref == "id": vm_ref = domid elif vm_ref == "hex_id": vm_ref = hex(int(domid)) elif vm_ref.find("invalid") != -1: vm_ref = params.get(vm_ref) elif vm_ref == "name": vm_ref = vm_name elif vm_ref == "uuid": vm_ref = domuuid # Back up xml file. vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) backup_xml = vmxml.copy() # Back up qemu.conf qemu_conf = utils_config.LibvirtQemuConfig() libvirtd = utils_libvirtd.Libvirtd() # Config libvirtd log if check_libvirtd_log == "yes": libvirtd_conf = utils_config.LibvirtdConfig() libvirtd_log_file = os.path.join(data_dir.get_tmp_dir(), "libvirtd.log") libvirtd_conf["log_level"] = '1' libvirtd_conf["log_filters"] = ('"1:json 1:libvirt 1:qemu 1:monitor ' '3:remote 4:event"') libvirtd_conf["log_outputs"] = '"1:file:%s"' % libvirtd_log_file logging.debug("the libvirtd config file content is:\n %s" % libvirtd_conf) libvirtd.restart() # Get image file image_source = vm.get_first_disk_devices()['source'] logging.debug("image source: %s" % image_source) new_image_source = image_source + '.rename' dump_path = os.path.join(data_dir.get_tmp_dir(), "dump/") logging.debug("dump_path: %s", dump_path) try: os.mkdir(dump_path) except OSError: # If the path already exists then pass pass dump_file = "" try: # Let's have guest memory less so that dumping core takes # time which doesn't timeout the testcase if vm_oncrash_action in ['coredump-destroy', 'coredump-restart']: memory_value = int(params.get("memory_value", "2097152")) memory_unit = params.get("memory_unit", "KiB") vmxml.set_memory(memory_value) vmxml.set_memory_unit(memory_unit) logging.debug(vmxml) vmxml.sync() if vm_action == "crash": if vm.is_alive(): vm.destroy(gracefully=False) vmxml.on_crash = vm_oncrash_action if not vmxml.xmltreefile.find('devices').findall('panic'): # Add <panic> 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 qemu_conf.auto_dump_path = dump_path libvirtd.restart() if vm_oncrash_action in ['coredump-destroy', 'coredump-restart']: dump_file = dump_path + "*" + vm_name[:20] + "-*" # Start VM and check the panic device virsh.start(vm_name, ignore_status=False) vmxml_new = vm_xml.VMXML.new_from_dumpxml(vm_name) # Skip this test if no panic device find if not vmxml_new.xmltreefile.find('devices').findall('panic'): test.cancel("No 'panic' device in the guest. Maybe your " "libvirt version doesn't support it.") try: if vm_action == "suspend": virsh.suspend(vm_name, ignore_status=False) elif vm_action == "resume": virsh.suspend(vm_name, ignore_status=False) virsh.resume(vm_name, ignore_status=False) elif vm_action == "destroy": virsh.destroy(vm_name, ignore_status=False) elif vm_action == "start": virsh.destroy(vm_name, ignore_status=False) if start_action == "rename": # rename the guest image file to make guest fail to start os.rename(image_source, new_image_source) virsh.start(vm_name, ignore_status=True) else: virsh.start(vm_name, ignore_status=False) if start_action == "restart_libvirtd": libvirtd.restart() elif vm_action == "kill": if kill_action == "stop_libvirtd": libvirtd.stop() utils_misc.kill_process_by_pattern(vm_name) libvirtd.restart() elif kill_action == "reboot_vm": virsh.reboot(vm_name, ignore_status=False) utils_misc.kill_process_tree(vm.get_pid(), signal.SIGKILL) else: utils_misc.kill_process_tree(vm.get_pid(), signal.SIGKILL) elif vm_action == "crash": session = vm.wait_for_login() session.cmd("service kdump stop", ignore_all_errors=True) # Enable sysRq session.cmd("echo 1 > /proc/sys/kernel/sysrq") # Send key ALT-SysRq-c to crash VM, and command will not # return as vm crashed, so fail early for 'destroy' and # 'preserve' action. For 'restart', 'coredump-restart' # and 'coredump-destroy' actions, they all need more time # to dump core file or restart OS, so using the default # session command timeout(60s) try: if vm_oncrash_action in ['destroy', 'preserve']: timeout = 3 else: timeout = 60 session.cmd("echo c > /proc/sysrq-trigger", timeout=timeout) except (ShellTimeoutError, ShellProcessTerminatedError): pass session.close() elif vm_action == "dump": dump_file = dump_path + "*" + vm_name + "-*" virsh.dump(vm_name, dump_file, dump_option, ignore_status=False) except process.CmdError as detail: test.error("Guest prepare action error: %s" % detail) if libvirtd_state == "off": libvirtd.stop() # Timing issue cause test to check domstate before prior action # kill gets completed if vm_action == "kill": time.sleep(2) if remote_uri: remote_ip = params.get("remote_ip", "REMOTE.EXAMPLE.COM") remote_pwd = params.get("remote_pwd", None) remote_user = params.get("remote_user", "root") if remote_ip.count("EXAMPLE.COM"): test.cancel("Test 'remote' parameters not setup") ssh_key.setup_ssh_key(remote_ip, remote_user, remote_pwd) result = virsh.domstate(vm_ref, extra, ignore_status=True, debug=True, uri=remote_uri) status = result.exit_status output = result.stdout.strip() # check status_error if status_error: if not status: test.fail("Run successfully with wrong command!") else: if status or not output: test.fail("Run failed with right command") if extra.count("reason"): if vm_action == "suspend": # If not, will cost long time to destroy vm virsh.destroy(vm_name) if not output.count("user"): test.fail(err_msg % vm_action) elif vm_action == "resume": if not output.count("unpaused"): test.fail(err_msg % vm_action) elif vm_action == "destroy": if not output.count("destroyed"): test.fail(err_msg % vm_action) elif vm_action == "start": if start_action == "rename": if not output.count("shut off (failed)"): test.fail(err_msg % vm_action) else: if not output.count("booted"): test.fail(err_msg % vm_action) elif vm_action == "kill": if not output.count("crashed"): test.fail(err_msg % vm_action) elif vm_action == "crash": if not check_crash_state(output, vm_oncrash_action, vm_name, dump_file): test.fail(err_msg % vm_action) # VM will be in preserved state, perform virsh reset # and check VM reboots and domstate reflects running # state from crashed state as bug is observed here if vm_oncrash_action == "preserve" and reset_action: virsh_dargs = {'debug': True, 'ignore_status': True} ret = virsh.reset(vm_name, **virsh_dargs) libvirt.check_exit_status(ret) ret = virsh.domstate(vm_name, extra, **virsh_dargs).stdout.strip() if "paused (crashed)" not in ret: test.fail("vm fails to change state from crashed" " to paused after virsh reset") # it will be in paused (crashed) state after reset # and resume is required for the vm to reboot ret = virsh.resume(vm_name, **virsh_dargs) libvirt.check_exit_status(ret) vm.wait_for_login() cmd_output = virsh.domstate(vm_name, '--reason').stdout.strip() if "running" not in cmd_output: test.fail("guest state failed to get updated") if vm_oncrash_action in ['coredump-destroy', 'coredump-restart']: if not find_dump_file: test.fail("Core dump file is not created in dump " "path: %s" % dump_path) # For cover bug 1178652 if (vm_oncrash_action == "rename-restart" and check_libvirtd_log == "yes"): libvirtd.restart() if not os.path.exists(libvirtd_log_file): test.fail("Expected VM log file: %s not exists" % libvirtd_log_file) cmd = ("grep -nr '%s' %s" % (err_msg, libvirtd_log_file)) if not process.run(cmd, ignore_status=True, shell=True).exit_status: test.fail("Find error message %s from log file: %s." % (err_msg, libvirtd_log_file)) elif vm_action == "dump": if dump_option == "--live": if not output.count("running (unpaused)"): test.fail(err_msg % vm_action) elif dump_option == "--crash": if not output.count("shut off (crashed)"): test.fail(err_msg % vm_action) if vm_ref == "remote": if not (re.search("running", output) or re.search("blocked", output) or re.search("idle", output)): test.fail("Run failed with right command") finally: qemu_conf.restore() if check_libvirtd_log == "yes": libvirtd_conf.restore() if os.path.exists(libvirtd_log_file): os.remove(libvirtd_log_file) libvirtd.restart() if vm_action == "start" and start_action == "rename": os.rename(new_image_source, image_source) if vm.is_alive(): vm.destroy(gracefully=False) backup_xml.sync() if os.path.exists(dump_path): shutil.rmtree(dump_path)
def run_virsh_dump(test, params, env): """ Test command: virsh dump. This command can dump the core of a domain to a file for analysis. 1. Positive testing 1.1 Dump domain with valid options. 1.2 Avoid file system cache when dumping. 1.3 Compress the dump images to valid/invalid formats. 2. Negative testing 2.1 Dump domain to a non-exist directory. 2.2 Dump domain with invalid option. 2.3 Dump a shut-off domain. """ vm_name = params.get("main_vm", "vm1") vm = env.get_vm(params["main_vm"]) options = params.get("dump_options") dump_file = params.get("dump_file") dump_image_format = params.get("dump_image_format") start_vm = params.get("start_vm") status_error = params.get("status_error", "no") qemu_conf = "/etc/libvirt/qemu.conf" # prepare the vm state if vm.is_alive() and start_vm == "no": vm.destroy() if vm.is_dead() and start_vm == "yes": vm.start() def check_domstate(actual, options): """ Check the domain status according to dump options. """ if options.find('live') >= 0: domstate = "running" if options.find('crash') >= 0 or options.find('reset') >0: domstate = "running" elif options.find('crash') >=0: domstate = "shut off" if options.find('reset') >= 0: domstate = "running" elif options.find('reset') >= 0: domstate = "running" else: domstate = "running" if start_vm == "no": domstate = "shut off" logging.debug("Domain should %s after run dump %s", domstate, options) if domstate == actual: return True else: return False def check_dump_format(dump_image_format, dump_file): """ Check the format of dumped file. If 'dump_image_format' is not specified or invalid in qemu.conf, then the file shoule be normal raw file, otherwise it shoud be compress to specified format, the supported compress format including: lzop, gzip, bzip2, and xz. """ valid_format = ["lzop", "gzip", "bzip2", "xz"] if len(dump_image_format) == 0 or dump_image_format not in valid_format: logging.debug("No need check the dumped file format") return True else: file_cmd = "file %s" % dump_file (status, output) = commands.getstatusoutput(file_cmd) if status == 0: logging.debug("Run file %s output: %s", dump_file, output) actual_format = output.split(" ")[1] if actual_format == dump_image_format: if dump_image_format in valid_format: logging.info("Compress dumped file to %s successfully", dump_image_format) return True else: logging.error("Compress dumped file to %s fail", dump_image_format) return False else: logging.error("Fail to check dumped file %s", dump_file) return False # Configure dump_image_format in /etc/libvirt/qemu.conf. if len(dump_image_format) != 0: conf_cmd = ("echo dump_image_format = \\\"%s\\\" >> %s" % (dump_image_format, qemu_conf)) if os.system(conf_cmd): logging.error("Config dump_image_format to %s fail", dump_image_format) libvirt_vm.service_libvirtd_control("restart") # Deal with bypass-cache option if options.find('bypass-cache') >= 0: thread.start_new_thread(check_bypass,(dump_file,)) # Guarantee check_bypass function has run before dump time.sleep(5) # Run virsh command cmd_result = virsh.dump(vm_name, dump_file, options, ignore_status=True, debug=True) status = cmd_result.exit_status # Check libvirtd status if libvirt_vm.service_libvirtd_control("status"): if check_domstate(vm.state(), options): if status_error == "yes": if status == 0: raise error.TestFail("Expect fail, but run successfully") if status_error == "no": if status != 0: raise error.TestFail("Expect succeed, but run fail") else: if os.path.exists(dump_file): if check_dump_format(dump_image_format, dump_file): logging.info("Successfully dump domain to %s", dump_file) else: raise error.TestFail("The format of dumped file " "is wrong.") else: raise error.TestFail("Fail to find domain dumped file.") else: raise error.TestFail("Domain status check fail.") else: raise error.TestFail("Libvirtd service is dead.") if os.path.exists(dump_file): os.remove(dump_file) if len(dump_image_format) != 0: clean_qemu_conf = "sed -i '$d' %s " % qemu_conf if os.system(clean_qemu_conf): raise error.TestFail("Fail to recover %s", qemu_conf)
def manipulate_vm(vm, operation, params=None): """ Manipulate the VM. :param vm: VM instance :param operation: stress_in_vms, inject_nmi, dump, suspend_resume or save_restore :param params: Test parameters """ err_msg = '' # Special operations for test if operation == "stress": logging.debug("Load stress in VM") err_msg = utils_test.load_stress(operation, params=params, vms=[vm])[0] elif operation == "inject_nmi": inject_times = int(params.get("inject_times", 10)) logging.info("Trying to inject nmi %s times", inject_times) while inject_times > 0: try: inject_times -= 1 virsh.inject_nmi(vm.name, debug=True, ignore_status=False) except process.CmdError as detail: err_msg = "Inject nmi failed: %s" % detail elif operation == "dump": dump_times = int(params.get("dump_times", 10)) logging.info("Trying to dump vm %s times", dump_times) while dump_times > 0: dump_times -= 1 dump_path = os.path.join(data_dir.get_tmp_dir(), "dump.file") try: virsh.dump(vm.name, dump_path, debug=True, ignore_status=False) except (process.CmdError, OSError) as detail: err_msg = "Dump %s failed: %s" % (vm.name, detail) try: os.remove(dump_path) except OSError: pass elif operation == "suspend_resume": paused_times = int(params.get("paused_times", 10)) logging.info("Trying to suspend/resume vm %s times", paused_times) while paused_times > 0: paused_times -= 1 try: virsh.suspend(vm.name, debug=True, ignore_status=False) virsh.resume(vm.name, debug=True, ignore_status=False) except process.CmdError as detail: err_msg = "Suspend-Resume %s failed: %s" % (vm.name, detail) elif operation == "save_restore": save_times = int(params.get("save_times", 10)) logging.info("Trying to save/restore vm %s times", save_times) while save_times > 0: save_times -= 1 save_path = os.path.join(data_dir.get_tmp_dir(), "save.file") try: virsh.save(vm.name, save_path, debug=True, ignore_status=False) virsh.restore(save_path, debug=True, ignore_status=False) except process.CmdError as detail: err_msg = "Save-Restore %s failed: %s" % (vm.name, detail) try: os.remove(save_path) except OSError: pass else: err_msg = "Unsupported operation in this function: %s" % operation return err_msg