def check_migration_res(result): """ Check if the migration result is as expected :param result: the output of migration :raise: test.fail if test is failed """ logging.info("Migration out: %s", results_stdout_52lts(result).strip()) logging.info("Migration error: %s", results_stderr_52lts(result).strip()) if status_error: # Migration should fail if err_msg: # Special error messages are expected if not re.search(err_msg, results_stderr_52lts(result).strip()): test.fail("Can not find the expected patterns '%s' in " "output '%s'" % (err_msg, results_stderr_52lts(result).strip())) else: logging.debug("It is the expected error message") else: if int(result.exit_status) != 0: logging.debug("Migration failure is expected result") else: test.fail("Migration success is unexpected result") else: if int(result.exit_status) != 0: test.fail(results_stderr_52lts(result).strip())
def find_hbas(hba_type="hba", status="online"): """ Find online hba/vhba cards. :params hba_type: "vhba" or "hba" :params status: "online" or "offline" :return: A list contains the online/offline vhba/hba list """ # TODO: add status=offline/online judgement, we don't test offline vhba now # so leave it here as a placeholder. result = virsh.nodedev_list(cap="scsi_host") if result.exit_status: raise exceptions.TestFail(results_stderr_52lts(result)) scsi_hosts = results_stdout_52lts(result).strip().splitlines() online_hbas_list = [] online_vhbas_list = [] # go through all scsi hosts, and split hbas/vhbas into lists for scsi_host in scsi_hosts: result = virsh.nodedev_dumpxml(scsi_host) stdout = results_stdout_52lts(result).strip() if result.exit_status: raise exceptions.TestFail(results_stderr_52lts(result)) if (re.search('vport_ops', stdout) and not re.search('<fabric_wwn>ffffffffffffffff</fabric_wwn>', stdout) and not re.search('<fabric_wwn>0</fabric_wwn>', stdout)): online_hbas_list.append(scsi_host) if re.search('fc_host', stdout) and not re.search('vport_ops', stdout): online_vhbas_list.append(scsi_host) if hba_type == "hba": return online_hbas_list if hba_type == "vhba": return online_vhbas_list
def check_migration_res(result): """ Check if the migration result is as expected :param result: the output of migration :raise: test.fail if test is failed """ logging.info("Migration out: %s", results_stdout_52lts(result).strip()) logging.info("Migration error: %s", results_stderr_52lts(result).strip()) if status_error: # Migration should fail if err_msg: # Special error messages are expected if not re.search(err_msg, results_stderr_52lts(result).strip()): test.fail("Can not find the expected patterns '%s' in " "output '%s'" % (err_msg, results_stderr_52lts(result).strip())) else: logging.debug("It is the expected error message") else: if int(result.exit_status) != 0: logging.debug("Migration failure is expected result") else: test.fail("Migration success is unexpected result") else: if int(result.exit_status) != 0: test.fail(results_stderr_52lts(result).strip())
def find_hbas(hba_type="hba", status="online"): """ Find online hba/vhba cards. :params hba_type: "vhba" or "hba" :params status: "online" or "offline" :return: A list contains the online/offline vhba/hba list """ # TODO: add status=offline/online judgement, we don't test offline vhba now # so leave it here as a placeholder. result = virsh.nodedev_list(cap="scsi_host") if result.exit_status: raise exceptions.TestFail(results_stderr_52lts(result)) scsi_hosts = results_stdout_52lts(result).strip().splitlines() online_hbas_list = [] online_vhbas_list = [] # go through all scsi hosts, and split hbas/vhbas into lists for scsi_host in scsi_hosts: result = virsh.nodedev_dumpxml(scsi_host) stdout = results_stdout_52lts(result).strip() if result.exit_status: raise exceptions.TestFail(results_stderr_52lts(result)) if (re.search('vport_ops', stdout) and not re.search('<fabric_wwn>ffffffffffffffff</fabric_wwn>', stdout) and not re.search('<fabric_wwn>0</fabric_wwn>', stdout)): online_hbas_list.append(scsi_host) if re.search('fc_host', stdout) and not re.search('vport_ops', stdout): online_vhbas_list.append(scsi_host) if hba_type == "hba": return online_hbas_list if hba_type == "vhba": return online_vhbas_list
def get_cpustats(vm, cpu=None): """ Get the cpustats output of a given domain :param vm: VM domain :param cpu: Host cpu index, default all cpus :return: dict of cpu stats values result format: {0:[vcputime,emulatortime,cputime] .. 'total':[cputime]} """ host_cpu_online = utils.cpu_online_list() cpustats = {} if cpu: cpustats[cpu] = [] option = "--start %s --count 1" % cpu result = virsh.cpu_stats(vm.name, option) if result.exit_status != 0: logging.error("cpu stats command failed: %s", results_stderr_52lts(result)) return None output = results_stdout_52lts(result).strip().split() if re.match("CPU%s" % cpu, output[0]): cpustats[cpu] = [ float(output[5]), # vcputime float(output[2]) - float(output[5]), # emulator float(output[2]) ] # cputime else: for i in range(len(host_cpu_online)): cpustats[host_cpu_online[i]] = [] option = "--start %s --count 1" % host_cpu_online[i] result = virsh.cpu_stats(vm.name, option) if result.exit_status != 0: logging.error("cpu stats command failed: %s", results_stderr_52lts(result)) return None output = results_stdout_52lts(result).strip().split() if re.match("CPU%s" % host_cpu_online[i], output[0]): cpustats[host_cpu_online[i]] = [ float(output[5]), float(output[2]) - float(output[5]), float(output[2]) ] result = virsh.cpu_stats(vm.name, "--total") cpustats["total"] = [] if result.exit_status != 0: logging.error("cpu stats command failed: %s", results_stderr_52lts(result)) return None output = results_stdout_52lts(result).strip().split() cpustats["total"] = [float(output[2])] # cputime return cpustats
def get_cpustats(vm, cpu=None): """ Get the cpustats output of a given domain :param vm: VM domain :param cpu: Host cpu index, default all cpus :return: dict of cpu stats values result format: {0:[vcputime,emulatortime,cputime] .. 'total':[cputime]} """ host_cpu_online = utils.cpu_online_list() cpustats = {} if cpu: cpustats[cpu] = [] option = "--start %s --count 1" % cpu result = virsh.cpu_stats(vm.name, option) if result.exit_status != 0: logging.error("cpu stats command failed: %s", results_stderr_52lts(result)) return None output = results_stdout_52lts(result).strip().split() if re.match("CPU%s" % cpu, output[0]): cpustats[cpu] = [float(output[5]), # vcputime float(output[2]) - float(output[5]), # emulator float(output[2])] # cputime else: for i in range(len(host_cpu_online)): cpustats[host_cpu_online[i]] = [] option = "--start %s --count 1" % host_cpu_online[i] result = virsh.cpu_stats(vm.name, option) if result.exit_status != 0: logging.error("cpu stats command failed: %s", results_stderr_52lts(result)) return None output = results_stdout_52lts(result).strip().split() if re.match("CPU%s" % host_cpu_online[i], output[0]): cpustats[host_cpu_online[i]] = [float(output[5]), float(output[2]) - float(output[5]), float(output[2])] result = virsh.cpu_stats(vm.name, "--total") cpustats["total"] = [] if result.exit_status != 0: logging.error("cpu stats command failed: %s", results_stderr_52lts(result)) return None output = results_stdout_52lts(result).strip().split() cpustats["total"] = [float(output[2])] # cputime return cpustats
def lv_take_snapshot(vg_name, lv_name, lv_snapshot_name, lv_snapshot_size): """ Take a snapshot of the original logical volume. """ error_context.context("Taking snapshot from original logical volume", logging.info) if not vg_check(vg_name): raise exceptions.TestError("Volume group could not be found") if lv_check(vg_name, lv_snapshot_name): raise exceptions.TestError("Snapshot already exists") if not lv_check(vg_name, lv_name): raise exceptions.TestError("Snapshot's origin could not be found") cmd = ("lvcreate --size " + lv_snapshot_size + " --snapshot " + " --name " + lv_snapshot_name + " /dev/" + vg_name + "/" + lv_name) try: result = process.run(cmd) except process.CmdError as ex: if ('Logical volume "%s" already exists in volume group "%s"' % (lv_snapshot_name, vg_name) in results_stderr_52lts(ex.result) and re.search(re.escape(lv_snapshot_name + " [active]"), results_stdout_52lts(process.run("lvdisplay")))): # the above conditions detect if merge of snapshot was postponed logging.warning(("Logical volume %s is still active! " + "Attempting to deactivate..."), lv_name) lv_reactivate(vg_name, lv_name) result = process.run(cmd) else: raise ex logging.info(results_stdout_52lts(result).rstrip())
def iscsi_logout(target_name=None): """ Logout from a target. If the target name is not set then logout all targets. :params target_name: Name of the target. """ if target_name: cmd = "iscsiadm --mode node --logout -T %s" % target_name else: cmd = "iscsiadm --mode node --logout all" output = '' try: output = decode_to_text(process.system_output(cmd)) except process.CmdError as detail: # iscsiadm will fail when no matching sessions found # This failure makes no sense when target name is not specified stderr = results_stderr_52lts(detail.result) if not target_name and 'No matching sessions' in stderr: logging.info("%s: %s", detail, stderr) else: raise target_logout = "" if "successful" in output: target_logout = target_name return target_logout
def run(self, args): # Enable root logger as some Avocado-vt libraries use that handler = logging.StreamHandler() handler.setLevel(logging.DEBUG) logging.getLogger("").addHandler(handler) try: bootstrap.bootstrap(options=args, interactive=True) sys.exit(0) except process.CmdError as ce: if ce.result.interrupted: logging.info('Bootstrap command interrupted by user') logging.info('Command: %s', ce.command) else: logging.error('Bootstrap command failed') logging.error('Command: %s', ce.command) stderr = results_stderr_52lts(ce.result) if stderr: logging.error('stderr output:') logging.error(stderr) stdout = results_stdout_52lts(ce.result) if stdout: logging.error('stdout output:') logging.error(stdout) sys.exit(1) except KeyboardInterrupt: logging.info('Bootstrap interrupted by user') sys.exit(1)
def iscsi_logout(target_name=None): """ Logout from a target. If the target name is not set then logout all targets. :params target_name: Name of the target. """ if target_name: cmd = "iscsiadm --mode node --logout -T %s" % target_name else: cmd = "iscsiadm --mode node --logout all" output = '' try: output = decode_to_text(process.system_output(cmd)) except process.CmdError as detail: # iscsiadm will fail when no matching sessions found # This failure makes no sense when target name is not specified stderr = results_stderr_52lts(detail.result) if not target_name and 'No matching sessions' in stderr: logging.info("%s: %s", detail, stderr) else: raise target_logout = "" if "successful" in output: target_logout = target_name return target_logout
def run(self, args): # Enable root logger as some Avocado-vt libraries use that handler = logging.StreamHandler() handler.setLevel(logging.DEBUG) logging.getLogger("").addHandler(handler) try: bootstrap.bootstrap(options=args, interactive=True) sys.exit(0) except process.CmdError as ce: if ce.result.interrupted: logging.info('Bootstrap command interrupted by user') logging.info('Command: %s', ce.command) else: logging.error('Bootstrap command failed') logging.error('Command: %s', ce.command) stderr = results_stderr_52lts(ce.result) if stderr: logging.error('stderr output:') logging.error(stderr) stdout = results_stdout_52lts(ce.result) if stdout: logging.error('stdout output:') logging.error(stdout) sys.exit(1) except KeyboardInterrupt: logging.info('Bootstrap interrupted by user') sys.exit(1)
def set_defcon(context_type, pathregex, context_range=None, selinux_force=False): """ Set the default context of a file/path in local SELinux policy :param context_type: The selinux context (only type is used) :param pathregex: Pathname regex e.g. r"/foo/bar/baz(/.*)?" :param context_range: MLS/MCS Security Range e.g. s0:c87,c520 :param selinux_force: True to force selinux configuration on Ubuntu :raise SelinuxError: if semanage command not found :raise SeCmdError: if semanage exits non-zero """ if ubuntu and not selinux_force: logging.warning("Ubuntu doesn't support selinux by default") return cmd = "semanage fcontext --add" if context_type: cmd += ' -t %s' % context_type if context_range: cmd += ' -r %s' % context_range if pathregex: cmd += ' "%s"' % pathregex result = process.run(cmd, ignore_status=True) result.stdout = result.stdout_text result.stderr = result.stderr_text _no_semanage(result) if result.exit_status != 0: raise SeCmdError(cmd, results_stderr_52lts(result))
def get_status(selinux_force=False): """ Get the status of selinux. :param selinux_force: True to force selinux configuration on Ubuntu :return: string of status in STATUS_LIST. :raise SeCmdError: if execute 'getenforce' failed. :raise SelinuxError: if 'getenforce' command exit 0, but the output is not expected. """ if ubuntu and not selinux_force: logging.warning("Ubuntu doesn't support selinux by default") return 'disabled' cmd = 'getenforce' try: result = process.run(cmd, ignore_status=True) except OSError: raise SeCmdError(cmd, "Command not available") if result.exit_status: raise SeCmdError(cmd, results_stderr_52lts(result)) for status in STATUS_LIST: if results_stdout_52lts(result).lower().count(status): return status else: continue raise SelinuxError("result of 'getenforce' (%s)is not expected." % results_stdout_52lts(result))
def get_status(selinux_force=False): """ Get the status of selinux. :param selinux_force: True to force selinux configuration on Ubuntu :return: string of status in STATUS_LIST. :raise SeCmdError: if execute 'getenforce' failed. :raise SelinuxError: if 'getenforce' command exit 0, but the output is not expected. """ if ubuntu and not selinux_force: logging.warning("Ubuntu doesn't support selinux by default") return 'disabled' cmd = 'getenforce' try: result = process.run(cmd, ignore_status=True) except OSError: raise SeCmdError(cmd, "Command not available") if result.exit_status: raise SeCmdError(cmd, results_stderr_52lts(result)) for status in STATUS_LIST: if results_stdout_52lts(result).lower().count(status): return status else: continue raise SelinuxError("result of 'getenforce' (%s)is not expected." % results_stdout_52lts(result))
def do_migration(vm, dest_uri, options, extra): """ Execute the migration with given parameters :param vm: the guest to be migrated :param dest_uri: the destination uri for migration :param options: options next to 'migrate' command :param extra: options in the end of the migrate command line :return: CmdResult object """ logging.info("Sleeping 10 seconds before migration") time.sleep(10) # Migrate the guest. migration_res = vm.migrate(dest_uri, options, extra, **virsh_args) logging.info("Migration out: %s", results_stdout_52lts(migration_res).strip()) logging.info("Migration error: %s", results_stderr_52lts(migration_res).strip()) if int(migration_res.exit_status) != 0: logging.error("Migration failed for %s.", vm_name) return migration_res if vm.is_alive(): # vm.connect_uri was updated logging.info("VM is alive on destination %s.", dest_uri) else: test.fail("VM is not alive on destination %s" % dest_uri) # Throws exception if console shows panic message vm.verify_kernel_crash() return migration_res
def set_defcon(context_type, pathregex, context_range=None, selinux_force=False): """ Set the default context of a file/path in local SELinux policy :param context_type: The selinux context (only type is used) :param pathregex: Pathname regex e.g. r"/foo/bar/baz(/.*)?" :param context_range: MLS/MCS Security Range e.g. s0:c87,c520 :param selinux_force: True to force selinux configuration on Ubuntu :raise SelinuxError: if semanage command not found :raise SeCmdError: if semanage exits non-zero """ if ubuntu and not selinux_force: logging.warning("Ubuntu doesn't support selinux by default") return cmd = "semanage fcontext --add" if context_type: cmd += ' -t %s' % context_type if context_range: cmd += ' -r %s' % context_range if pathregex: cmd += ' "%s"' % pathregex result = process.run(cmd, ignore_status=True) result.stdout = result.stdout_text result.stderr = result.stderr_text _no_semanage(result) if result.exit_status != 0: raise SeCmdError(cmd, results_stderr_52lts(result))
def run(self, command, timeout=60, ignore_status=False): """ Method to provide a utils.run-like interface to execute command on remote host or guest. :param timeout: Total time duration to wait for command return. :param ignore_status: If ignore_status=True, do not raise an exception, no matter what the exit code of the command is. Else, raise CmdError if exit code of command is not zero. """ # Redirect the stdout and stderr to file, Deviding error message # from output, and taking off the color of output. To return the same # result with utils.run() function. command = "%s 1>%s 2>%s" % ( command, self.stdout_pipe, self.stderr_pipe) status, _ = self.session.cmd_status_output(command, timeout=timeout) output = self.session.cmd_output("cat %s;rm -f %s" % (self.stdout_pipe, self.stdout_pipe)) errput = self.session.cmd_output("cat %s;rm -f %s" % (self.stderr_pipe, self.stderr_pipe)) cmd_result = process.CmdResult(command=command, exit_status=status, stdout=output, stderr=errput) cmd_result.stdout = results_stdout_52lts(cmd_result) cmd_result.stderr = results_stderr_52lts(cmd_result) if status and (not ignore_status): raise process.CmdError(command, cmd_result) return cmd_result
def run(self, command, timeout=60, ignore_status=False): """ Method to provide a utils.run-like interface to execute command on remote host or guest. :param timeout: Total time duration to wait for command return. :param ignore_status: If ignore_status=True, do not raise an exception, no matter what the exit code of the command is. Else, raise CmdError if exit code of command is not zero. """ # Redirect the stdout and stderr to file, Deviding error message # from output, and taking off the color of output. To return the same # result with utils.run() function. command = "%s 1>%s 2>%s" % ( command, self.stdout_pipe, self.stderr_pipe) status, _ = self.session.cmd_status_output(command, timeout=timeout) output = self.session.cmd_output("cat %s;rm -f %s" % (self.stdout_pipe, self.stdout_pipe)) errput = self.session.cmd_output("cat %s;rm -f %s" % (self.stderr_pipe, self.stderr_pipe)) cmd_result = process.CmdResult(command=command, exit_status=status, stdout=output, stderr=errput) cmd_result.stdout = results_stdout_52lts(cmd_result) cmd_result.stderr = results_stderr_52lts(cmd_result) if status and (not ignore_status): raise process.CmdError(command, cmd_result) return cmd_result
def lv_take_snapshot(vg_name, lv_name, lv_snapshot_name, lv_snapshot_size): """ Take a snapshot of the original logical volume. """ error_context.context("Taking snapshot from original logical volume", logging.info) if not vg_check(vg_name): raise exceptions.TestError("Volume group could not be found") if lv_check(vg_name, lv_snapshot_name): raise exceptions.TestError("Snapshot already exists") if not lv_check(vg_name, lv_name): raise exceptions.TestError("Snapshot's origin could not be found") cmd = ("lvcreate --size " + lv_snapshot_size + " --snapshot " + " --name " + lv_snapshot_name + " /dev/" + vg_name + "/" + lv_name) try: result = process.run(cmd) except process.CmdError as ex: if ('Logical volume "%s" already exists in volume group "%s"' % (lv_snapshot_name, vg_name) in results_stderr_52lts(ex.result) and re.search(re.escape(lv_snapshot_name + " [active]"), results_stdout_52lts(process.run("lvdisplay")))): # the above conditions detect if merge of snapshot was postponed logging.warning(("Logical volume %s is still active! " + "Attempting to deactivate..."), lv_name) lv_reactivate(vg_name, lv_name) result = process.run(cmd) else: raise ex logging.info(results_stdout_52lts(result).rstrip())
def __init__(self, params): self.nfs_client_ip = params.get("nfs_client_ip") # To Avoid host key verification failure ret = process.run("ssh-keygen -R %s" % self.nfs_client_ip, ignore_status=True) stderr = results_stderr_52lts(ret) if ret.exit_status and "No such file or directory" not in stderr: raise exceptions.TestFail("Failed to update host key: %s" % stderr) # Setup SSH connection self.ssh_obj = SSHConnection(params) ssh_timeout = int(params.get("ssh_timeout", 10)) self.ssh_obj.conn_setup(timeout=ssh_timeout) self.params = params self.mkdir_mount_remote = False self.mount_dir = params.get("nfs_mount_dir") self.mount_options = params.get("nfs_mount_options") self.mount_src = params.get("nfs_mount_src") self.nfs_server_ip = params.get("nfs_server_ip") self.ssh_user = params.get("ssh_username", "root") self.remote_nfs_mount = params.get("remote_nfs_mount", "yes") self.ssh_hostkey_check = params.get("ssh_hostkey_check", "no") == "yes" self.ssh_cmd = "ssh %s@%s " % (self.ssh_user, self.nfs_client_ip) if not self.ssh_hostkey_check: self.ssh_cmd += "-o StrictHostKeyChecking=no "
def amend(self, params, cache_mode=None, ignore_status=False): """ Amend the image format specific options for the image :param params: dictionary containing the test parameters :param cache_mode: the cache mode used to write the output disk image, the valid options are: 'none', 'writeback' (default), 'writethrough', 'directsync' and 'unsafe'. :param ignore_status: Whether to raise an exception when command returns =! 0 (False), or not (True). :note: params may contain amend options: amend_size virtual disk size of the image (a string qemu-img can understand, such as '10G') amend_compat compatibility level (0.10 or 1.1) amend_backing_file file name of a base image amend_backing_fmt image format of the base image amend_encryption encrypt the image, allowed values: on and off. Default is "off" amend_cluster_size cluster size for the image amend_preallocation preallocation mode when create image, allowed values: off, metadata. Default is "off" amend_lazy_refcounts postpone refcount updates, allowed values: on and off. Default is "off" amend_refcount_bits width of a reference count entry in bits amend_extra_params additional options, used for extending amend :return: process.CmdResult object containing the result of the command """ cmd_list = [self.image_cmd, 'amend'] options = [ "%s=%s" % (key[6:], val) for key, val in six.iteritems(params) if key.startswith('amend_') ] if cache_mode: cmd_list.append("-t %s" % cache_mode) if options: cmd_list.append("-o %s" % ",".join(options).replace("extra_params=", "")) cmd_list.append("-f %s %s" % (self.image_format, self.image_filename)) logging.info("Amend image %s" % self.image_filename) cmd_result = process.run(" ".join(cmd_list), ignore_status=False) cmd_result.stdout = results_stdout_52lts(cmd_result) cmd_result.stderr = results_stderr_52lts(cmd_result) return cmd_result
def start(self): """ Start network with self.virsh. """ cmd_result = self.virsh.net_start(self.name) if cmd_result.exit_status: raise xcepts.LibvirtXMLError( "Failed to start network %s.\n" "Detail: %s" % (self.name, results_stderr_52lts(cmd_result)))
def define(self): """ Define network from self.xml. """ cmd_result = self.virsh.net_define(self.xml) if cmd_result.exit_status: raise xcepts.LibvirtXMLError( "Failed to define network %s.\n" "Detail: %s" % (self.name, results_stderr_52lts(cmd_result)))
def check_migration_res(result): """ Check if the migration result is as expected :param result: the output of migration :raise: test.fail if test is failed """ if not err_msg: if int(result.exit_status) != 0: test.fail(results_stderr_52lts(result).strip()) else: logging.debug(result) if not re.search(err_msg, results_stderr_52lts(result).strip()): test.fail("Can not find the expected patterns '%s' in " "output '%s'" % (err_msg, results_stderr_52lts(result).strip())) else: logging.debug("It is the expected error message")
def vg_ramdisk_cleanup(ramdisk_filename, vg_ramdisk_dir, vg_name, loop_device): """ Inline cleanup function in case of test error. """ result = process.run("vgremove " + vg_name, ignore_status=True) if result.exit_status == 0: logging.info(results_stdout_52lts(result).rstrip()) else: logging.debug("%s -> %s", result.command, results_stderr_52lts(result)) result = process.run("pvremove " + loop_device, ignore_status=True) if result.exit_status == 0: logging.info(results_stdout_52lts(result).rstrip()) else: logging.debug("%s -> %s", result.command, results_stderr_52lts(result)) for _ in range(10): time.sleep(0.1) result = process.run("losetup -d " + loop_device, ignore_status=True) if b"resource busy" not in result.stderr: if result.exit_status != 0: logging.debug("%s -> %s", result.command, results_stderr_52lts(result)) else: logging.info("Loop device %s deleted", loop_device) break if os.path.exists(ramdisk_filename): os.unlink(ramdisk_filename) logging.info("Ramdisk filename %s deleted", ramdisk_filename) process.run("umount " + vg_ramdisk_dir, ignore_status=True) if result.exit_status == 0: if loop_device != "": logging.info("Loop device %s unmounted", loop_device) else: logging.debug("%s -> %s", result.command, results_stderr_52lts(result)) if os.path.exists(vg_ramdisk_dir): try: shutil.rmtree(vg_ramdisk_dir) logging.info("Ramdisk directory %s deleted", vg_ramdisk_dir) except OSError: pass
def vg_ramdisk_cleanup(ramdisk_filename, vg_ramdisk_dir, vg_name, loop_device): """ Inline cleanup function in case of test error. """ result = process.run("vgremove " + vg_name, ignore_status=True) if result.exit_status == 0: logging.info(results_stdout_52lts(result).rstrip()) else: logging.debug("%s -> %s", result.command, results_stderr_52lts(result)) result = process.run("pvremove " + loop_device, ignore_status=True) if result.exit_status == 0: logging.info(results_stdout_52lts(result).rstrip()) else: logging.debug("%s -> %s", result.command, results_stderr_52lts(result)) for _ in range(10): time.sleep(0.1) result = process.run("losetup -d " + loop_device, ignore_status=True) if b"resource busy" not in result.stderr: if result.exit_status != 0: logging.debug("%s -> %s", result.command, results_stderr_52lts(result)) else: logging.info("Loop device %s deleted", loop_device) break if os.path.exists(ramdisk_filename): os.unlink(ramdisk_filename) logging.info("Ramdisk filename %s deleted", ramdisk_filename) process.run("umount " + vg_ramdisk_dir, ignore_status=True) if result.exit_status == 0: if loop_device != "": logging.info("Loop device %s unmounted", loop_device) else: logging.debug("%s -> %s", result.command, results_stderr_52lts(result)) if os.path.exists(vg_ramdisk_dir): try: shutil.rmtree(vg_ramdisk_dir) logging.info("Ramdisk directory %s deleted", vg_ramdisk_dir) except OSError: pass
def v2v_cmd(params): """ Append 'virt-v2v' and execute it. :param params: A dictionary includes all of required parameters such as 'target', 'hypervisor' and 'hostname', etc. :return: A CmdResult object """ if V2V_EXEC is None: raise ValueError('Missing command: virt-v2v') target = params.get('target') hypervisor = params.get('hypervisor') # vpx:// or esx:// src_uri_type = params.get('src_uri_type') hostname = params.get('hostname') vpx_dc = params.get('vpx_dc') esxi_host = params.get('esxi_host', params.get('esx_ip')) opts_extra = params.get('v2v_opts') # Set v2v_timeout to 3 hours, the value can give v2v enough time to execute, # and avoid v2v process be killed by mistake. # the value is bigger than the timeout value in CI, so when some timeout # really happens, CI will still interrupt the v2v process. v2v_timeout = params.get('v2v_timeout', 10800) rhv_upload_opts = params.get('rhv_upload_opts') uri_obj = Uri(hypervisor) # Return actual 'uri' according to 'hostname' and 'hypervisor' if src_uri_type == 'esx': vpx_dc = None uri = uri_obj.get_uri(hostname, vpx_dc, esxi_host) target_obj = Target(target, uri) try: # Return virt-v2v command line options based on 'target' and # 'hypervisor' options = target_obj.get_cmd_options(params) if rhv_upload_opts: options = options + ' ' + rhv_upload_opts if opts_extra: options = options + ' ' + opts_extra # Construct a final virt-v2v command cmd = '%s %s' % (V2V_EXEC, options) cmd_result = process.run(cmd, timeout=v2v_timeout, verbose=True, ignore_status=True) finally: target_obj.cleanup() cmd_result.stdout = results_stdout_52lts(cmd_result) cmd_result.stderr = results_stderr_52lts(cmd_result) return cmd_result
def amend(self, params, cache_mode=None, ignore_status=False): """ Amend the image format specific options for the image :param params: dictionary containing the test parameters :param cache_mode: the cache mode used to write the output disk image, the valid options are: 'none', 'writeback' (default), 'writethrough', 'directsync' and 'unsafe'. :param ignore_status: Whether to raise an exception when command returns =! 0 (False), or not (True). :note: params may contain amend options: amend_size virtual disk size of the image (a string qemu-img can understand, such as '10G') amend_compat compatibility level (0.10 or 1.1) amend_backing_file file name of a base image amend_backing_fmt image format of the base image amend_encryption encrypt the image, allowed values: on and off. Default is "off" amend_cluster_size cluster size for the image amend_preallocation preallocation mode when create image, allowed values: off, metadata. Default is "off" amend_lazy_refcounts postpone refcount updates, allowed values: on and off. Default is "off" amend_refcount_bits width of a reference count entry in bits amend_extra_params additional options, used for extending amend :return: process.CmdResult object containing the result of the command """ cmd_list = [self.image_cmd, 'amend'] options = ["%s=%s" % (key[6:], val) for key, val in six.iteritems(params) if key.startswith('amend_')] if cache_mode: cmd_list.append("-t %s" % cache_mode) if options: cmd_list.append("-o %s" % ",".join(options).replace("extra_params=", "")) cmd_list.append("-f %s %s" % (self.image_format, self.image_filename)) logging.info("Amend image %s" % self.image_filename) cmd_result = process.run(" ".join(cmd_list), ignore_status=False) cmd_result.stdout = results_stdout_52lts(cmd_result) cmd_result.stderr = results_stderr_52lts(cmd_result) return cmd_result
def start(self): """ Start network with self.virsh. """ cmd_result = self.virsh.net_start(self.name) if cmd_result.exit_status: raise xcepts.LibvirtXMLError("Failed to start network %s.\n" "Detail: %s" % (self.name, results_stderr_52lts(cmd_result)))
def define(self): """ Define network from self.xml. """ cmd_result = self.virsh.net_define(self.xml) if cmd_result.exit_status: raise xcepts.LibvirtXMLError("Failed to define network %s.\n" "Detail: %s" % (self.name, results_stderr_52lts(cmd_result)))
def undefine(self): """ Undefine network witch name is self.name. """ self.virsh.net_destroy(self.name) cmd_result = self.virsh.net_undefine(self.name) if cmd_result.exit_status: raise xcepts.LibvirtXMLError( "Failed to undefine network %s.\n" "Detail: %s" % (self.name, results_stderr_52lts(cmd_result)))
def undefine(self): """ Undefine network witch name is self.name. """ self.virsh.net_destroy(self.name) cmd_result = self.virsh.net_undefine(self.name) if cmd_result.exit_status: raise xcepts.LibvirtXMLError("Failed to undefine network %s.\n" "Detail: %s" % (self.name, results_stderr_52lts(cmd_result)))
def virt_xml_validate(filename, schema_name=None): """ Return CmdResult from running virt-xml-validate on backing XML """ command = 'virt-xml-validate %s' % filename if schema_name: command += ' %s' % schema_name cmdresult = process.run(command, ignore_status=True) cmdresult.stdout = results_stdout_52lts(cmdresult) cmdresult.stderr = results_stderr_52lts(cmdresult) return cmdresult
def virt_xml_validate(filename, schema_name=None): """ Return CmdResult from running virt-xml-validate on backing XML """ command = 'virt-xml-validate %s' % filename if schema_name: command += ' %s' % schema_name cmdresult = process.run(command, ignore_status=True) cmdresult.stdout = results_stdout_52lts(cmdresult) cmdresult.stderr = results_stderr_52lts(cmdresult) return cmdresult
def del_defcon(context_type, pathregex, selinux_force=False): """ Remove the default local SELinux policy type for a file/path :param context: The selinux context (only type is used) :pramm pathregex: Pathname regex e.g. r"/foo/bar/baz(/.*)?" :param selinux_force: True to force selinux configuration on Ubuntu :raise SelinuxError: if semanage command not found :raise SeCmdError: if semanage exits non-zero """ if ubuntu and not selinux_force: logging.warning("Ubuntu doesn't support selinux by default") return cmd = ("semanage fcontext --delete -t %s '%s'" % (context_type, pathregex)) result = process.run(cmd, ignore_status=True) result.stdout = results_stdout_52lts(result) result.stderr = results_stderr_52lts(result) _no_semanage(result) if result.exit_status != 0: raise SeCmdError(cmd, results_stderr_52lts(result))
def del_defcon(context_type, pathregex, selinux_force=False): """ Remove the default local SELinux policy type for a file/path :param context: The selinux context (only type is used) :pramm pathregex: Pathname regex e.g. r"/foo/bar/baz(/.*)?" :param selinux_force: True to force selinux configuration on Ubuntu :raise SelinuxError: if semanage command not found :raise SeCmdError: if semanage exits non-zero """ if ubuntu and not selinux_force: logging.warning("Ubuntu doesn't support selinux by default") return cmd = ("semanage fcontext --delete -t %s '%s'" % (context_type, pathregex)) result = process.run(cmd, ignore_status=True) result.stdout = results_stdout_52lts(result) result.stderr = results_stderr_52lts(result) _no_semanage(result) if result.exit_status != 0: raise SeCmdError(cmd, results_stderr_52lts(result))
def new_from_dumpxml(dev_name, virsh_instance=base.virsh): """ Get a instance of NodedevXML by dumpxml dev_name. """ nodedevxml = NodedevXML(virsh_instance=virsh_instance) dumpxml_result = virsh_instance.nodedev_dumpxml(dev_name) if dumpxml_result.exit_status: stderr = results_stderr_52lts(dumpxml_result) raise xcepts.LibvirtXMLError("Nodedev_dumpxml %s failed.\n" "Error: %s." % (dev_name, stderr)) nodedevxml.xml = results_stdout_52lts(dumpxml_result) return nodedevxml
def get_vcpucount_details(vm, options): """ To get vcpucount output :param vm: VM object :param options: options to passed to vcpucount :return: tuple of result and dict of vcpucount output values """ vcpucount_details = { 'max_config': None, 'max_live': None, 'cur_config': None, 'cur_live': None, 'guest_live': None } result = virsh.vcpucount(vm.name, options, ignore_status=True, debug=True) if results_stderr_52lts(result): logging.debug("vcpu count command failed") return (result, vcpucount_details) if options: stdout = results_stdout_52lts(result).strip() if 'guest' in options: vcpucount_details['guest_live'] = int(stdout) elif 'config' in options: if 'maximum' in options: vcpucount_details['max_config'] = int(stdout) else: vcpucount_details['cur_config'] = int(stdout) elif 'live' in options: if 'maximum' in options: vcpucount_details['max_live'] = int(stdout) else: vcpucount_details['cur_live'] = int(stdout) else: output = results_stdout_52lts(result).strip().split('\n') for item in output: if ('maximum' in item) and ('config' in item): vcpucount_details['max_config'] = int(item.split()[2].strip()) elif ('maximum' in item) and ('live' in item): vcpucount_details['max_live'] = int(item.split()[2].strip()) elif ('current' in item) and ('config' in item): vcpucount_details['cur_config'] = int(item.split()[2].strip()) elif ('current' in item) and ('live' in item): vcpucount_details['cur_live'] = int(item.split()[2].strip()) else: pass return (result, vcpucount_details)
def run(**kwargs): """ Wrapped process.run invocation that will start, stop, restart, etc. a service. :param kwargs: extra arguments to process.run, .e.g. timeout. But not for ignore_status. We need a CmdResult to parse and raise a exceptions.TestError if command failed. We will not let the CmdError out. :return: result of parse_func. """ logging.debug("Setting ignore_status to True.") kwargs["ignore_status"] = True result = run_func(" ".join(command(service_name)), **kwargs) result.stdout = results_stdout_52lts(result) result.stderr = results_stderr_52lts(result) return parse_func(result)
def run(**kwargs): """ Wrapped process.run invocation that will start, stop, restart, etc. a service. :param kwargs: extra arguments to process.run, .e.g. timeout. But not for ignore_status. We need a CmdResult to parse and raise a exceptions.TestError if command failed. We will not let the CmdError out. :return: result of parse_func. """ logging.debug("Setting ignore_status to True.") kwargs["ignore_status"] = True result = run_func(" ".join(command(service_name)), **kwargs) result.stdout = results_stdout_52lts(result) result.stderr = results_stderr_52lts(result) return parse_func(result)
def compare_images(self, image1, image2, strict_mode=False, verbose=True, force_share=False): """ Compare 2 images using the appropriate tools for each virt backend. :param image1: image path of first image :param image2: image path of second image :param strict_mode: Boolean value, True for strict mode, False for default mode. :param verbose: Record output in debug file or not :return: process.CmdResult object containing the result of the command """ compare_images = self.support_cmd("compare") force_share &= self.cap_force_share if not compare_images: logging.warn("sub-command compare not supported by qemu-img") return None else: logging.info("Comparing images %s and %s", image1, image2) compare_cmd = "%s compare" % self.image_cmd if force_share: compare_cmd += " -U" if strict_mode: compare_cmd += " -s" compare_cmd += " %s %s" % (image1, image2) cmd_result = process.run(compare_cmd, ignore_status=True, shell=True) if verbose: logging.debug("Output from command: %s", results_stdout_52lts(cmd_result)) if cmd_result.exit_status == 0: logging.info("Compared images are equal") elif cmd_result.exit_status == 1: raise exceptions.TestFail("Compared images differ") else: raise exceptions.TestError("Error in image comparison") cmd_result.stdout = results_stdout_52lts(cmd_result) cmd_result.stderr = results_stderr_52lts(cmd_result) return cmd_result
def run_remote_cmd(cmd): """ A function to run a command on remote host. :param cmd: the command to be executed :return: CmdResult object """ remote_runner = remote.RemoteRunner(host=server_ip, username=server_user, password=server_pwd) cmdResult = remote_runner.run(cmd, ignore_status=True) if cmdResult.exit_status: test.fail("Failed to run '%s' on remote: %s" % (cmd, results_stderr_52lts(cmdResult).strip())) return cmdResult
def get_vcpucount_details(vm, options): """ To get vcpucount output :param vm: VM object :param options: options to passed to vcpucount :return: tuple of result and dict of vcpucount output values """ vcpucount_details = {'max_config': None, 'max_live': None, 'cur_config': None, 'cur_live': None, 'guest_live': None} result = virsh.vcpucount(vm.name, options, ignore_status=True, debug=True) if results_stderr_52lts(result): logging.debug("vcpu count command failed") return (result, vcpucount_details) if options: stdout = results_stdout_52lts(result).strip() if 'guest' in options: vcpucount_details['guest_live'] = int(stdout) elif 'config' in options: if 'maximum' in options: vcpucount_details['max_config'] = int(stdout) else: vcpucount_details['cur_config'] = int(stdout) elif 'live' in options: if 'maximum' in options: vcpucount_details['max_live'] = int(stdout) else: vcpucount_details['cur_live'] = int(stdout) else: output = results_stdout_52lts(result).strip().split('\n') for item in output: if ('maximum' in item) and ('config' in item): vcpucount_details['max_config'] = int(item.split()[2].strip()) elif ('maximum' in item) and ('live' in item): vcpucount_details['max_live'] = int(item.split()[2].strip()) elif ('current' in item) and ('config' in item): vcpucount_details['cur_config'] = int(item.split()[2].strip()) elif ('current' in item) and ('live' in item): vcpucount_details['cur_live'] = int(item.split()[2].strip()) else: pass return (result, vcpucount_details)
def check_vcpucount(vm, exp_vcpu, option="", guest_agent=False): """ To check the vcpu count details from vcpucount API :param vm: VM object :param exp_vcpu: dict of expected vcpus :param option: options to vcpucount API if any :param guest_agest: True if need to check inside guest,guest agent present :return: True if exp_vcpu matches the vcpucount output, False if not """ result = True vcpucount_result = {} vcpucount_option = "" if option == "--guest" and vm.is_alive() and guest_agent: vcpucount_option = "--guest" (vcresult, vcpucount_result) = get_vcpucount_details(vm, vcpucount_option) if results_stderr_52lts(vcresult): result = False if vcpucount_option == "--guest" and guest_agent: if vcpucount_result['guest_live'] != exp_vcpu['guest_live']: logging.error( "Virsh vcpucount output is unexpected\nExpected: " "%s\nActual: %s", exp_vcpu, vcpucount_result) result = False else: # Check for config option results if vm.is_dead(): if (exp_vcpu['max_config'] != vcpucount_result['max_config'] or exp_vcpu['cur_config'] != vcpucount_result['cur_config']): logging.error( "Virsh vcpucount output is unexpected\nExpected" ":%s\nActual:%s", exp_vcpu, vcpucount_result) result = False else: if (exp_vcpu['max_config'] != vcpucount_result['max_config'] or exp_vcpu['max_live'] != vcpucount_result['max_live'] or exp_vcpu['cur_config'] != vcpucount_result['cur_config'] or exp_vcpu['cur_live'] != vcpucount_result['cur_live']): logging.error( "Virsh vcpucount output is unexpected\n " "Expected:%s\nActual:%s", exp_vcpu, vcpucount_result) result = False if result: logging.debug("Command vcpucount check pass") return result
def check_vcpucount(vm, exp_vcpu, option="", guest_agent=False): """ To check the vcpu count details from vcpucount API :param vm: VM object :param exp_vcpu: dict of expected vcpus :param option: options to vcpucount API if any :param guest_agest: True if need to check inside guest,guest agent present :return: True if exp_vcpu matches the vcpucount output, False if not """ result = True vcpucount_result = {} vcpucount_option = "" if option == "--guest" and vm.is_alive() and guest_agent: vcpucount_option = "--guest" (vcresult, vcpucount_result) = get_vcpucount_details(vm, vcpucount_option) if results_stderr_52lts(vcresult): result = False if vcpucount_option == "--guest" and guest_agent: if vcpucount_result['guest_live'] != exp_vcpu['guest_live']: logging.error("Virsh vcpucount output is unexpected\nExpected: " "%s\nActual: %s", exp_vcpu, vcpucount_result) result = False else: # Check for config option results if vm.is_dead(): if (exp_vcpu['max_config'] != vcpucount_result['max_config'] or exp_vcpu['cur_config'] != vcpucount_result['cur_config']): logging.error("Virsh vcpucount output is unexpected\nExpected" ":%s\nActual:%s", exp_vcpu, vcpucount_result) result = False else: if (exp_vcpu['max_config'] != vcpucount_result['max_config'] or exp_vcpu['max_live'] != vcpucount_result['max_live'] or exp_vcpu['cur_config'] != vcpucount_result['cur_config'] or exp_vcpu['cur_live'] != vcpucount_result['cur_live']): logging.error("Virsh vcpucount output is unexpected\n " "Expected:%s\nActual:%s", exp_vcpu, vcpucount_result) result = False if result: logging.debug("Command vcpucount check pass") return result
def get_defcon(local=False, selinux_force=False): """ Return list of dictionaries containing SELinux default file context types :param local: Only return locally modified default contexts :param selinux_force: True to force selinux configuration on Ubuntu :return: list of dictionaries of default context attributes """ if ubuntu and not selinux_force: logging.warning("Ubuntu doesn't support selinux by default") return if local: result = process.run("semanage fcontext --list -C", ignore_status=True) else: result = process.run("semanage fcontext --list", ignore_status=True) _no_semanage(result) if result.exit_status != 0: raise SeCmdError('semanage', results_stderr_52lts(result)) result_list = results_stdout_52lts(result).strip().split('\n') # Need to process top-down instead of bottom-up result_list.reverse() first_line = result_list.pop() # First column name has a space in it column_names = [ name.strip().lower().replace(' ', '_') for name in first_line.split(' ') if len(name) > 0 ] # Shorten first column name column_names[0] = column_names[0].replace("selinux_", "") fcontexts = [] for line in result_list: if len(line) < 1: # skip blank lines continue column_data = [ name.strip() for name in line.split(' ') if len(name) > 0 ] # Enumerating data raises exception if no column_names match fcontext = dict([(column_names[idx], data) for idx, data in enumerate(column_data)]) # find/set functions only accept type, not full context string fcontext['context'] = get_type_from_context(fcontext['context']) fcontexts.append(fcontext) return fcontexts
def get_defcon(local=False, selinux_force=False): """ Return list of dictionaries containing SELinux default file context types :param local: Only return locally modified default contexts :param selinux_force: True to force selinux configuration on Ubuntu :return: list of dictionaries of default context attributes """ if ubuntu and not selinux_force: logging.warning("Ubuntu doesn't support selinux by default") return if local: result = process.run("semanage fcontext --list -C", ignore_status=True) else: result = process.run("semanage fcontext --list", ignore_status=True) _no_semanage(result) if result.exit_status != 0: raise SeCmdError('semanage', results_stderr_52lts(result)) result_list = results_stdout_52lts(result).strip().split('\n') # Need to process top-down instead of bottom-up result_list.reverse() first_line = result_list.pop() # First column name has a space in it column_names = [name.strip().lower().replace(' ', '_') for name in first_line.split(' ') if len(name) > 0] # Shorten first column name column_names[0] = column_names[0].replace("selinux_", "") fcontexts = [] for line in result_list: if len(line) < 1: # skip blank lines continue column_data = [name.strip() for name in line.split(' ') if len(name) > 0] # Enumerating data raises exception if no column_names match fcontext = dict([(column_names[idx], data) for idx, data in enumerate(column_data)]) # find/set functions only accept type, not full context string fcontext['context'] = get_type_from_context(fcontext['context']) fcontexts.append(fcontext) return fcontexts
def compare_images(self, image1, image2, strict_mode=False, verbose=True, force_share=False): """ Compare 2 images using the appropriate tools for each virt backend. :param image1: image path of first image :param image2: image path of second image :param strict_mode: Boolean value, True for strict mode, False for default mode. :param verbose: Record output in debug file or not :return: process.CmdResult object containing the result of the command """ compare_images = self.support_cmd("compare") force_share &= self.cap_force_share if not compare_images: logging.warn("sub-command compare not supported by qemu-img") return None else: logging.info("Comparing images %s and %s", image1, image2) compare_cmd = "%s compare" % self.image_cmd if force_share: compare_cmd += " -U" if strict_mode: compare_cmd += " -s" compare_cmd += " %s %s" % (image1, image2) cmd_result = process.run(compare_cmd, ignore_status=True, shell=True) if verbose: logging.debug("Output from command: %s", results_stdout_52lts(cmd_result)) if cmd_result.exit_status == 0: logging.info("Compared images are equal") elif cmd_result.exit_status == 1: raise exceptions.TestFail("Compared images differ") else: raise exceptions.TestError("Error in image comparison") cmd_result.stdout = results_stdout_52lts(cmd_result) cmd_result.stderr = results_stderr_52lts(cmd_result) return cmd_result
def v2v_cmd(params): """ Append 'virt-v2v' and execute it. :param params: A dictionary includes all of required parameters such as 'target', 'hypervisor' and 'hostname', etc. :return: A CmdResult object """ if V2V_EXEC is None: raise ValueError('Missing command: virt-v2v') target = params.get('target') hypervisor = params.get('hypervisor') hostname = params.get('hostname') vpx_dc = params.get('vpx_dc') esx_ip = params.get('esx_ip') opts_extra = params.get('v2v_opts') v2v_timeout = params.get('v2v_timeout', 2400) rhv_upload_opts = params.get('rhv_upload_opts') uri_obj = Uri(hypervisor) # Return actual 'uri' according to 'hostname' and 'hypervisor' uri = uri_obj.get_uri(hostname, vpx_dc, esx_ip) target_obj = Target(target, uri) # Return virt-v2v command line options based on 'target' and 'hypervisor' options = target_obj.get_cmd_options(params) if rhv_upload_opts: options = options + ' ' + rhv_upload_opts if opts_extra: options = options + ' ' + opts_extra # Construct a final virt-v2v command cmd = '%s %s' % (V2V_EXEC, options) cmd_result = process.run(cmd, timeout=v2v_timeout, verbose=True, ignore_status=True) cmd_result.stdout = results_stdout_52lts(cmd_result) cmd_result.stderr = results_stderr_52lts(cmd_result) return cmd_result
def get_context_of_file(filename, selinux_force=False): """ Get the context of file. :param filename: filename for the context to be get :param selinux_force: True to force selinux configuration on Ubuntu :raise SeCmdError: if execute 'getfattr' failed. """ if ubuntu and not selinux_force: logging.warning("Ubuntu doesn't support selinux by default") return # More direct than scraping 'ls' output. cmd = "getfattr --name security.selinux %s" % filename result = process.run(cmd, ignore_status=True) if result.exit_status: raise SeCmdError(cmd, results_stderr_52lts(result)) output = results_stdout_52lts(result) return get_context_from_str(output)
def get_context_of_file(filename, selinux_force=False): """ Get the context of file. :param filename: filename for the context to be get :param selinux_force: True to force selinux configuration on Ubuntu :raise SeCmdError: if execute 'getfattr' failed. """ if ubuntu and not selinux_force: logging.warning("Ubuntu doesn't support selinux by default") return # More direct than scraping 'ls' output. cmd = "getfattr --name security.selinux %s" % filename result = process.run(cmd, ignore_status=True) if result.exit_status: raise SeCmdError(cmd, results_stderr_52lts(result)) output = results_stdout_52lts(result) return get_context_from_str(output)
def set_status(status, selinux_force=False): """ Set status of selinux. :param status: status want to set selinux. :param selinux_force: True to force selinux configuration on Ubuntu :raise SelinuxError: status is not supported. :raise SelinuxError: need to reboot host. :raise SeCmdError: execute setenforce failed. :raise SelinuxError: cmd setenforce exit normally, but status of selinux is not set to expected. """ if ubuntu and not selinux_force: logging.warning("Ubuntu doesn't support selinux by default") return if status not in STATUS_LIST: raise SelinuxError("Status %s is not accepted." % status) current_status = get_status(selinux_force) if status == current_status: return else: if current_status == "disabled" or status == "disabled": raise SelinuxError("Please modify /etc/selinux/config and " "reboot host to set selinux to %s." % status) else: cmd = "setenforce %s" % status result = process.run(cmd, ignore_status=True) if result.exit_status: raise SeCmdError(cmd, results_stderr_52lts(result)) else: current_status = get_status(selinux_force) if not status == current_status: raise SelinuxError("Status of selinux is set to %s," "but not expected %s. " % (current_status, status)) else: pass logging.debug("Set status of selinux to %s success.", status)
def set_status(status, selinux_force=False): """ Set status of selinux. :param status: status want to set selinux. :param selinux_force: True to force selinux configuration on Ubuntu :raise SelinuxError: status is not supported. :raise SelinuxError: need to reboot host. :raise SeCmdError: execute setenforce failed. :raise SelinuxError: cmd setenforce exit normally, but status of selinux is not set to expected. """ if ubuntu and not selinux_force: logging.warning("Ubuntu doesn't support selinux by default") return if status not in STATUS_LIST: raise SelinuxError("Status %s is not accepted." % status) current_status = get_status(selinux_force) if status == current_status: return else: if current_status == "disabled" or status == "disabled": raise SelinuxError("Please modify /etc/selinux/config and " "reboot host to set selinux to %s." % status) else: cmd = "setenforce %s" % status result = process.run(cmd, ignore_status=True) if result.exit_status: raise SeCmdError(cmd, results_stderr_52lts(result)) else: current_status = get_status(selinux_force) if not status == current_status: raise SelinuxError("Status of selinux is set to %s," "but not expected %s. " % (current_status, status)) else: pass logging.debug("Set status of selinux to %s success.", status)
def v2v_cmd(params): """ Append 'virt-v2v' and execute it. :param params: A dictionary includes all of required parameters such as 'target', 'hypervisor' and 'hostname', etc. :return: A CmdResult object """ if V2V_EXEC is None: raise ValueError('Missing command: virt-v2v') target = params.get('target') hypervisor = params.get('hypervisor') hostname = params.get('hostname') vpx_dc = params.get('vpx_dc') esx_ip = params.get('esx_ip') opts_extra = params.get('v2v_opts') v2v_timeout = params.get('v2v_timeout', 5400) rhv_upload_opts = params.get('rhv_upload_opts') uri_obj = Uri(hypervisor) # Return actual 'uri' according to 'hostname' and 'hypervisor' uri = uri_obj.get_uri(hostname, vpx_dc, esx_ip) target_obj = Target(target, uri) # Return virt-v2v command line options based on 'target' and 'hypervisor' options = target_obj.get_cmd_options(params) if rhv_upload_opts: options = options + ' ' + rhv_upload_opts if opts_extra: options = options + ' ' + opts_extra # Construct a final virt-v2v command cmd = '%s %s' % (V2V_EXEC, options) cmd_result = process.run(cmd, timeout=v2v_timeout, verbose=True, ignore_status=True) cmd_result.stdout = results_stdout_52lts(cmd_result) cmd_result.stderr = results_stderr_52lts(cmd_result) return cmd_result
def check_image(self, params, root_dir, force_share=False): """ Check an image using the appropriate tools for each virt backend. :param params: Dictionary containing the test parameters. :param root_dir: Base directory for relative filenames. :note: params should contain: image_name -- the name of the image file, without extension image_format -- the format of the image (qcow2, raw etc) :raise VMImageCheckError: In case qemu-img check fails on the image. """ image_filename = self.image_filename logging.debug("Checking image file %s", image_filename) image_is_checkable = self.image_format in ['qcow2', 'qed'] force_share &= self.cap_force_share if (storage.file_exists(params, image_filename) or self.is_remote_image()) and image_is_checkable: check_img = self.support_cmd("check") and self.support_cmd("info") if not check_img: logging.debug("Skipping image check " "(lack of support in qemu-img)") else: try: # FIXME: do we really need it? self.info(force_share) except process.CmdError: logging.error("Error getting info from image %s", image_filename) chk_cmd = "%s check" % self.image_cmd if force_share: chk_cmd += " -U" chk_cmd += " %s" % image_filename cmd_result = process.run(chk_cmd, ignore_status=True, shell=True, verbose=False) # Error check, large chances of a non-fatal problem. # There are chances that bad data was skipped though if cmd_result.exit_status == 1: stdout = results_stdout_52lts(cmd_result) for e_line in stdout.splitlines(): logging.error("[stdout] %s", e_line) stderr = results_stderr_52lts(cmd_result) for e_line in stderr.splitlines(): logging.error("[stderr] %s", e_line) chk = params.get("backup_image_on_check_error", "no") if chk == "yes": self.backup_image(params, root_dir, "backup", False) raise exceptions.TestWarn("qemu-img check exceptions. Some bad " "data in the image may have gone" " unnoticed (%s)" % image_filename) # Exit status 2 is data corruption for sure, # so fail the test elif cmd_result.exit_status == 2: stdout = results_stdout_52lts(cmd_result) for e_line in stdout.splitlines(): logging.error("[stdout] %s", e_line) stderr = results_stderr_52lts(cmd_result) for e_line in stderr.splitlines(): logging.error("[stderr] %s", e_line) chk = params.get("backup_image_on_check_error", "no") if chk == "yes": self.backup_image(params, root_dir, "backup", False) raise virt_vm.VMImageCheckError(image_filename) # Leaked clusters, they are known to be harmless to data # integrity elif cmd_result.exit_status == 3: raise exceptions.TestWarn("Leaked clusters were noticed" " during image check. No data " "integrity problem was found " "though. (%s)" % image_filename) # Just handle normal operation if params.get("backup_image", "no") == "yes": self.backup_image(params, root_dir, "backup", True, True) else: if not storage.file_exists(params, image_filename): logging.debug("Image file %s not found, skipping check", image_filename) elif not image_is_checkable: logging.debug( "Image format %s is not checkable, skipping check", self.image_format)
def run(test, params, env): """ Test virsh migrate command. """ def set_feature(vmxml, feature, value): """ Set guest features for PPC :param state: the htm status :param vmxml: guest xml """ features_xml = vm_xml.VMFeaturesXML() if feature == 'hpt': features_xml.hpt_resizing = value elif feature == 'htm': features_xml.htm = value vmxml.features = features_xml vmxml.sync() def trigger_hpt_resize(session): """ Check the HPT order file and dmesg :param session: the session to guest :raise: test.fail if required message is not found """ hpt_order_path = "/sys/kernel/debug/powerpc/hpt_order" hpt_order = session.cmd_output('cat %s' % hpt_order_path).strip() hpt_order = int(hpt_order) logging.info('Current hpt_order is %d', hpt_order) hpt_order += 1 cmd = 'echo %d > %s' % (hpt_order, hpt_order_path) cmd_result = session.cmd_status_output(cmd) result = process.CmdResult(stderr=cmd_result[1], stdout=cmd_result[1], exit_status=cmd_result[0]) libvirt.check_exit_status(result) dmesg = session.cmd('dmesg') dmesg_content = params.get('dmesg_content').split('|') for content in dmesg_content: if content % hpt_order not in dmesg: test.fail("'%s' is missing in dmesg" % (content % hpt_order)) else: logging.info("'%s' is found in dmesg", content % hpt_order) def check_vm_network_accessed(session=None): """ The operations to the VM need to be done before or after migration happens :param session: The session object to the host :raise: test.error when ping fails """ # Confirm local/remote VM can be accessed through network. logging.info("Check VM network connectivity") s_ping, _ = utils_test.ping(vm.get_address(), count=10, timeout=20, output_func=logging.debug, session=session) if s_ping != 0: if session: session.close() test.fail("%s did not respond after %d sec." % (vm.name, 20)) def check_virsh_command_and_option(command, option=None): """ Check if virsh command exists :param command: the command to be checked :param option: the command option to be checked """ msg = "This version of libvirt does not support " if not virsh.has_help_command(command): test.cancel(msg + "virsh command '%s'" % command) if option and not virsh.has_command_help_match(command, option): test.cancel(msg + "virsh command '%s' with option '%s'" % (command, option)) def add_ctrls(vm_xml, dev_type="pci", dev_index="0", dev_model="pci-root"): """ Add multiple devices :param dev_type: the type of the device to be added :param dev_index: the maximum index of the device to be added :param dev_model: the model of the device to be added """ for inx in range(0, int(dev_index) + 1): newcontroller = Controller("controller") newcontroller.type = dev_type newcontroller.index = inx newcontroller.model = dev_model logging.debug("New device is added:\n%s", newcontroller) vm_xml.add_device(newcontroller) vm_xml.sync() def do_migration(vm, dest_uri, options, extra): """ Execute the migration with given parameters :param vm: the guest to be migrated :param dest_uri: the destination uri for migration :param options: options next to 'migrate' command :param extra: options in the end of the migrate command line :return: CmdResult object """ logging.info("Sleeping 10 seconds before migration") time.sleep(10) # Migrate the guest. virsh_args.update({"ignore_status": True}) migration_res = vm.migrate(dest_uri, options, extra, **virsh_args) if int(migration_res.exit_status) != 0: logging.error("Migration failed for %s.", vm_name) return migration_res if vm.is_alive(): # vm.connect_uri was updated logging.info("VM is alive on destination %s.", dest_uri) else: test.fail("VM is not alive on destination %s" % dest_uri) # Throws exception if console shows panic message vm.verify_kernel_crash() return migration_res def cleanup_libvirtd_log(log_file): """ Remove existing libvirtd log file on source and target host. :param log_file: log file with absolute path """ if os.path.exists(log_file): logging.debug("Delete local libvirt log file '%s'", log_file) os.remove(log_file) cmd = "rm -f %s" % log_file logging.debug("Delete remote libvirt log file '%s'", log_file) cmd_parms = {'server_ip': server_ip, 'server_user': server_user, 'server_pwd': server_pwd} remote.run_remote_cmd(cmd, cmd_parms, runner_on_target) def cleanup_dest(vm): """ Clean up the destination host environment when doing the uni-direction migration. :param vm: the guest to be cleaned up """ logging.info("Cleaning up VMs on %s", vm.connect_uri) try: if virsh.domain_exists(vm.name, uri=vm.connect_uri): vm_state = vm.state() if vm_state == "paused": vm.resume() elif vm_state == "shut off": vm.start() vm.destroy(gracefully=False) if vm.is_persistent(): vm.undefine() except Exception as detail: logging.error("Cleaning up destination failed.\n%s", detail) 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): """ Control migration duration :param to_speed: the speed value in Mbps to be set for migration :return int: the new migration speed after setting """ virsh_args.update({"ignore_status": False}) old_speed = virsh.migrate_getspeed(vm_name, **virsh_args) logging.debug("Current migration speed is %s MiB/s\n", old_speed.stdout.strip()) logging.debug("Set migration speed to %d MiB/s\n", to_speed) cmd_result = virsh.migrate_setspeed(vm_name, to_speed, "", **virsh_args) actual_speed = virsh.migrate_getspeed(vm_name, **virsh_args) logging.debug("New migration speed is %s MiB/s\n", actual_speed.stdout.strip()) return int(actual_speed.stdout.strip()) def check_setspeed(params): """ Set/get migration speed :param params: the parameters used :raise: test.fail if speed set does not take effect """ expected_value = int(params.get("migrate_speed", '41943040')) // (1024 * 1024) actual_value = control_migrate_speed(to_speed=expected_value) params.update({'compare_to_value': actual_value}) if actual_value != expected_value: test.fail("Migration speed is expected to be '%d MiB/s', but '%d MiB/s' " "found" % (expected_value, actual_value)) def check_domjobinfo(params, option=""): """ Check given item in domjobinfo of the guest is as expected :param params: the parameters used :param option: options for domjobinfo :raise: test.fail if the value of given item is unexpected """ def search_jobinfo(jobinfo): """ Find value of given item in domjobinfo :param jobinfo: cmdResult object :raise: test.fail if not found """ for item in jobinfo.stdout.splitlines(): if item.count(jobinfo_item): groups = re.findall(r'[0-9.]+', item.strip()) logging.debug("In '%s' search '%s'\n", item, groups[0]) if (math.fabs(float(groups[0]) - float(compare_to_value)) // float(compare_to_value) > diff_rate): test.fail("{} {} has too much difference from " "{}".format(jobinfo_item, groups[0], compare_to_value)) break jobinfo_item = params.get("jobinfo_item") compare_to_value = params.get("compare_to_value") logging.debug("compare_to_value:%s", compare_to_value) diff_rate = float(params.get("diff_rate", "0")) if not jobinfo_item or not compare_to_value: return vm_ref = '{}{}'.format(vm_name, option) jobinfo = virsh.domjobinfo(vm_ref, **virsh_args) search_jobinfo(jobinfo) check_domjobinfo_remote = params.get("check_domjobinfo_remote") if check_domjobinfo_remote: remote_virsh_session = virsh.VirshPersistent(**remote_virsh_dargs) jobinfo = remote_virsh_session.domjobinfo(vm_ref, **virsh_args) search_jobinfo(jobinfo) remote_virsh_session.close_session() def check_maxdowntime(params): """ Set/get migration maxdowntime :param params: the parameters used :raise: test.fail if maxdowntime set does not take effect """ expected_value = int(float(params.get("migrate_maxdowntime", '0.3')) * 1000) virsh_args.update({"ignore_status": False}) old_value = int(virsh.migrate_getmaxdowntime(vm_name).stdout.strip()) logging.debug("Current migration maxdowntime is %d ms", old_value) logging.debug("Set migration maxdowntime to %d ms", expected_value) virsh.migrate_setmaxdowntime(vm_name, expected_value, **virsh_args) actual_value = int(virsh.migrate_getmaxdowntime(vm_name).stdout.strip()) logging.debug("New migration maxdowntime is %d ms", actual_value) if actual_value != expected_value: test.fail("Migration maxdowntime is expected to be '%d ms', but '%d ms' " "found" % (expected_value, actual_value)) params.update({'compare_to_value': actual_value}) def do_actions_during_migrate(params): """ The entry point to execute action list during migration :param params: the parameters used """ actions_during_migration = params.get("actions_during_migration") if not actions_during_migration: return for action in actions_during_migration.split(","): if action == 'setspeed': check_setspeed(params) elif action == 'domjobinfo': check_domjobinfo(params) elif action == 'setmaxdowntime': check_maxdowntime(params) time.sleep(3) def attach_channel_xml(): """ Create channel xml and attach it to guest configuration """ # Check if pty channel exists already for elem in new_xml.devices.by_device_tag('channel'): if elem.type_name == channel_type_name: logging.debug("{0} channel already exists in guest. " "No need to add new one".format(channel_type_name)) return params = {'channel_type_name': channel_type_name, 'target_type': target_type, 'target_name': target_name} channel_xml = libvirt.create_channel_xml(params) virsh.attach_device(domain_opt=vm_name, file_opt=channel_xml.xml, flagstr="--config", ignore_status=False) logging.debug("New VMXML with channel:\n%s", virsh.dumpxml(vm_name)) def check_timeout_postcopy(params): """ Check the vm state on target host after timeout when --postcopy and --timeout-postcopy are used. The vm state is expected as running. :param params: the parameters used """ timeout = int(params.get("timeout_postcopy", 10)) time.sleep(timeout + 1) remote_virsh_session = virsh.VirshPersistent(**remote_virsh_dargs) vm_state = results_stdout_52lts(remote_virsh_session.domstate(vm_name)).strip() if vm_state != "running": remote_virsh_session.close_session() test.fail("After timeout '%s' seconds, " "the vm state on target host should " "be 'running', but '%s' found", timeout, vm_state) remote_virsh_session.close_session() def get_usable_compress_cache(pagesize): """ Get a number which is bigger than pagesize and is power of two. :param pagesize: the given integer :return: an integer satisfying the criteria """ def calculate(num): result = num & (num - 1) return (result == 0) item = pagesize found = False while (not found): item += 1 found = calculate(item) logging.debug("%d is smallest one that is bigger than '%s' and " "is power of 2", item, pagesize) return item def check_migration_res(result): """ Check if the migration result is as expected :param result: the output of migration :raise: test.fail if test is failed """ logging.info("Migration out: %s", results_stdout_52lts(result).strip()) logging.info("Migration error: %s", results_stderr_52lts(result).strip()) if status_error: # Migration should fail if err_msg: # Special error messages are expected if not re.search(err_msg, results_stderr_52lts(result).strip()): test.fail("Can not find the expected patterns '%s' in " "output '%s'" % (err_msg, results_stderr_52lts(result).strip())) else: logging.debug("It is the expected error message") else: if int(result.exit_status) != 0: logging.debug("Migration failure is expected result") else: test.fail("Migration success is unexpected result") else: if int(result.exit_status) != 0: test.fail(results_stderr_52lts(result).strip()) check_parameters(test, params) # Params for NFS shared storage shared_storage = params.get("migrate_shared_storage", "") if shared_storage == "": default_guest_asset = defaults.get_default_guest_os_info()['asset'] default_guest_asset = "%s.qcow2" % default_guest_asset shared_storage = os.path.join(params.get("nfs_mount_dir"), default_guest_asset) logging.debug("shared_storage:%s", shared_storage) # params for migration connection params["virsh_migrate_desturi"] = libvirt_vm.complete_uri( params.get("migrate_dest_host")) # Params to update disk using shared storage params["disk_type"] = "file" params["disk_source_protocol"] = "netfs" params["mnt_path_name"] = params.get("nfs_mount_dir") # Local variables virsh_args = {"debug": True} virsh_opt = params.get("virsh_opt", "") server_ip = params.get("server_ip") server_user = params.get("server_user", "root") server_pwd = params.get("server_pwd") extra = params.get("virsh_migrate_extra") options = params.get("virsh_migrate_options") src_uri = params.get("virsh_migrate_connect_uri") dest_uri = params.get("virsh_migrate_desturi") log_file = params.get("libvirt_log", "/var/log/libvirt/libvirtd.log") check_complete_job = "yes" == params.get("check_complete_job", "no") config_libvirtd = "yes" == params.get("config_libvirtd", "no") contrl_index = params.get("new_contrl_index", None) asynch_migration = "yes" == params.get("asynch_migrate", "no") grep_str_remote_log = params.get("grep_str_remote_log", "") grep_str_local_log = params.get("grep_str_local_log", "") disable_verify_peer = "yes" == params.get("disable_verify_peer", "no") status_error = "yes" == params.get("status_error", "no") stress_in_vm = "yes" == params.get("stress_in_vm", "no") low_speed = params.get("low_speed", None) remote_virsh_dargs = {'remote_ip': server_ip, 'remote_user': server_user, 'remote_pwd': server_pwd, 'unprivileged_user': None, 'ssh_remote_auth': True} hpt_resize = params.get("hpt_resize", None) htm_state = params.get("htm_state", None) # For pty channel test add_channel = "yes" == params.get("add_channel", "no") channel_type_name = params.get("channel_type_name", None) target_type = params.get("target_type", None) target_name = params.get("target_name", None) cmd_run_in_remote_guest = params.get("cmd_run_in_remote_guest", None) cmd_run_in_remote_guest_1 = params.get("cmd_run_in_remote_guest_1", None) cmd_run_in_remote_host = params.get("cmd_run_in_remote_host", None) cmd_run_in_remote_host_1 = params.get("cmd_run_in_remote_host_1", None) cmd_run_in_remote_host_2 = params.get("cmd_run_in_remote_host_2", None) # For qemu command line checking qemu_check = params.get("qemu_check", None) xml_check_after_mig = params.get("guest_xml_check_after_mig", None) # params for cache matrix test cache = params.get("cache") remove_cache = "yes" == params.get("remove_cache", "no") err_msg = params.get("err_msg") arch = platform.machine() if any([hpt_resize, contrl_index, htm_state]) and 'ppc64' not in arch: test.cancel("The case is PPC only.") # For TLS tls_recovery = params.get("tls_auto_recovery", "yes") # qemu config qemu_conf_dict = None # libvirtd config libvirtd_conf_dict = None remote_virsh_session = None vm = None vm_session = None libvirtd_conf = None qemu_conf = None mig_result = None test_exception = None is_TestError = False is_TestFail = False is_TestSkip = False # Objects to be cleaned up in the end objs_list = [] tls_obj = None # Local variables vm_name = params.get("migrate_main_vm") vm = env.get_vm(vm_name) vm.verify_alive() # For safety reasons, we'd better back up xmlfile. new_xml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) orig_config_xml = new_xml.copy() if not orig_config_xml: test.error("Backing up xmlfile failed.") try: # Create a remote runner for later use runner_on_target = remote.RemoteRunner(host=server_ip, username=server_user, password=server_pwd) # Change the configuration files if needed before starting guest # For qemu.conf if extra.count("--tls"): # Setup TLS tls_obj = TLSConnection(params) if tls_recovery == "yes": objs_list.append(tls_obj) tls_obj.auto_recover = True tls_obj.conn_setup() if not disable_verify_peer: qemu_conf_dict = {"migrate_tls_x509_verify": "1"} # Setup qemu configure logging.debug("Configure the qemu") cleanup_libvirtd_log(log_file) qemu_conf = libvirt.customize_libvirt_config(qemu_conf_dict, config_type="qemu", remote_host=True, extra_params=params) # Setup libvirtd if config_libvirtd: logging.debug("Configure the libvirtd") cleanup_libvirtd_log(log_file) libvirtd_conf_dict = setup_libvirtd_conf_dict(params) libvirtd_conf = libvirt.customize_libvirt_config(libvirtd_conf_dict, remote_host=True, extra_params=params) # Prepare required guest xml before starting guest if contrl_index: new_xml.remove_all_device_by_type('controller') logging.debug("After removing controllers, current XML:\n%s\n", new_xml) add_ctrls(new_xml, dev_index=contrl_index) if add_channel: attach_channel_xml() if hpt_resize: set_feature(new_xml, 'hpt', hpt_resize) if htm_state: set_feature(new_xml, 'htm', htm_state) if cache: params["driver_cache"] = cache if remove_cache: params["enable_cache"] = "no" # Change the disk of the vm to shared disk and then start VM libvirt.set_vm_disk(vm, params) if not vm.is_alive(): vm.start() logging.debug("Guest xml after starting:\n%s", vm_xml.VMXML.new_from_dumpxml(vm_name)) # Check qemu command line after guest is started if qemu_check: check_content = qemu_check if hpt_resize: check_content = "%s%s" % (qemu_check, hpt_resize) if htm_state: check_content = "%s%s" % (qemu_check, htm_state) libvirt.check_qemu_cmd_line(check_content) # Check local guest network connection before migration vm_session = vm.wait_for_login() check_vm_network_accessed() # Preparation for the running guest before migration if hpt_resize and hpt_resize != 'disabled': trigger_hpt_resize(vm_session) if low_speed: control_migrate_speed(int(low_speed)) 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() if extra.count("timeout-postcopy"): func_name = check_timeout_postcopy if params.get("actions_during_migration"): func_name = do_actions_during_migrate if extra.count("comp-xbzrle-cache"): cache = get_usable_compress_cache(memory.get_page_size()) extra = "%s %s" % (extra, cache) # For --postcopy enable postcopy_options = params.get("postcopy_options") if postcopy_options: extra = "%s %s" % (extra, postcopy_options) # Execute migration process if not asynch_migration: mig_result = do_migration(vm, dest_uri, options, extra) else: migration_test = libvirt.MigrationTest() logging.debug("vm.connect_uri=%s", vm.connect_uri) vms = [vm] try: migration_test.do_migration(vms, None, dest_uri, 'orderly', options, thread_timeout=900, ignore_status=True, virsh_opt=virsh_opt, func=func_name, extra_opts=extra, func_params=params) mig_result = migration_test.ret except exceptions.TestFail as fail_detail: test.fail(fail_detail) except exceptions.TestSkipError as skip_detail: test.cancel(skip_detail) except exceptions.TestError as error_detail: test.error(error_detail) except Exception as details: mig_result = migration_test.ret logging.error(details) check_migration_res(mig_result) if add_channel: # Get the channel device source path of remote guest if not remote_virsh_session: remote_virsh_session = virsh.VirshPersistent(**remote_virsh_dargs) file_path = tempfile.mktemp(dir=data_dir.get_tmp_dir()) remote_virsh_session.dumpxml(vm_name, to_file=file_path, debug=True, ignore_status=True) local_vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) local_vmxml.xmltreefile = xml_utils.XMLTreeFile(file_path) for elem in local_vmxml.devices.by_device_tag('channel'): logging.debug("Found channel device {}".format(elem)) if elem.type_name == channel_type_name: host_source = elem.source.get('path') logging.debug("Remote guest uses {} for channel device".format(host_source)) break remote_virsh_session.close_session() if not host_source: test.fail("Can not find source for %s channel on remote host" % channel_type_name) # Prepare to wait for message on remote host from the channel cmd_parms = {'server_ip': server_ip, 'server_user': server_user, 'server_pwd': server_pwd} cmd_result = remote.run_remote_cmd(cmd_run_in_remote_host % host_source, cmd_parms, runner_on_target) # Send message from remote guest to the channel file remote_vm_obj = utils_test.RemoteVMManager(cmd_parms) vm_ip = vm.get_address() vm_pwd = params.get("password") remote_vm_obj.setup_ssh_auth(vm_ip, vm_pwd) cmd_result = remote_vm_obj.run_command(vm_ip, cmd_run_in_remote_guest_1) remote_vm_obj.run_command(vm_ip, cmd_run_in_remote_guest % results_stdout_52lts(cmd_result).strip()) logging.debug("Sending message is done") # Check message on remote host from the channel remote.run_remote_cmd(cmd_run_in_remote_host_1, cmd_parms, runner_on_target) logging.debug("Receiving message is done") remote.run_remote_cmd(cmd_run_in_remote_host_2, cmd_parms, runner_on_target) if check_complete_job: opts = " --completed" check_virsh_command_and_option("domjobinfo", opts) if extra.count("comp-xbzrle-cache"): params.update({'compare_to_value': cache // 1024}) check_domjobinfo(params, option=opts) if grep_str_local_log: cmd = "grep -E '%s' %s" % (grep_str_local_log, log_file) cmdRes = process.run(cmd, shell=True, ignore_status=True) if cmdRes.exit_status: test.fail(results_stderr_52lts(cmdRes).strip()) if grep_str_remote_log: cmd = "grep -E '%s' %s" % (grep_str_remote_log, log_file) cmd_parms = {'server_ip': server_ip, 'server_user': server_user, 'server_pwd': server_pwd} remote.run_remote_cmd(cmd, cmd_parms, runner_on_target) if xml_check_after_mig: if not remote_virsh_session: remote_virsh_session = virsh.VirshPersistent(**remote_virsh_dargs) target_guest_dumpxml = results_stdout_52lts( remote_virsh_session.dumpxml(vm_name, debug=True, ignore_status=True)).strip() if hpt_resize: check_str = hpt_resize elif htm_state: check_str = htm_state if hpt_resize or htm_state: xml_check_after_mig = "%s'%s'" % (xml_check_after_mig, check_str) if not re.search(xml_check_after_mig, target_guest_dumpxml): remote_virsh_session.close_session() test.fail("Fail to search '%s' in target guest XML:\n%s" % (xml_check_after_mig, target_guest_dumpxml)) if contrl_index: all_ctrls = re.findall(xml_check_after_mig, target_guest_dumpxml) if len(all_ctrls) != int(contrl_index) + 1: remote_virsh_session.close_session() test.fail("%s pci-root controllers are expected in guest XML, " "but found %s" % (int(contrl_index) + 1, len(all_ctrls))) remote_virsh_session.close_session() if int(mig_result.exit_status) == 0: server_session = remote.wait_for_login('ssh', server_ip, '22', server_user, server_pwd, r"[\#\$]\s*$") check_vm_network_accessed(server_session) server_session.close() except exceptions.TestFail as details: is_TestFail = True test_exception = details except exceptions.TestSkipError as details: is_TestSkip = True test_exception = details except exceptions.TestError as details: is_TestError = True test_exception = details except Exception as details: test_exception = details finally: logging.debug("Recover test environment") try: # Clean VM on destination vm.connect_uri = dest_uri cleanup_dest(vm) vm.connect_uri = src_uri logging.info("Recovery VM XML configration") orig_config_xml.sync() logging.debug("The current VM XML:\n%s", orig_config_xml.xmltreefile) if remote_virsh_session: remote_virsh_session.close_session() if extra.count("--tls") and not disable_verify_peer: logging.debug("Recover the qemu configuration") libvirt.customize_libvirt_config(None, config_type="qemu", remote_host=True, extra_params=params, is_recover=True, config_object=qemu_conf) if config_libvirtd: logging.debug("Recover the libvirtd configuration") libvirt.customize_libvirt_config(None, remote_host=True, extra_params=params, is_recover=True, config_object=libvirtd_conf) logging.info("Remove local NFS image") source_file = params.get("source_file") libvirt.delete_local_disk("file", path=source_file) if objs_list: for obj in objs_list: logging.debug("Clean up local objs") del obj except Exception as exception_detail: if (not test_exception and not is_TestError and not is_TestFail and not is_TestSkip): raise exception_detail else: # if any of above exceptions has been raised, only print # error log here to avoid of hiding the original issue logging.error(exception_detail) # Check result if is_TestFail: test.fail(test_exception) if is_TestSkip: test.cancel(test_exception) if is_TestError: test.error(test_exception) if not test_exception: logging.info("Case execution is done.") else: test.error(test_exception)
def create(self, params, ignore_errors=False): """ Create an image using qemu_img or dd. :param params: Dictionary containing the test parameters. :param ignore_errors: Whether to ignore errors on the image creation cmd. :note: params should contain: image_name name of the image file, without extension image_format format of the image (qcow2, raw etc) image_cluster_size (optional) cluster size for the image image_size requested size of the image (a string qemu-img can understand, such as '10G') create_with_dd use dd to create the image (raw format only) base_image(optional) the base image name when create snapshot base_format(optional) the format of base image encrypted(optional) if the image is encrypted, allowed values: on and off. Default is "off" preallocated(optional) if preallocation when create image, allowed values: off, metadata. Default is "off" :return: tuple (path to the image created, process.CmdResult object containing the result of the creation command). """ if params.get( "create_with_dd") == "yes" and self.image_format == "raw": # maps K,M,G,T => (count, bs) human = {'K': (1, 1), 'M': (1, 1024), 'G': (1024, 1024), 'T': (1024, 1048576), } if self.size[-1] in human: block_size = human[self.size[-1]][1] size = int(self.size[:-1]) * human[self.size[-1]][0] qemu_img_cmd = ("dd if=/dev/zero of=%s count=%s bs=%sK" % (self.image_filename, size, block_size)) else: qemu_img_cmd = self.image_cmd qemu_img_cmd += " create" qemu_img_cmd += " -f %s" % self.image_format image_cluster_size = params.get("image_cluster_size", None) preallocated = params.get("preallocated", "off") encrypted = params.get("encrypted", "off") image_extra_params = params.get("image_extra_params", "") has_backing_file = params.get('has_backing_file') qemu_img_cmd += " -o " if self.image_format == "qcow2": if preallocated != "off": qemu_img_cmd += "preallocation=%s," % preallocated if encrypted != "off": qemu_img_cmd += "encryption=%s," % encrypted if image_cluster_size: qemu_img_cmd += "cluster_size=%s," % image_cluster_size if has_backing_file == "yes": backing_param = params.object_params("backing_file") backing_file = storage.get_image_filename(backing_param, self.root_dir) backing_fmt = backing_param.get("image_format") qemu_img_cmd += "backing_file=%s," % backing_file qemu_img_cmd += "backing_fmt=%s," % backing_fmt if image_extra_params: qemu_img_cmd += "%s," % image_extra_params qemu_img_cmd = qemu_img_cmd.rstrip(" -o") qemu_img_cmd = qemu_img_cmd.rstrip(",") if self.base_tag: qemu_img_cmd += " -b %s" % self.base_image_filename if self.base_format: qemu_img_cmd += " -F %s" % self.base_format qemu_img_cmd += " %s" % self.image_filename qemu_img_cmd += " %s" % self.size if (params.get("image_backend", "filesystem") == "filesystem"): image_dirname = os.path.dirname(self.image_filename) if image_dirname and not os.path.isdir(image_dirname): e_msg = ("Parent directory of the image file %s does " "not exist" % self.image_filename) logging.error(e_msg) logging.error("This usually means a serious setup exceptions.") logging.error("Please verify if your data dir contains the " "expected directory structure") logging.error("Backing data dir: %s", data_dir.get_backing_data_dir()) logging.error("Directory structure:") for root, _, _ in os.walk(data_dir.get_backing_data_dir()): logging.error(root) logging.warning("We'll try to proceed by creating the dir. " "Other errors may ensue") os.makedirs(image_dirname) msg = "Create image by command: %s" % qemu_img_cmd error_context.context(msg, logging.info) cmd_result = process.run( qemu_img_cmd, shell=True, verbose=False, ignore_status=True) if cmd_result.exit_status != 0 and not ignore_errors: raise exceptions.TestError("Failed to create image %s" % self.image_filename) cmd_result.stdout = results_stdout_52lts(cmd_result) cmd_result.stderr = results_stderr_52lts(cmd_result) return self.image_filename, cmd_result