def test_default_default(self): style = self.get_style( utils_misc.generate_random_string(16), utils_misc.generate_random_string(16)) self.assertEqual(style['mac_prefix'], '9a') self.assertEqual(style['container_class'], utils_net.QemuIface) self.assert_(issubclass(style['container_class'], utils_net.VirtIface))
def file_exists(params, filename_path): sg_uri = create_gluster_uri(params, stripped=True) g_uri = create_gluster_uri(params, stripped=False) # Using directly /tmp dir because directory should be really temporary and # should be deleted immediately when no longer needed and # created directory don't file tmp dir by any data. tmpdir = "gmount-%s" % (utils_misc.generate_random_string(6)) tmpdir_path = os.path.join(data_dir.get_tmp_dir(), tmpdir) while os.path.exists(tmpdir_path): tmpdir = "gmount-%s" % (utils_misc.generate_random_string(6)) tmpdir_path = os.path.join(data_dir.get_tmp_dir(), tmpdir) ret = False try: try: os.mkdir(tmpdir_path) glusterfs_mount(sg_uri, tmpdir_path) mount_filename_path = os.path.join(tmpdir_path, filename_path[len(g_uri):]) if os.path.exists(mount_filename_path): ret = True except Exception as e: logging.error("Failed to mount gluster volume %s to" " mount dir %s: %s" % (sg_uri, tmpdir_path, e)) finally: if utils_misc.umount(sg_uri, tmpdir_path, "glusterfs", False, "fuse.glusterfs"): try: os.rmdir(tmpdir_path) except OSError: pass else: logging.warning("Unable to unmount tmp directory %s with glusterfs" " mount.", tmpdir_path) return ret
def create_bridge(): """ Create a bridge on host for test """ cmd_create_br = 'nmcli con add type bridge con-name %s ifname %s' con_name = 'con_' + utils_misc.generate_random_string(3) bridge_name = 'br_' + utils_misc.generate_random_string(3) process.run(cmd_create_br % (con_name, bridge_name), verbose=True) return con_name, bridge_name
def test_arbitrart_attributes(self): parallel = librarian.get('parallel')(virsh_instance = self.dummy_virsh) serial = librarian.get('serial')(virsh_instance = self.dummy_virsh) channel = librarian.get('channel')(virsh_instance = self.dummy_virsh) console = librarian.get('console')(virsh_instance = self.dummy_virsh) for chardev in (parallel, serial, channel, console): attribute1 = utils_misc.generate_random_string(10) value1 = utils_misc.generate_random_string(10) attribute2 = utils_misc.generate_random_string(10) value2 = utils_misc.generate_random_string(10) chardev.add_source(**{attribute1:value1, attribute2:value2}) chardev.add_target(**{attribute1:value1, attribute2:value2}) self.assertEqual(chardev.sources, chardev.targets)
def update_env(env): @utils_env.lock_safe def _update_env(env, key, value): env["changing_dict"][key] = value if "changing_dict" not in env: env["changing_dict"] = {} while True: key = "%s" % utils_misc.generate_random_string(length=10) value = "%s" % utils_misc.generate_random_string(length=10) _update_env(env, key, value) if termination_event.isSet(): break
def __init__(self, vm_name, params): self.name = vm_name self.params = params self.vm_type = self.params.get('vm_type') self.driver_type = self.params.get('driver_type') self.instance = ("%s-%s" % (time.strftime("%Y%m%d-%H%M%S"), utils_misc.generate_random_string(16)))
def __init__(self, test_params): """ Setup one or more device xml for a device based on TestParams instance """ if self.__class__.identifier is None: identifier = utils_misc.generate_random_string(4) self.__class__.identifier = identifier # how many of this type of device to make self.test_params = test_params # Copy params for this class into attributes cls_name = self.__class__.__name__ # Already have test-prefix stripped off for key, value in self.test_params.dev_params(cls_name).items(): # Any keys with _anything are not used by this class if key.count('_') > 0: logging.debug("Removing key: %s from params for class %s", test_params.test_prefix + key, cls_name) continue # Attempt to convert numbers try: setattr(self, key, int(value)) except ValueError: setattr(self, key, value) if self.count < 1: raise error.TestError("Configuration for class %s count must " "be specified and greater than zero") logging.info("Setting up %d %s device(s)", self.count, cls_name) # Setup each device_xml instance self._device_xml_list = [self.init_device(index) # test_params.dev_params() enforces count for index in xrange(0, self.count)]
def test_virt_tar_out(test, vm, params): """ 1) Write a tempfile to guest 2) Copy file to host with tar-out 3) Delete created file """ content = "This is file for test of virt-tar-out." path = params.get("vt_temp_file", "/tmp/test_virt_tar_out") file_dir = os.path.dirname(path) path_on_host = os.path.join(data_dir.get_tmp_dir(), "test_virt_tar_out.tar") vt = utils_test.libguestfs.VirtTools(vm, params) mountpoint = params.get("vt_mountpoint") if mountpoint is None: tmpdir = "gmount-%s" % (utils_misc.generate_random_string(6)) mountpoint = "/tmp/%s" % tmpdir if not os.path.exists(mountpoint): os.mkdir(mountpoint) writes, writeo = vt.write_file_with_guestmount(mountpoint, path, content, cleanup=False) if utils_misc.umount("", mountpoint, "") is False: logging.error("Umount vm's filesytem failed.") if writes is False: test.fail("Write file to mounted filesystem failed.") logging.info("Create %s successfully.", path) # Copy file to host tar_out_result = vt.tar_out(file_dir, path_on_host) logging.debug(tar_out_result) if tar_out_result.exit_status: test.fail("Tar out failed.") logging.info("Tar out successfully.") # uncompress file and check file in it. uc_result = process.run("cd %s && tar xf %s" % (file_dir, path_on_host), shell=True) logging.debug(uc_result) try: os.remove(path_on_host) except IOError as detail: test.fail(str(detail)) if uc_result.exit_status: test.fail("uncompress file on host failed.") logging.info("uncompress file on host successfully.") # Check file cat_result = process.run("cat %s" % path, ignore_status=True, shell=True) logging.debug(cat_result) try: os.remove(path) except IOError as detail: logging.error(detail) if cat_result.exit_status: test.fail("Cat file failed.") else: if not re.search(content, cat_result.stdout_text): test.fail("Catted file do not match.")
def get_backup_set(filename, backup_dir, action, good): """ Get all sources and destinations required for each backup. """ if not os.path.isdir(backup_dir): os.makedirs(backup_dir) basename = os.path.basename(filename) bkp_set = [] if action not in ('backup', 'restore'): logging.error("No backup sets for action: %s, state: %s", action, good) return bkp_set if good: src = filename dst = os.path.join(backup_dir, "%s.backup" % basename) if action == 'backup': bkp_set = [[src, dst]] elif action == 'restore': bkp_set = [[dst, src]] else: # We have to make 2 backups, one of the bad image, another one # of the good image src_bad = filename src_good = os.path.join(backup_dir, "%s.backup" % basename) hsh = utils_misc.generate_random_string(4) dst_bad = (os.path.join(backup_dir, "%s.bad.%s" % (basename, hsh))) dst_good = (os.path.join(backup_dir, "%s.good.%s" % (basename, hsh))) if action == 'backup': bkp_set = [[src_bad, dst_bad], [src_good, dst_good]] elif action == 'restore': bkp_set = [[src_good, src_bad]] return bkp_set
def __init__(self, test, params, env): self.test = test self.params = params self.env = env self.login_timeout = int(self.params.get("login_timeout", 360)) self.mig_timeout = float(self.params.get("mig_timeout", "3600")) self.mig_protocol = self.params.get("migration_protocol", "tcp") self.mig_cancel_delay = int(self.params.get("mig_cancel") == "yes") * 2 self.mig_exec_cmd_src = self.params.get("migration_exec_cmd_src") self.mig_exec_cmd_dst = self.params.get("migration_exec_cmd_dst") if self.mig_exec_cmd_src and "gzip" in self.mig_exec_cmd_src: self.mig_exec_file = self.params.get("migration_exec_file", "/var/tmp/exec") self.mig_exec_file += "-%s" % utils_misc.generate_random_string(8) self.mig_exec_cmd_src = self.mig_exec_cmd_src % self.mig_exec_file self.mig_exec_cmd_dst = self.mig_exec_cmd_dst % self.mig_exec_file self.offline = self.params.get("offline", "no") == "yes" self.check = self.params.get("vmstate_check", "no") == "yes" self.living_guest_os = self.params.get("migration_living_guest", "yes") == "yes" self.vm = self.env.get_vm(self.params["main_vm"]) self.test_command = self.params.get("migration_test_command") self.background_command = self.params.get("migration_bg_command") self.bg_check_command = self.params.get("migration_bg_check_command") self.guest_stress_test = self.params.get("guest_stress_test") self.ping_pong = self.params.get("ping_pong", 1) self.stress_stop_cmd = self.params.get("stress_stop_cmd")
def receiver(): """ Receive side """ logging.info("Starting receiver process on %s", receiver_addr) if vm_receiver: session = vm_receiver.wait_for_login(timeout=login_timeout) else: username = params.get("username", "") password = params.get("password", "") prompt = params.get("shell_prompt", "[\#\$]") linesep = eval("'%s'" % params.get("shell_linesep", r"\n")) client = params.get("shell_client") port = int(params.get("shell_port")) log_filename = ("session-%s-%s.log" % (receiver_addr, utils_misc.generate_random_string(4))) session = remote.remote_login(client, receiver_addr, port, username, password, prompt, linesep, log_filename, timeout) session.set_status_test_command("echo %errorlevel%") install_ntttcp(session) ntttcp_receiver_cmd = params.get("ntttcp_receiver_cmd") global _receiver_ready f = open(results_path + ".receiver", 'a') for b in buffers: utils_misc.wait_for(lambda: not _wait(), timeout) _receiver_ready = True rbuf = params.get("fixed_rbuf", b) cmd = ntttcp_receiver_cmd % ( session_num, receiver_addr, rbuf, buf_num) r = session.cmd_output(cmd, timeout=timeout, print_func=logging.debug) f.write("Send buffer size: %s\n%s\n%s" % (b, cmd, r)) f.close() session.close()
def run_smartcard_setup(test, params, env): """ Simple setup test to create certs on the client to be passed to VM's smartcard. @param test: QEMU test object. @param params: Dictionary with the test parameters. @param env: Dictionary with test environment. """ # Get necessary params cert_list = params.get("gencerts").split(",") cert_db = params.get("certdb") self_sign = params.get("self_sign") cert_trustargs = params.get("trustargs") logging.debug("Cert List:") for cert in cert_list: logging.debug(cert) logging.debug(cert_trustargs) logging.debug("CN=" + cert) logging.debug(cert_db) client_vm = env.get_vm(params["client_vm"]) client_vm.verify_alive() client_session = client_vm.wait_for_login( timeout=int(params.get("login_timeout", 360)), username="******", password="******") #generate a random string, used to create a random key for the certs randomstring = utils_misc.generate_random_string(2048) cmd = "echo '" + randomstring + "' > /tmp/randomtext.txt" output = client_session.cmd(cmd) #output2 = client_session.cmd("cat /tmp/randomtext.txt") utils_spice.wait_timeout(5) #for each cert listed by the test, create it on the client for cert in cert_list: cmd = "certutil " if self_sign: cmd += " -x " cmd += "-t '" + cert_trustargs + "' -S -s " + "'CN=" + cert cmd += "' -n '" + cert + "' -d " + cert_db cmd += " -z " + "/tmp/randomtext.txt" logging.debug(cmd) output = client_session.cmd(cmd) logging.debug("Cert Created: " + output) cmd = "certutil -L -d " + cert_db output = client_session.cmd(cmd) logging.info("Listing all certs on the client: " + output) #Verify that all the certs have been generated on the client for cert in cert_list: if not(cert in output): raise error.TestFail("Certificate %s not found" % cert) client_session.close()
def specify_fstab_entry(type, **kwargs): """ Specify entry in fstab file """ type_list = ['cdrom', 'uuid', 'label', 'virtio', 'sr0', 'invalid'] if type not in type_list: test.error('Not support %s in fstab' % type) session = kwargs['session'] # Specify cdrom device if type == 'cdrom': line = '/dev/cdrom /media/CDROM auto exec' if 'grub2' in utils_misc.get_bootloader_cfg(session): line += ',nofail' line += ' 0 0' logging.debug('fstab entry is "%s"', line) cmd = [ 'mkdir -p /media/CDROM', 'mount /dev/cdrom /media/CDROM', 'echo "%s" >> /etc/fstab' % line ] for i in range(len(cmd)): session.cmd(cmd[i]) elif type == 'sr0': line = params.get('fstab_content') session.cmd('echo "%s" >> /etc/fstab' % line) elif type == 'invalid': line = utils_misc.generate_random_string(6) session.cmd('echo "%s" >> /etc/fstab' % line) else: map = {'uuid': 'UUID', 'label': 'LABEL', 'virtio': '/vd'} logging.info(type) if session.cmd_status('cat /etc/fstab|grep %s' % map[type]): # Specify device by UUID if type == 'uuid': entry = session.cmd('blkid -s UUID|grep swap').strip().split() # Replace path for UUID origin = entry[0].strip(':') replace = entry[1].replace('"', '') # Specify virtio device elif type == 'virtio': entry = session.cmd('cat /etc/fstab|grep /boot').strip() # Get the ID (no matter what, usually UUID) origin = entry.split()[0] key = origin.split('=')[1] blkinfo = session.cmd('blkid|grep %s' % key).strip() # Replace with virtio disk path replace = blkinfo.split()[0].strip(':') # Specify device by label elif type == 'label': blk = make_label(session) entry = session.cmd('blkid|grep %s' % blk).strip() # Remove " from LABEL="****" replace = entry.split()[1].strip().replace('"', '') # Replace the original id/path with label origin = entry.split()[0].strip(':') cmd_fstab = "sed -i 's|%s|%s|' /etc/fstab" % (origin, replace) session.cmd(cmd_fstab) fstab = session.cmd_output('cat /etc/fstab') logging.debug('Content of /etc/fstab:\n%s', fstab)
def test_full_set(self): def what_func(propertea): return props[propertea] props = {} for propertea in self.VirtIface.__all_slots__: props[propertea] = utils_misc.generate_random_string(16) virtiface = self.VirtIface(props) self.loop_assert(virtiface, props.keys(), what_func)
def test_half_set(self): def what_func(propertea): return props[propertea] half_prop_end = (len(self.VirtIface.__all_slots__) / 2) + 1 props = {} for propertea in self.VirtIface.__all_slots__[0:half_prop_end]: props[propertea] = utils_misc.generate_random_string(16) virtiface = self.VirtIface(props) self.loop_assert(virtiface, props.keys(), what_func)
def run(test, params, env): """ live_snapshot_base test: 1). Boot up guest 2). Create a file on host and record md5 3). Copy the file to guest 3). Create live snapshot 4). Copy the file from guest,then check md5 :param test: Kvm test object :param params: Dictionary with the test parameters :param env: Dictionary with test environment. """ vm = env.get_vm(params["main_vm"]) vm.verify_alive() timeout = int(params.get("login_timeout", 3600)) session = vm.wait_for_login(timeout=timeout) dd_timeout = params.get("dd_timeoout", 600) copy_timeout = params.get("copy_timeoout", 600) base_file = storage.get_image_filename(params, data_dir.get_data_dir()) device = vm.get_block({"file": base_file}) snapshot_file = "images/%s" % params.get("snapshot_name") snapshot_file = utils_misc.get_path(data_dir.get_data_dir(), snapshot_file) snapshot_format = params.get("snapshot_format", "qcow2") tmp_name = utils_misc.generate_random_string(5) src = dst = "/tmp/%s" % tmp_name if params.get("os_type") != "linux": dst = "c:\\users\\public\\%s" % tmp_name try: error_context.context("create file on host, copy it to guest", logging.info) cmd = params.get("dd_cmd") % src process.system(cmd, timeout=dd_timeout, shell=True) md5 = crypto.hash_file(src, algorithm="md5") vm.copy_files_to(src, dst, timeout=copy_timeout) process.system("rm -f %s" % src) error_context.context("create live snapshot", logging.info) if vm.live_snapshot(base_file, snapshot_file, snapshot_format) != device: test.fail("Fail to create snapshot") backing_file = vm.monitor.get_backingfile(device) if backing_file != base_file: logging.error( "backing file: %s, base file: %s", backing_file, base_file) test.fail("Got incorrect backing file") error_context.context("copy file to host, check content not changed", logging.info) vm.copy_files_from(dst, src, timeout=copy_timeout) if md5 and (md5 != crypto.hash_file(src, algorithm="md5")): test.fail("diff md5 before/after create snapshot") session.cmd(params.get("alive_check_cmd", "dir")) finally: if session: session.close() process.system("rm -f %s %s" % (snapshot_file, src))
def run(test, params, env): """ Base test for vnc, mainly focus on handshaking during vnc connection setup. This case check following point: 1) VNC server support different rfb protocol version. Now it is 3.3, 3.7 and 3.8. 2) Connection could be setup with password enable. 3) Change and __com.redhat_set_password monitor command could work. This case will do following step: 1) Start VM with VNC password enable. 2) Handshaking after vnc password set by change. 3) Handshaking after vnc password set by __com.redhat_set_password. 4) Handshaking again after vnc password timeout. :param test: QEMU test object :param params: Dictionary with the test parameters :param env: Dictionary with test environmen. """ vm = env.get_vm(params["main_vm"]) vm.verify_alive() port = vm.get_vnc_port() default_cmd = "__com.redhat_set_password protocol=vnc," default_cmd += "password=%s,expiration=%s" change_passwd_cmd = params.get("change_passwd_cmd", default_cmd) rfb_version_list = params.get("rfb_version").strip().split() for rfb_version in rfb_version_list: error_context.base_context("Test with guest RFB version %s" % rfb_version) rand = random.SystemRandom() rand.seed() password = utils_misc.generate_random_string(rand.randint(1, 8)) logging.info("Set VNC password to: %s", password) timeout = rand.randint(10, 100) logging.info("VNC password timeout is: %s", timeout) vm.monitor.send_args_cmd(change_passwd_cmd % (password, timeout)) error_context.context("Connect to VNC server after setting password" " to '%s'" % password) vnc = VNC(port=port, rfb_version=rfb_version) status = vnc.hand_shake(password) vnc.initialize() vnc.close() if not status: test.fail("VNC Authentication failed.") logging.info("VNC Authentication pass") logging.info("Waiting for vnc password timeout.") time.sleep(timeout + 5) error_context.context("Connect to VNC server after password expires") vnc = VNC(port=port, rfb_version=rfb_version) status = vnc.hand_shake(password) vnc.close() if status: # Should not handshake succeffully. test.fail("VNC connected with Timeout password, The" " cmd of setting expire time doesn't work.")
def run(test, params, env): """ KVM restore from file-test: 1) Pause VM 2) Save VM to file 3) Restore VM from file, and measure the time it takes 4) Remove VM restoration file 5) Check VM :param test: QEMU test object :param params: Dictionary with the test parameters :param env: Dictionary with test environment """ vm = env.get_vm(params["main_vm"]) vm.verify_alive() timeout = int(params.get("login_timeout", 360)) expect_time = int(params.get("expect_restore_time", 25)) session = vm.wait_for_login(timeout=timeout) save_file = params.get("save_file", os.path.join("/tmp", utils_misc.generate_random_string(8))) try: error.context("Pause VM", logging.info) vm.pause() error.context("Save VM to file", logging.info) vm.save_to_file(save_file) error.context("Restore VM from file", logging.info) time.sleep(10) utils_memory.drop_caches() vm.restore_from_file(save_file) session = vm.wait_for_login(timeout=timeout) restore_time = utils_misc.monotonic_time() - vm.start_monotonic_time test.write_test_keyval({'result': "%ss" % restore_time}) logging.info("Restore time: %ss" % restore_time) finally: try: error.context("Remove VM restoration file", logging.info) os.remove(save_file) error.context("Check VM", logging.info) vm.verify_alive() vm.wait_for_login(timeout=timeout) except Exception: logging.warning("Unable to restore VM, restoring from image") params["restore_image_after_testing"] = "yes" if restore_time > expect_time: raise error.TestFail( "Guest restoration took too long: %ss" % restore_time) session.close()
def setup(self, test, params, env): self.br0_name = "br0-%s" % (utils_misc.generate_random_string(3)) while self.br0_name in utils_misc.get_net_if(): self.br0_name = "br0-%s" % (utils_misc.generate_random_string(3)) self.br0_ip = params.get("bridge_ip", "192.168.250.1") self.ovs = None error.context("Try to log into guest.") self.vms = [env.get_vm(vm) for vm in params.get("vms").split()] for vm in self.vms: vm.verify_alive() error.context("Start OpenVSwitch.") self.ovs = openvswitch.OpenVSwitchSystem() self.ovs.init_system() self.ovs.check() error.context("Add new bridge %s." % (self.br0_name)) self.ovs.add_br(self.br0_name) utils_misc.set_net_if_ip(self.br0_name, self.br0_ip) utils_misc.bring_up_ifname(self.br0_name) self.dns_pidf = (utils_misc.check_add_dnsmasq_to_br(self.br0_name, test.tmpdir)) error.context("Add new ports from vms %s to bridge %s." % (self.vms, self.br0_name)) for vm in self.vms: utils_misc.change_iface_bridge(vm.virtnet[1], self.br0_name, self.ovs) logging.debug(self.ovs.status()) self.host = ovs_utils.Machine(src=test.srcdir) self.mvms = [ovs_utils.Machine(vm) for vm in self.vms] self.machines = [self.host] + self.mvms #ForAllP(self.mvms).cmd("dhclinet") time.sleep(5) utils_misc.ForAllP(self.machines).fill_addrs()
def nonexist_snapshot_file(self): """ Generate a non-existed path of snapshot file. """ error_context.context("Generate a non-existed path of" " snapshot file", logging.info) tmp_name = utils_misc.generate_random_string(5) dst = os.path.join(data_dir.get_tmp_dir(), tmp_name) path = os.path.join(dst, self.snapshot_file) if not os.path.exists(path): return path raise exceptions.TestFail("Path %s is existed." % path)
def test_apendex_set(self): """ Verify container ignores unknown key names """ def what_func(propertea): return props[propertea] props = {} for propertea in self.VirtIface.__all_slots__: props[propertea] = utils_misc.generate_random_string(16) more_props = {} for _ in xrange(0, 16): key = utils_misc.generate_random_string(16) value = utils_misc.generate_random_string(16) more_props[key] = value # Keep separated for testing apendex_set = {} apendex_set.update(props) apendex_set.update(more_props) virtiface = self.VirtIface(apendex_set) # str(props) guarantees apendex set wasn't incorporated self.loop_assert(virtiface, props.keys(), what_func)
def _build_cmd(cmd, args=None, q_id=None): """ Format QMP command from cmd and args :param cmd: Command ('device_add', ...) :param q_id: queue id; True = generate random, None = None, str = use str """ obj = {"execute": cmd} if args is not None: obj["arguments"] = args if q_id is True: obj["id"] = utils_misc.generate_random_string(8) elif q_id is not None: obj["id"] = q_id return obj
def _action_before_fsfreeze(self, *args): copy_timeout = int(self.params.get("copy_timeoout", 600)) file_size = int(self.params.get("file_size", "500")) tmp_name = utils_misc.generate_random_string(5) self.host_path = self.guest_path = "/tmp/%s" % tmp_name if self.params.get("os_type") != "linux": self.guest_path = r"c:\%s" % tmp_name error.context("Create a file in host.") utils.run("dd if=/dev/urandom of=%s bs=1M count=%s" % (self.host_path, file_size)) self.orig_hash = utils.hash_file(self.host_path) error.context("Transfer file from %s to %s" % (self.host_path, self.guest_path), logging.info) self.bg = utils.InterruptedThread(self.vm.copy_files_to, (self.host_path, self.guest_path), dict(verbose=True, timeout=copy_timeout)) self.bg.start()
def test_virt_copy_out(vm, params): """ 1) Write a tempfile to guest 2) Copy file to host with copy-out 3) Delete created file 4) Check file on host """ content = "This is file for test of virt-copy-out." path = params.get("vt_temp_file", "/tmp/test_virt_copy_out") path_dir = os.path.dirname(path) vt = utils_test.libguestfs.VirtTools(vm, params) mountpoint = params.get("vt_mountpoint") if mountpoint is None: tmpdir = "gmount-%s" % (utils_misc.generate_random_string(6)) mountpoint = "/tmp/%s" % tmpdir if not os.path.exists(mountpoint): os.mkdir(mountpoint) writes, writeo = vt.write_file_with_guestmount(mountpoint, path, content, cleanup=False) if utils_misc.umount("", mountpoint, "") is False: logging.error("Umount vm's filesytem failed.") if writes is False: raise error.TestFail("Write file to mounted filesystem failed.") logging.info("Create %s successfully.", path) # Copy file to host copy_out_result = vt.copy_out(path, path_dir) logging.debug(copy_out_result) if copy_out_result.exit_status: raise error.TestFail("Copy out failed.") logging.info("Copy out successfully.") # Check file cat_result = utils.run("cat %s" % path, ignore_status=True) logging.debug(cat_result.stdout) try: os.remove(path) except IOError, detail: logging.error(detail)
def __init__(self, test, params, image_name, blkdebug_cfg="", prompt=r"qemu-io>\s*$", log_filename=None, io_options="", log_func=None): self.type = "" if log_filename: log_filename += "-" + utils_misc.generate_random_string(4) self.output_func = utils_misc.log_line self.output_params = (log_filename,) else: self.output_func = None self.output_params = () self.output_prefix = "" self.prompt = prompt self.blkdebug_cfg = blkdebug_cfg self.qemu_io_cmd = utils_misc.get_qemu_io_binary(params) self.io_options = io_options self.run_command = False self.image_name = image_name self.blkdebug_cfg = blkdebug_cfg self.log_func = log_func
def run(test, params, env): """ Test Step 1. boot up two virtual machine 2. For linux guest,Transfer data: host <--> guest1 <--> guest2 <-->host via ipv6 For windows guest,Transfer data: host <--> guest1&guest2 via ipv6 3. after data transfer, check data have no change Params: :param test: QEMU test object :param params: Dictionary with the test parameters :param env: Dictionary with test environment. """ timeout = int(params.get("login_timeout", '360')) client = params.get("file_transfer_client") port = params.get("file_transfer_port") password = params.get("password") username = params.get("username") tmp_dir = params["tmp_dir"] filesize = int(params.get("filesize", '4096')) dd_cmd = params["dd_cmd"] file_trans_timeout = int(params.get("file_trans_timeout", '1200')) file_md5_check_timeout = int(params.get("file_md5_check_timeout", '600')) def get_file_md5sum(file_name, session, timeout): """ Get file md5sum from guest. """ logging.info("Get md5sum of the file:'%s'" % file_name) s, o = session.cmd_status_output("md5sum %s" % file_name, timeout=timeout) if s != 0: test.error("Get file md5sum failed as %s" % o) return re.findall(r"\w{32}", o)[0] sessions = {} addresses = {} inet_name = {} vms = [] error_context.context("Boot vms for test", logging.info) for vm_name in params.get("vms", "vm1 vm2").split(): vms.append(env.get_vm(vm_name)) # config ipv6 address host and guest. host_ifname = params.get("netdst") host_address = utils_net.get_host_ip_address(params, ip_ver="ipv6", linklocal=True) error_context.context("Get ipv6 address of host: %s" % host_address, logging.info) for vm in vms: vm.verify_alive() sessions[vm] = vm.wait_for_login(timeout=timeout) if params.get("os_type") == "linux": inet_name[vm] = utils_net.get_linux_ifname(sessions[vm], vm.get_mac_address()) addresses[vm] = utils_net.get_guest_ip_addr(sessions[vm], vm.get_mac_address(), params.get("os_type"), ip_version="ipv6", linklocal=True) error_context.context( "Get ipv6 address of %s: %s" % (vm.name, addresses[vm]), logging.info) # prepare test data guest_path = (tmp_dir + "src-%s" % utils_misc.generate_random_string(8)) dest_path = (tmp_dir + "dst-%s" % utils_misc.generate_random_string(8)) host_path = os.path.join(test.tmpdir, "tmp-%s" % utils_misc.generate_random_string(8)) logging.info("Test setup: Creating %dMB file on host", filesize) process.run(dd_cmd % (host_path, filesize), shell=True) try: src_md5 = (crypto.hash_file(host_path, algorithm="md5")) error_context.context("md5 value of data from src: %s" % src_md5, logging.info) # transfer data for vm in vms: error_context.context("Transfer data from host to %s" % vm.name, logging.info) remote.copy_files_to(addresses[vm], client, username, password, port, host_path, guest_path, timeout=file_trans_timeout, interface=host_ifname) dst_md5 = get_file_md5sum(guest_path, sessions[vm], timeout=file_md5_check_timeout) error_context.context( "md5 value of data in %s: %s" % (vm.name, dst_md5), logging.info) if dst_md5 != src_md5: test.fail("File changed after transfer host -> %s" % vm.name) if params.get("os_type") == "linux": for vm_src in addresses: for vm_dst in addresses: if vm_src != vm_dst: error_context.context( "Transferring data from %s to %s" % (vm_src.name, vm_dst.name), logging.info) remote.scp_between_remotes(addresses[vm_src], addresses[vm_dst], port, password, password, username, username, guest_path, dest_path, timeout=file_trans_timeout, src_inter=host_ifname, dst_inter=inet_name[vm_src]) dst_md5 = get_file_md5sum( dest_path, sessions[vm_dst], timeout=file_md5_check_timeout) error_context.context( "md5 value of data in %s: %s" % (vm.name, dst_md5), logging.info) if dst_md5 != src_md5: test.fail("File changed transfer %s -> %s" % (vm_src.name, vm_dst.name)) for vm in vms: error_context.context("Transfer data from %s to host" % vm.name, logging.info) remote.copy_files_from(addresses[vm], client, username, password, port, guest_path, host_path, timeout=file_trans_timeout, interface=host_ifname) error_context.context("Check whether the file changed after trans", logging.info) dst_md5 = (crypto.hash_file(host_path, algorithm="md5")) error_context.context( "md5 value of data after copying to host: %s" % dst_md5, logging.info) if dst_md5 != src_md5: test.fail("File changed after transfer (md5sum mismatch)") process.system_output("rm -rf %s" % host_path, timeout=timeout) finally: process.system("rm -rf %s" % host_path, timeout=timeout, ignore_status=True) for vm in vms: if params.get("os_type") == "linux": sessions[vm].cmd("rm -rf %s %s || true" % (guest_path, dest_path), timeout=timeout, ignore_all_errors=True) else: sessions[vm].cmd("del /f %s" % guest_path, timeout=timeout, ignore_all_errors=True) sessions[vm].close()
def run(test, params, env): """ KVM nfs performance test: 1) boot guest over virtio driver. 2) mount nfs server in guest with tcp protocol. 3) test write performance in guest using dd commands. 4) test read performance in guest using dd commands. Note: This test is used for performance benchmark test, not for the functional test usage. The result of this test depends on the regression.py tool, though you can run it during function testing, you may not get any possible error report from this script directly. :param test: kvm test object :param params: Dictionary with the test parameters :param env: Dictionary with test environment """ def _do_clean_up(func, *args): try: if args: func(*args) else: func() except Exception as e: logging.warn( "Failed to execute function '%s'." " error message:\n%s", func.__name__, e) def _clean_up(step_cnt): error_context.context("Clean up", logging.info) if step_cnt >= STEP_5: # remove test file. cmd = "rm -f %s" % " ".join(test_file_list) _do_clean_up(session.cmd, cmd) if step_cnt >= STEP_4: # umount nfs partition. cmd = "umount %s" % mnt_point _do_clean_up(session.cmd, cmd) if step_cnt >= STEP_3: # remove mount ponit directory. cmd = "rm -rf %s" % mnt_point _do_clean_up(session.cmd, cmd) if step_cnt >= STEP_2: # close result file. _do_clean_up(result_file.close) if step_cnt >= STEP_1: # close session. _do_clean_up(session.close) def _do_write_test(blk_size, test_file): # Clean up caches session.cmd("echo 3 >/proc/sys/vm/drop_caches") error_context.context( "test %s size block write performance in guest" " using dd commands" % blk_size, logging.info) dd_cmd = "dd" dd_cmd += " if=/dev/zero" dd_cmd += " of=%s" % test_file dd_cmd += " bs=%s" % blk_size dd_cmd += " oflag=direct" dd_cmd += " count=10000" try: out = session.cmd_output(dd_cmd, timeout=test_timeout) except Exception: _clean_up(STEP_4) raise return out def _do_read_test(blk_size, test_file): # Clean up caches session.cmd("echo 3 >/proc/sys/vm/drop_caches") error_context.context( "test %s size block read performance in guest" " using dd commands" % blk_size, logging.info) dd_cmd = "dd" dd_cmd += " if=%s" % test_file dd_cmd += " of=/dev/null" dd_cmd += " bs=%s" % blk_size dd_cmd += " iflag=direct" try: out = session.cmd_output(dd_cmd, timeout=test_timeout) except Exception: _clean_up(STEP_5) raise # After STEP 6 return out if not hasattr(test, "write_perf_keyval"): test.cancel("There is no 'write_perf_keyval' method in" " test object, skip this test") error_context.context("boot guest over virtio driver", logging.info) vm = env.get_vm(params["main_vm"]) vm.verify_alive() timeout = int(params.get("login_timeout", 360)) test_timeout = int(params["test_timeout"]) session = vm.wait_for_login(timeout=timeout) guest_ver = session.cmd_output("uname -r").strip() host_ver = os.uname()[2] kvm_userspace_ver_cmd = params.get("kvm_userspace_ver_cmd", "") if kvm_userspace_ver_cmd: try: cmd_result = process.run(kvm_userspace_ver_cmd, shell=True) qemu_version = cmd_result.stdout.strip() except process.CmdError: qemu_version = "Unknown" else: qemu_path = utils_misc.get_qemu_binary(params) version_line = process.system_output("%s -help | head -n 1" % qemu_path, shell=True) matches = re.findall("version .*?,", version_line, re.I) if matches: qemu_version = " ".join(matches[0].split()[1:]).strip(",") else: qemu_version = "Unknown" # After STEP 1 try: result_name = params.get("result_name", "nfs-perf.RHS") result_file_path = utils_misc.get_path(test.resultsdir, result_name) result_file = open(result_file_path, 'w') except Exception: _clean_up(STEP_1) raise # After STEP 2 error_context.context("mount nfs server in guest with tcp protocol", logging.info) nfs_server = params.get("nfs_server") nfs_path = params.get("nfs_path") mnt_option = params.get("mnt_option") mnt_point = "/tmp/nfs_perf_%s" % utils_misc.generate_random_string(4) test_file_prefix = os.path.join( mnt_point, "test_%si_" % utils_misc.generate_random_string(4)) blk_size_list = params.get("blk_size_list", "8k").split() test_file_list = list(map(lambda x: test_file_prefix + x, blk_size_list)) if (not nfs_server) or (not nfs_path) or (not mnt_point): _clean_up(STEP_2) test.error("Missing configuration for nfs partition." " Check your config files") try: session.cmd("mkdir -p %s" % mnt_point) except Exception: _clean_up(STEP_2) raise # After STEP 3 # Prepare nfs partition. mnt_cmd = "mount" mnt_cmd += " -t nfs" if mnt_option: mnt_cmd += " -o %s" % mnt_option mnt_cmd += " %s:%s" % (nfs_server, nfs_path) mnt_cmd_out = mnt_cmd + " /tmp/***_****_****" mnt_cmd += " %s" % mnt_point try: session.cmd(mnt_cmd) except Exception: _clean_up(STEP_3) raise # After STEP 4 # Record mount command in result file. try: result_file.write("### kvm-userspace-ver : %s\n" % qemu_version) result_file.write("### kvm_version : %s\n" % host_ver) result_file.write("### guest-kernel-ver : %s\n" % guest_ver) result_file.write("### %s\n" % mnt_cmd_out) result_file.write("Category:ALL\n") except (IOError, ValueError) as e: logging.error("Failed to write to result file," " error message:\n%s", e) result_list = ["%s|%016s|%016s" % ("blk_size", "Write", "Read")] speed_pattern = r"(\d+ bytes).*?([\d\.]+ s).*?([\d\.]+ [KkMmGgTt])B/s" try: prefix = "nfs" for blk_size in blk_size_list: prefix += "--%s" % blk_size test_file = test_file_list[blk_size_list.index(blk_size)] result = "%08s|" % blk_size[:-1] # Get write test result. out = _do_write_test(blk_size, test_file) tmp_list = re.findall(speed_pattern, out) if not tmp_list: _clean_up(STEP_5) test.error("Could not get correct write result." " dd cmd output:\n%s" % out) _, _, speed = tmp_list[0] speed = utils_misc.normalize_data_size(speed) result += "%016s|" % speed test.write_perf_keyval({"%s--%s" % (prefix, "write"): speed}) # Get read test result. out = _do_read_test(blk_size, test_file) tmp_list = re.findall(speed_pattern, out) if not tmp_list: _clean_up(STEP_6) test.error("Could not get correct read result." " dd cmd output:\n%s" % out) _, _, speed = tmp_list[0] speed = utils_misc.normalize_data_size(speed) result += "%016s" % speed test.write_perf_keyval({"%s--%s" % (prefix, "read"): speed}) # Append result into result list. result_list.append(result) finally: try: result_file.write("\n".join(result_list)) except (IOError, ValueError) as e: logging.error( "Failed to write to result file," " error message:\n%s", e) _clean_up(STEP_6)
def run(test, params, env): """ Convert specific esx guest """ for v in list(params.values()): if "V2V_EXAMPLE" in v: test.cancel("Please set real value for %s" % v) if utils_v2v.V2V_EXEC is None: raise ValueError('Missing command: virt-v2v') version_requried = params.get("version_requried") vpx_hostname = params.get('vpx_hostname') vpx_passwd = params.get("vpx_password") esxi_host = esx_ip = params.get('esx_hostname') vpx_dc = params.get('vpx_dc') vm_name = params.get('main_vm') output_mode = params.get('output_mode') pool_name = params.get('pool_name', 'v2v_test') pool_type = params.get('pool_type', 'dir') pool_target = params.get('pool_target_path', 'v2v_pool') pvt = libvirt.PoolVolumeTest(test, params) v2v_timeout = int(params.get('v2v_timeout', 1200)) v2v_cmd_timeout = int(params.get('v2v_cmd_timeout', 18000)) v2v_opts = '-v -x' if params.get('v2v_debug', 'on') in ['on', 'force_on' ] else '' if params.get("v2v_opts"): # Add a blank by force v2v_opts += ' ' + params.get("v2v_opts") status_error = 'yes' == params.get('status_error', 'no') address_cache = env.get('address_cache') checkpoint = params.get('checkpoint', '') skip_vm_check = params.get('skip_vm_check', 'no') skip_reason = params.get('skip_reason') error_list = [] remote_host = vpx_hostname # For VDDK input_transport = params.get("input_transport") vddk_libdir = params.get('vddk_libdir') # nfs mount source vddk_libdir_src = params.get('vddk_libdir_src') vddk_thumbprint = params.get('vddk_thumbprint') src_uri_type = params.get('src_uri_type') esxi_password = params.get('esxi_password') json_disk_pattern = params.get('json_disk_pattern') # For construct rhv-upload option in v2v cmd output_method = params.get("output_method") rhv_upload_opts = params.get("rhv_upload_opts") storage_name = params.get('storage_name') os_pool = os_storage = params.get('output_storage', 'default') # for get ca.crt file from ovirt engine rhv_passwd = params.get("rhv_upload_passwd") rhv_passwd_file = params.get("rhv_upload_passwd_file") ovirt_engine_passwd = params.get("ovirt_engine_password") ovirt_hostname = params.get("ovirt_engine_url").split( '/')[2] if params.get("ovirt_engine_url") else None ovirt_ca_file_path = params.get("ovirt_ca_file_path") local_ca_file_path = params.get("local_ca_file_path") os_version = params.get('os_version') os_type = params.get('os_type') virtio_win_path = params.get('virtio_win_path') # qemu-guest-agent path in virtio-win or rhv-guest-tools-iso qa_path = params.get('qa_path') # download url of qemu-guest-agent qa_url = params.get('qa_url') v2v_sasl = None # default values for v2v_cmd auto_clean = True cmd_only = False cmd_has_ip = 'yes' == params.get('cmd_has_ip', 'yes') interaction_run = 'yes' == params.get('interaction_run', 'no') def log_fail(msg): """ Log error and update error list """ logging.error(msg) error_list.append(msg) def check_device_exist(check, virsh_session_id): """ Check if device exist after convertion """ xml = virsh.dumpxml(vm_name, session_id=virsh_session_id).stdout if check == 'cdrom': if "device='cdrom'" not in xml: log_fail('CDROM no longer exists') def check_vmtools(vmcheck, check): """ Check whether vmware tools packages have been removed, or vmware-tools service has stopped :param vmcheck: VMCheck object for vm checking :param check: Checkpoint of different cases :return: None """ if check == 'vmtools': logging.info('Check if packages been removed') pkgs = vmcheck.session.cmd('rpm -qa').strip() removed_pkgs = params.get('removed_pkgs').strip().split(',') if not removed_pkgs: test.error('Missing param "removed_pkgs"') for pkg in removed_pkgs: if pkg in pkgs: log_fail('Package "%s" not removed' % pkg) elif check == 'vmtools_service': logging.info('Check if service stopped') vmtools_service = params.get('service_name') status = utils_misc.get_guest_service_status( vmcheck.session, vmtools_service) logging.info('Service %s status: %s', vmtools_service, status) if status != 'inactive': log_fail('Service "%s" is not stopped' % vmtools_service) def check_modprobe(vmcheck): """ Check whether content of /etc/modprobe.conf meets expectation """ content = vmcheck.session.cmd('cat /etc/modprobe.conf').strip() logging.debug(content) cfg_content = params.get('cfg_content') if not cfg_content: test.error('Missing content for search') logging.info('Search "%s" in /etc/modprobe.conf', cfg_content) pattern = r'\s+'.join(cfg_content.split()) if not re.search(pattern, content): log_fail('Not found "%s"' % cfg_content) def check_device_map(vmcheck): """ Check if the content of device.map meets expectation. """ logging.info(vmcheck.session.cmd('fdisk -l').strip()) device_map = params.get('device_map_path') content = vmcheck.session.cmd('cat %s' % device_map) logging.debug('Content of device.map:\n%s', content) logging.info('Found device: %d', content.count('/dev/')) logging.info('Found virtio device: %d', content.count('/dev/vd')) if content.count('/dev/') != content.count('/dev/vd'): log_fail('Content of device.map not correct') else: logging.info('device.map has been remaped to "/dev/vd*"') def check_resume_swap(vmcheck): """ Check the content of grub files meet expectation. """ if os_version == 'rhel7': chkfiles = [ '/etc/default/grub', '/boot/grub2/grub.cfg', '/etc/grub2.cfg' ] if os_version == 'rhel6': chkfiles = ['/boot/grub/grub.conf', '/etc/grub.conf'] for file_i in chkfiles: status, content = vmcheck.run_cmd('cat %s' % file_i) if status != 0: log_fail('%s does not exist' % file_i) resume_dev_count = content.count('resume=/dev/') if resume_dev_count == 0 or resume_dev_count != content.count( 'resume=/dev/vd'): reason = 'Maybe the VM\'s swap pariton is lvm' log_fail('Content of %s is not correct or %s' % (file_i, reason)) content = vmcheck.session.cmd('cat /proc/cmdline') logging.debug('Content of /proc/cmdline:\n%s', content) if 'resume=/dev/vd' not in content: log_fail('Content of /proc/cmdline is not correct') def check_rhev_file_exist(vmcheck): """ Check if rhev files exist """ file_path = { 'rhev-apt.exe': r'C:\rhev-apt.exe', 'rhsrvany.exe': r'"C:\Program Files\Guestfs\Firstboot\rhsrvany.exe"' } for key in file_path: status = vmcheck.session.cmd_status('dir %s' % file_path[key]) if status == 0: logging.info('%s exists' % key) else: log_fail('%s does not exist after convert to rhv' % key) def check_file_architecture(vmcheck): """ Check the 3rd party module info :param vmcheck: VMCheck object for vm checking """ content = vmcheck.session.cmd('uname -r').strip() status = vmcheck.session.cmd_status( 'rpm -qf /lib/modules/%s/fileaccess/fileaccess_mod.ko ' % content) if status == 0: log_fail('3rd party module info is not correct') else: logging.info( 'file /lib/modules/%s/fileaccess/fileaccess_mod.ko is not owned by any package' % content) def check_windows_ogac(vmcheck): """ Check qemu-guest-agent service in VM :param vmcheck: VMCheck object for vm checking """ try: res = utils_misc.wait_for(lambda: re.search( 'running', vmcheck.get_service_info('qemu-ga'), re.I), 300, step=30) except ShellProcessTerminatedError: # Windows guest may reboot after installing qemu-ga service logging.debug('Windows guest is rebooting') if vmcheck.session: vmcheck.session.close() vmcheck.session = None vmcheck.create_session() res = utils_misc.wait_for(lambda: re.search( 'running', vmcheck.get_service_info('qemu-ga'), re.I), 300, step=30) if not res: test.fail('Not found running qemu-ga service') def check_linux_ogac(vmcheck): """ Check qemu-guest-agent service in VM :param vmcheck: VMCheck object for vm checking """ def get_pkgs(pkg_path): """ Get all qemu-guest-agent pkgs """ pkgs = [] for _, _, files in os.walk(pkg_path): for file_name in files: pkgs.append(file_name) return pkgs def get_pkg_version_vm(): """ Get qemu-guest-agent version in VM """ vender = vmcheck.get_vm_os_vendor() if vender in ['Ubuntu', 'Debian']: cmd = 'dpkg -l qemu-guest-agent' else: cmd = 'rpm -q qemu-guest-agent' _, output = vmcheck.run_cmd(cmd) pkg_ver_ptn = [ r'qemu-guest-agent +[0-9]+:(.*?dfsg.*?) +', r'qemu-guest-agent-(.*?)\.x86_64' ] for ptn in pkg_ver_ptn: if re.search(ptn, output): return re.search(ptn, output).group(1) return '' if os.path.isfile(os.getenv('VIRTIO_WIN')): mount_point = utils_v2v.v2v_mount(os.getenv('VIRTIO_WIN'), 'rhv_tools_setup_iso', fstype='iso9660') export_path = params['tmp_mount_point'] = mount_point else: export_path = os.getenv('VIRTIO_WIN') qemu_guest_agent_dir = os.path.join(export_path, qa_path) all_pkgs = get_pkgs(qemu_guest_agent_dir) logging.debug('The installing qemu-guest-agent is: %s' % all_pkgs) vm_pkg_ver = get_pkg_version_vm() logging.debug('qemu-guest-agent verion in vm: %s' % vm_pkg_ver) # Check the service status of qemu-guest-agent in VM status_ptn = r'Active: active \(running\)|qemu-ga \(pid +[0-9]+\) is running' cmd = 'service qemu-ga status;systemctl status qemu-guest-agent' _, output = vmcheck.run_cmd(cmd) if not re.search(status_ptn, output): log_fail('qemu-guest-agent service exception') def check_ubuntools(vmcheck): """ Check open-vm-tools, ubuntu-server in VM :param vmcheck: VMCheck object for vm checking """ logging.info('Check if open-vm-tools service stopped') status = utils_misc.get_guest_service_status(vmcheck.session, 'open-vm-tools') logging.info('Service open-vm-tools status: %s', status) if status != 'inactive': log_fail('Service open-vm-tools is not stopped') else: logging.info('Check if the ubuntu-server exist') content = vmcheck.session.cmd('dpkg -s ubuntu-server') if 'install ok installed' in content: logging.info('ubuntu-server has not been removed.') else: log_fail('ubuntu-server has been removed') def global_pem_setup(f_pem): """ Setup global rhv server ca :param f_pem: ca file path """ ca_anchors_dir = '/etc/pki/ca-trust/source/anchors' shutil.copy(f_pem, ca_anchors_dir) process.run('update-ca-trust extract', shell=True) os.unlink(os.path.join(ca_anchors_dir, os.path.basename(f_pem))) def global_pem_cleanup(): """ Cleanup global rhv server ca """ process.run('update-ca-trust extract', shell=True) def find_net(bridge_name): """ Find which network use specified bridge :param bridge_name: bridge name you want to find """ net_list = virsh.net_state_dict(only_names=True) net_name = '' if len(net_list): for net in net_list: net_info = virsh.net_info(net).stdout.strip() search = re.search(r'Bridge:\s+(\S+)', net_info) if search: if bridge_name == search.group(1): net_name = net else: logging.info('Conversion server has no network') return net_name def destroy_net(net_name): """ destroy network in conversion server """ if virsh.net_state_dict()[net_name]['active']: logging.info("Remove network %s in conversion server", net_name) virsh.net_destroy(net_name) if virsh.net_state_dict()[net_name]['autostart']: virsh.net_autostart(net_name, "--disable") output = virsh.net_list("--all").stdout.strip() logging.info(output) def start_net(net_name): """ start network in conversion server """ logging.info("Recover network %s in conversion server", net_name) virsh.net_autostart(net_name) if not virsh.net_state_dict()[net_name]['active']: virsh.net_start(net_name) output = virsh.net_list("--all").stdout.strip() logging.info(output) def check_result(result, status_error): """ Check virt-v2v command result """ def vm_check(status_error): """ Checking the VM """ if status_error: return if output_mode == 'json' and not check_json_output(params): test.fail('check json output failed') if output_mode == 'local' and not check_local_output(params): test.fail('check local output failed') if output_mode in ['null', 'json', 'local']: return # vmchecker must be put before skip_vm_check in order to clean up # the VM. vmchecker = VMChecker(test, params, env) params['vmchecker'] = vmchecker if skip_vm_check == 'yes': logging.info('Skip checking vm after conversion: %s' % skip_reason) return if output_mode == 'rhev': if not utils_v2v.import_vm_to_ovirt( params, address_cache, timeout=v2v_timeout): test.fail('Import VM failed') elif output_mode == 'libvirt': virsh.start(vm_name, debug=True) # Check guest following the checkpoint document after convertion logging.info('Checking common checkpoints for v2v') if checkpoint == 'ogac': # windows guests will reboot at any time after qemu-ga is # installed. The process cannot be controled. In order to # don't break vmchecker.run() process, It's better to put # check_windows_ogac before vmchecker.run(). Because in # check_windows_ogac, it waits until rebooting completes. vmchecker.checker.create_session() if os_type == 'windows': check_windows_ogac(vmchecker.checker) else: check_linux_ogac(vmchecker.checker) ret = vmchecker.run() if len(ret) == 0: logging.info("All common checkpoints passed") # Check specific checkpoints if checkpoint == 'cdrom': virsh_session = utils_sasl.VirshSessionSASL(params) virsh_session_id = virsh_session.get_id() check_device_exist('cdrom', virsh_session_id) virsh_session.close() if checkpoint.startswith('vmtools'): check_vmtools(vmchecker.checker, checkpoint) if checkpoint == 'modprobe': check_modprobe(vmchecker.checker) if checkpoint == 'device_map': check_device_map(vmchecker.checker) if checkpoint == 'resume_swap': check_resume_swap(vmchecker.checker) if checkpoint == 'rhev_file': check_rhev_file_exist(vmchecker.checker) if checkpoint == 'file_architecture': check_file_architecture(vmchecker.checker) if checkpoint == 'ubuntu_tools': check_ubuntools(vmchecker.checker) if checkpoint == 'without_default_net': if virsh.net_state_dict()[net_name]['active']: log_fail("Bridge virbr0 already started during conversion") # Merge 2 error lists error_list.extend(vmchecker.errors) utils_v2v.check_exit_status(result, status_error) output = result.stdout_text + result.stderr_text # VM or local output checking vm_check(status_error) # Check log size decrease option if checkpoint == 'log decrease': nbdkit_option = r'nbdkit\.backend\.datapath=0' if not re.search(nbdkit_option, output): test.fail("checkpoint '%s' failed" % checkpoint) # Log checking log_check = utils_v2v.check_log(params, output) if log_check: log_fail(log_check) if len(error_list): test.fail('%d checkpoints failed: %s' % (len(error_list), error_list)) try: if version_requried and not utils_v2v.multiple_versions_compare( version_requried): test.cancel("Testing requries version: %s" % version_requried) v2v_params = { 'hostname': remote_host, 'hypervisor': 'esx', 'main_vm': vm_name, 'vpx_dc': vpx_dc, 'esx_ip': esx_ip, 'new_name': vm_name + utils_misc.generate_random_string(4), 'v2v_opts': v2v_opts, 'input_mode': 'libvirt', 'os_storage': os_storage, 'os_pool': os_pool, 'network': params.get('network'), 'bridge': params.get('bridge'), 'target': params.get('target'), 'password': vpx_passwd if src_uri_type != 'esx' else esxi_password, 'input_transport': input_transport, 'vcenter_host': vpx_hostname, 'vcenter_password': vpx_passwd, 'vddk_thumbprint': vddk_thumbprint, 'vddk_libdir': vddk_libdir, 'vddk_libdir_src': vddk_libdir_src, 'src_uri_type': src_uri_type, 'esxi_password': esxi_password, 'esxi_host': esxi_host, 'output_method': output_method, 'os_storage_name': storage_name, 'rhv_upload_opts': rhv_upload_opts, 'oo_json_disk_pattern': json_disk_pattern, 'cmd_has_ip': cmd_has_ip, 'params': params } os.environ['LIBGUESTFS_BACKEND'] = 'direct' v2v_uri = utils_v2v.Uri('esx') remote_uri = v2v_uri.get_uri(remote_host, vpx_dc, esx_ip) # Create password file for access to ESX hypervisor vpx_passwd_file = params.get("vpx_passwd_file") with open(vpx_passwd_file, 'w') as pwd_f: if src_uri_type == 'esx': pwd_f.write(esxi_password) else: pwd_f.write(vpx_passwd) v2v_params['v2v_opts'] += " -ip %s" % vpx_passwd_file if params.get('output_format'): v2v_params.update({'of_format': params['output_format']}) # Rename guest with special name while converting to rhev if '#' in vm_name and output_mode == 'rhev': v2v_params['new_name'] = v2v_params['new_name'].replace('#', '_') # Create SASL user on the ovirt host if output_mode == 'rhev': # create different sasl_user name for different job params.update({ 'sasl_user': params.get("sasl_user") + utils_misc.generate_random_string(3) }) logging.info('sals user name is %s' % params.get("sasl_user")) user_pwd = "[['%s', '%s']]" % (params.get("sasl_user"), params.get("sasl_pwd")) v2v_sasl = utils_sasl.SASL(sasl_user_pwd=user_pwd) v2v_sasl.server_ip = params.get("remote_ip") v2v_sasl.server_user = params.get('remote_user') v2v_sasl.server_pwd = params.get('remote_pwd') v2v_sasl.setup(remote=True) logging.debug('A SASL session %s was created', v2v_sasl) if output_method == 'rhv_upload': # Create password file for '-o rhv_upload' to connect to ovirt with open(rhv_passwd_file, 'w') as f: f.write(rhv_passwd) # Copy ca file from ovirt to local remote.scp_from_remote(ovirt_hostname, 22, 'root', ovirt_engine_passwd, ovirt_ca_file_path, local_ca_file_path) # Create libvirt dir pool if output_mode == 'libvirt': pvt.pre_pool(pool_name, pool_type, pool_target, '') if checkpoint == 'root_ask': v2v_params['v2v_opts'] += ' --root ask' v2v_params['custom_inputs'] = params.get('choice', '2') if checkpoint.startswith('root_') and checkpoint != 'root_ask': root_option = params.get('root_option') v2v_params['v2v_opts'] += ' --root %s' % root_option if checkpoint == 'with_proxy': http_proxy = params.get('esx_http_proxy') https_proxy = params.get('esx_https_proxy') logging.info('Set http_proxy=%s, https_proxy=%s', http_proxy, https_proxy) os.environ['http_proxy'] = http_proxy os.environ['https_proxy'] = https_proxy if checkpoint == 'ogac': os.environ['VIRTIO_WIN'] = virtio_win_path if not os.path.exists(os.getenv('VIRTIO_WIN')): test.fail('%s does not exist' % os.getenv('VIRTIO_WIN')) if os.path.isdir(os.getenv('VIRTIO_WIN')) and os_type == 'linux': export_path = os.getenv('VIRTIO_WIN') qemu_guest_agent_dir = os.path.join(export_path, qa_path) if not os.path.exists(qemu_guest_agent_dir) and os.access( export_path, os.W_OK) and qa_url: logging.debug( 'Not found qemu-guest-agent in virtio-win or rhv-guest-tools-iso,' ' Try to prepare it manually. This is not a permanant step, once' ' the official build includes it, this step should be removed.' ) os.makedirs(qemu_guest_agent_dir) rpm_name = os.path.basename(qa_url) download.get_file( qa_url, os.path.join(qemu_guest_agent_dir, rpm_name)) if checkpoint == 'virtio_iso_blk': if not os.path.exists(virtio_win_path): test.fail('%s does not exist' % virtio_win_path) # Find a free loop device free_loop_dev = process.run("losetup --find", shell=True).stdout_text.strip() # Setup a loop device cmd = 'losetup %s %s' % (free_loop_dev, virtio_win_path) process.run(cmd, shell=True) os.environ['VIRTIO_WIN'] = free_loop_dev if checkpoint == 'invalid_pem': # simply change the 2nd line to lowercase to get an invalid pem with open(local_ca_file_path, 'r+') as fd: for i in range(2): pos = fd.tell() res = fd.readline() fd.seek(pos) fd.write(res.lower()) fd.flush() if checkpoint == 'without_default_net': net_name = find_net('virbr0') if net_name: destroy_net(net_name) if checkpoint == 'empty_cdrom': virsh_dargs = { 'uri': remote_uri, 'remote_ip': remote_host, 'remote_user': '******', 'remote_pwd': vpx_passwd, 'auto_close': True, 'debug': True } remote_virsh = virsh.VirshPersistent(**virsh_dargs) v2v_result = remote_virsh.dumpxml(vm_name) remote_virsh.close_session() else: if checkpoint == 'exist_uuid': auto_clean = False if checkpoint in [ 'mismatched_uuid', 'no_uuid', 'invalid_source', 'system_rhv_pem_set', 'system_rhv_pem_unset' ]: cmd_only = True auto_clean = False v2v_result = utils_v2v.v2v_cmd(v2v_params, auto_clean, cmd_only, interaction_run) if 'new_name' in v2v_params: vm_name = params['main_vm'] = v2v_params['new_name'] if checkpoint.startswith('system_rhv_pem'): if checkpoint == 'system_rhv_pem_set': global_pem_setup(local_ca_file_path) rhv_cafile = r'-oo rhv-cafile=\S+\s*' new_cmd = utils_v2v.cmd_remove_option(v2v_result, rhv_cafile) logging.debug('New v2v command:\n%s', new_cmd) if checkpoint == 'mismatched_uuid': # append more uuid new_cmd = v2v_result + ' -oo rhv-disk-uuid=%s' % str(uuid.uuid4()) if checkpoint == 'no_uuid': rhv_disk_uuid = r'-oo rhv-disk-uuid=\S+\s*' new_cmd = utils_v2v.cmd_remove_option(v2v_result, rhv_disk_uuid) logging.debug('New v2v command:\n%s', new_cmd) if checkpoint == 'exist_uuid': new_vm_name = v2v_params['new_name'] + '_exist_uuid' new_cmd = v2v_result.command.replace('-on %s' % vm_name, '-on %s' % new_vm_name) logging.debug('re-run v2v command:\n%s', new_cmd) if checkpoint == 'invalid_source': if params.get('invalid_vpx_hostname'): new_cmd = v2v_result.replace( vpx_hostname, params.get('invalid_vpx_hostname')) if params.get('invalid_esx_hostname'): new_cmd = v2v_result.replace( esxi_host, params.get('invalid_esx_hostname')) if checkpoint in [ 'mismatched_uuid', 'no_uuid', 'invalid_source', 'exist_uuid', 'system_rhv_pem_set', 'system_rhv_pem_unset' ]: v2v_result = utils_v2v.cmd_run(new_cmd, params.get('v2v_dirty_resources')) check_result(v2v_result, status_error) finally: if checkpoint == 'ogac' and params.get('tmp_mount_point'): if os.path.exists(params.get('tmp_mount_point')): utils_misc.umount(os.getenv('VIRTIO_WIN'), params['tmp_mount_point'], 'iso9660') os.environ.pop('VIRTIO_WIN') if checkpoint == 'virtio_iso_blk': process.run('losetup -d %s' % free_loop_dev, shell=True) os.environ.pop('VIRTIO_WIN') if checkpoint == 'system_rhv_pem_set': global_pem_cleanup() if checkpoint == 'without_default_net': if net_name: start_net(net_name) if params.get('vmchecker'): params['vmchecker'].cleanup() if output_mode == 'rhev' and v2v_sasl: v2v_sasl.cleanup() logging.debug('SASL session %s is closing', v2v_sasl) v2v_sasl.close_session() if output_mode == 'libvirt': pvt.cleanup_pool(pool_name, pool_type, pool_target, '') if checkpoint == 'with_proxy': logging.info('Unset http_proxy&https_proxy') os.environ.pop('http_proxy') os.environ.pop('https_proxy') # Cleanup constant files utils_v2v.cleanup_constant_files(params)
def run(test, params, env): """ WHQL DTM client installation: 1) Log into the guest (the client machine) and into a DTM server machine 2) Stop the DTM client service (wttsvc) on the client machine 3) Delete the client machine from the server's data store 4) Rename the client machine (give it a randomly generated name) 5) Move the client machine into the server's workgroup 6) Reboot the client machine 7) Install the DTM client software 8) Setup auto logon for the user created by the installation (normally DTMLLUAdminUser) 9) Reboot again :param test: kvm test object :param params: Dictionary with the test parameters :param env: Dictionary with test environment. """ vm = env.get_vm(params["main_vm"]) vm.verify_alive() session = vm.wait_for_login(timeout=int(params.get("login_timeout", 360))) # Collect test params server_address = params.get("server_address") server_shell_port = int(params.get("server_shell_port")) server_file_transfer_port = int(params.get("server_file_transfer_port")) server_studio_path = params.get("server_studio_path", "%programfiles%\\ " "Microsoft Driver Test Manager\\Studio") server_username = params.get("server_username") server_password = params.get("server_password") client_username = params.get("client_username") client_password = params.get("client_password") dsso_delete_machine_binary = params.get("dsso_delete_machine_binary", "deps/whql_delete_machine_15.exe") dsso_delete_machine_binary = utils_misc.get_path(test.bindir, dsso_delete_machine_binary) install_timeout = float(params.get("install_timeout", 600)) install_cmd = params.get("install_cmd") wtt_services = params.get("wtt_services") # Stop WTT service(s) on client for svc in wtt_services.split(): utils_test.stop_windows_service(session, svc) # Copy dsso_delete_machine_binary to server rss_client.upload(server_address, server_file_transfer_port, dsso_delete_machine_binary, server_studio_path, timeout=60) # Open a shell session with server server_session = remote.remote_login("nc", server_address, server_shell_port, "", "", session.prompt, session.linesep) server_session.set_status_test_command(session.status_test_command) # Get server and client information cmd = "echo %computername%" server_name = server_session.cmd_output(cmd).strip() client_name = session.cmd_output(cmd).strip() cmd = "wmic computersystem get domain" server_workgroup = server_session.cmd_output(cmd).strip() server_workgroup = server_workgroup.splitlines()[-1] regkey = r"HKLM\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters" cmd = "reg query %s /v Domain" % regkey o = server_session.cmd_output(cmd).strip().splitlines()[-1] try: server_dns_suffix = o.split(None, 2)[2] except IndexError: server_dns_suffix = "" # Delete the client machine from the server's data store (if it's there) server_session.cmd("cd %s" % server_studio_path) cmd = "%s %s %s" % (os.path.basename(dsso_delete_machine_binary), server_name, client_name) server_session.cmd(cmd, print_func=logging.info) server_session.close() # Rename the client machine client_name = "autotest_%s" % utils_misc.generate_random_string(4) logging.info("Renaming client machine to '%s'", client_name) cmd = ('wmic computersystem where name="%%computername%%" rename name="%s"' % client_name) session.cmd(cmd, timeout=600) # Join the server's workgroup logging.info("Joining workgroup '%s'", server_workgroup) cmd = ('wmic computersystem where name="%%computername%%" call ' 'joindomainorworkgroup name="%s"' % server_workgroup) session.cmd(cmd, timeout=600) # Set the client machine's DNS suffix logging.info("Setting DNS suffix to '%s'", server_dns_suffix) cmd = 'reg add %s /v Domain /d "%s" /f' % (regkey, server_dns_suffix) session.cmd(cmd, timeout=300) # Reboot session = vm.reboot(session) # Access shared resources on the server machine logging.info("Attempting to access remote share on server") cmd = r"net use \\%s /user:%s %s" % (server_name, server_username, server_password) end_time = time.time() + 120 while time.time() < end_time: try: session.cmd(cmd) break except Exception: pass time.sleep(5) else: raise error.TestError("Could not access server share from client " "machine") # Install logging.info("Installing DTM client (timeout=%ds)", install_timeout) install_cmd = r"cmd /c \\%s\%s" % (server_name, install_cmd.lstrip("\\")) session.cmd(install_cmd, timeout=install_timeout) # Setup auto logon logging.info("Setting up auto logon for user '%s'", client_username) cmd = ('reg add ' '"HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\winlogon" ' '/v "%s" /d "%s" /t REG_SZ /f') session.cmd(cmd % ("AutoAdminLogon", "1")) session.cmd(cmd % ("DefaultUserName", client_username)) session.cmd(cmd % ("DefaultPassword", client_password)) # Reboot one more time session = vm.reboot(session) session.close()
def run(test, params, env): """ Test network/interface function on 2 vms: - Test settings on 2 vms - Run ping check on 2 vms including pinging each other ... """ vms = params.get('vms').split() vm_list = [env.get_vm(v_name) for v_name in vms] if len(vm_list) != 2: test.cancel('More or less than 2 vms is currently unsupported') feature = params.get('feature', '') case = params.get('case', '') check_ping = 'yes' == params.get('check_ping') expect_ping_host = 'yes' == params.get('expect_ping_host', 'no') expect_ping_out = 'yes' == params.get('expect_ping_out', 'no') expect_ping_vm = 'yes' == params.get('expect_ping_vm', 'no') out_ip = params.get('out_ip', 'www.redhat.com') live_update = 'yes' == params.get('live_update', 'no') set_all = 'yes' == params.get('set_all', 'no') rand_id = '_' + utils_misc.generate_random_string(3) bridge_name = params.get('bridge_name', 'test_br0') + rand_id iface_name = utils_net.get_net_if(state="UP")[0] test_net = 'net_isolated' + rand_id bridge_created = False vmxml_backup_list = [] for vm_i in vm_list: vmxml_backup_list.append(vm_xml.VMXML.new_from_inactive_dumpxml(vm_i.name)) try: # Test feature: port isolated if feature == 'port_isolated': if not libvirt_version.version_compare(6, 2, 0): test.cancel('Libvirt version should be' ' > 6.2.0 to support port isolated') if case.startswith('set_iface'): create_bridge(bridge_name, iface_name) bridge_created = True iface_type = case.split('_')[-1] if iface_type == 'network': net_dict = {'net_forward': "{'mode': 'bridge'}", 'net_bridge': "{'name': '%s'}" % bridge_name} prepare_network(test_net, **net_dict) updated_iface_dict = { 'type': iface_type, 'source': "{'network': '%s'}" % test_net, } elif iface_type == 'bridge': updated_iface_dict = { 'type': iface_type, 'source': "{'bridge': '%s'}" % bridge_name, } else: test.error('Unsupported iface type: %s' % iface_type) # Set 2 vms to isolated=yes or set one to 'yes', the other to 'no' isolated_settings = ['yes'] * 2 if set_all else ['yes', 'no'] for i in (0, 1): vm_i = vm_list[i] new_iface_dict = dict( list(updated_iface_dict.items()) + [('port', "{'isolated': '%s'}" % isolated_settings[i])] ) libvirt.modify_vm_iface(vm_i.name, 'update_iface', new_iface_dict) logging.debug(virsh.dumpxml(vm_i.name).stdout_text) if case == 'update_iface': if params.get('iface_port'): iface_dict = {'port': params['iface_port']} for vm_i in vm_list: libvirt.modify_vm_iface(vm_i.name, 'update_iface', iface_dict) logging.debug(virsh.dumpxml(vm_i.name).stdout_text) if live_update: for vm_i in vm_list: vm_i.start() # Test Update iface with new attrs new_iface_dict = {} if params.get('new_iface_port'): new_iface_dict['port'] = params['new_iface_port'] elif params.get('del_port') == 'yes': new_iface_dict['del_port'] = True for vm_i in vm_list: updated_iface = libvirt.modify_vm_iface(vm_i.name, 'get_xml', new_iface_dict) result = virsh.update_device(vm_i.name, updated_iface, debug=True) libvirt.check_exit_status(result) if case == 'attach_iface': new_ifaces = {} for vm_i in vm_list: # Create iface xml to be attached new_iface = interface.Interface('network') new_iface.xml = libvirt.modify_vm_iface( vm_i.name, 'get_xml', {'port': params.get('new_iface_port')} ) new_ifaces[vm_i.name] = new_iface # Remove current ifaces on vm vmxml_i = vm_xml.VMXML.new_from_inactive_dumpxml(vm_i.name) vmxml_i.remove_all_device_by_type('interface') vmxml_i.sync() logging.debug(virsh.dumpxml(vm_i.name).stdout_text) # Start vm for hotplug vm_i.start() session = vm_i.wait_for_serial_login() # Hotplug iface virsh.attach_device(vm_i.name, new_iface.xml, debug=True, ignore_status=False) # Wait a few seconds for interface to be fully attached time.sleep(5) ip_l_before = session.cmd_output('ip l') logging.debug(ip_l_before) session.close() if case == 'set_network': create_bridge(bridge_name, iface_name) bridge_created = True net_dict = { 'net_forward': "{'mode': 'bridge'}", 'net_bridge': "{'name': '%s'}" % bridge_name, 'net_port': "{'isolated': '%s'}" % params.get( 'net_isolated', 'yes')} prepare_network(test_net, **net_dict) # Modify iface to connect to newly added network updated_iface_dict = {'type': 'network', 'source': "{'network': '%s'}" % test_net} for vm_i in vm_list: libvirt.modify_vm_iface(vm_i.name, 'update_iface', updated_iface_dict) logging.debug(virsh.domiflist(vm_i.name).stdout_text) # Check ping result from vm session to host, outside, the other vm if check_ping: for vm_i in vm_list: if vm_i.is_dead(): vm_i.start() host_ip = utils_net.get_host_ip_address() ping_expect = { host_ip: expect_ping_host, out_ip: expect_ping_out, } # A map of vm session and vm's ip addr session_n_ip = {} for vm_i in vm_list: mac = vm_i.get_mac_address() sess = vm_i.wait_for_serial_login() vm_ip = utils_net.get_guest_ip_addr(sess, mac) session_n_ip[sess] = vm_ip logging.debug('Vm %s ip: %s', vm_i.name, vm_ip) # Check ping result from each vm's session for i in (0, 1): sess = list(session_n_ip.keys())[i] another_sess = list(session_n_ip.keys())[1 - i] ping_expect[session_n_ip[another_sess]] = expect_ping_vm if not ping_func(sess, **ping_expect): test.fail('Ping check failed') # Remove the other session's ip from ping result, then the # next round of ping check will not do a ping check to the vm itself ping_expect.pop(session_n_ip[another_sess]) # Some test steps after ping check if feature == 'port_isolated': if case == 'attach_iface': # Test detach of iface for vm_name_i in new_ifaces: virsh.detach_device( vm_name_i, new_ifaces[vm_name_i].xml, wait_for_event=True, debug=True, ignore_status=False ) # Check whether iface successfully detached by checking 'ip l' output for vm_i in vm_list: session = vm_i.wait_for_serial_login() ip_l_after = session.cmd_output('ip l') session.close() if len(ip_l_before.splitlines()) == len(ip_l_after.splitlines()): test.fail('Output of "ip l" is not changed afte detach, ' 'interface not successfully detached')
def test_default_default(self): style = self.get_style(utils_misc.generate_random_string(16), utils_misc.generate_random_string(16)) self.assertEqual(style['mac_prefix'], '9a') self.assertEqual(style['container_class'], utils_net.QemuIface) self.assert_(issubclass(style['container_class'], utils_net.VirtIface))
def run(test, params, env): """ Convert specific esx guest """ V2V_UNSUPPORT_RHEV_APT_VER = "[virt-v2v-1.43.3-4.el9,)" for v in list(params.values()): if "V2V_EXAMPLE" in v: test.cancel("Please set real value for %s" % v) if utils_v2v.V2V_EXEC is None: raise ValueError('Missing command: virt-v2v') enable_legacy_policy = params_get(params, "enable_legacy_policy") == 'yes' version_required = params.get("version_required") unprivileged_user = params_get(params, 'unprivileged_user') vpx_hostname = params.get('vpx_hostname') vpx_passwd = params.get("vpx_password") esxi_host = esx_ip = params.get('esx_hostname') vpx_dc = params.get('vpx_dc') vm_name = params.get('main_vm') output_mode = params.get('output_mode') pool_name = params.get('pool_name', 'v2v_test') pool_type = params.get('pool_type', 'dir') pool_target = params.get('pool_target_path', 'v2v_pool') pvt = libvirt.PoolVolumeTest(test, params) v2v_timeout = int(params.get('v2v_timeout', 1200)) v2v_cmd_timeout = int(params.get('v2v_cmd_timeout', 18000)) v2v_opts = '-v -x' if params.get('v2v_debug', 'on') in ['on', 'force_on' ] else '' if params.get("v2v_opts"): # Add a blank by force v2v_opts += ' ' + params.get("v2v_opts") status_error = 'yes' == params.get('status_error', 'no') address_cache = env.get('address_cache') checkpoint = params.get('checkpoint', '').split(',') skip_vm_check = params.get('skip_vm_check', 'no') skip_reason = params.get('skip_reason') error_list = [] remote_host = vpx_hostname # For VDDK input_transport = params.get("input_transport") vddk_libdir = params.get('vddk_libdir') # nfs mount source vddk_libdir_src = params.get('vddk_libdir_src') vddk_thumbprint = params.get('vddk_thumbprint') src_uri_type = params.get('src_uri_type') esxi_password = params.get('esxi_password') json_disk_pattern = params.get('json_disk_pattern') # For construct rhv-upload option in v2v cmd output_method = params.get("output_method") rhv_upload_opts = params.get("rhv_upload_opts") storage_name = params.get('storage_name') os_pool = os_storage = params.get('output_storage', 'default') # for get ca.crt file from ovirt engine rhv_passwd = params.get("rhv_upload_passwd") rhv_passwd_file = params.get("rhv_upload_passwd_file") ovirt_engine_passwd = params.get("ovirt_engine_password") ovirt_hostname = params.get("ovirt_engine_url").split( '/')[2] if params.get("ovirt_engine_url") else None ovirt_ca_file_path = params.get("ovirt_ca_file_path") local_ca_file_path = params.get("local_ca_file_path") os_version = params.get('os_version') os_type = params.get('os_type') virtio_win_path = params.get('virtio_win_path') # qemu-guest-agent path in virtio-win or rhv-guest-tools-iso qa_path = params.get('qa_path') # download url of qemu-guest-agent qa_url = params.get('qa_url') v2v_sasl = None # default values for v2v_cmd auto_clean = True cmd_only = False cmd_has_ip = 'yes' == params.get('cmd_has_ip', 'yes') interaction_run = 'yes' == params.get('interaction_run', 'no') def log_fail(msg): """ Log error and update error list """ LOG.error(msg) error_list.append(msg) def check_vmtools(vmcheck, check): """ Check whether vmware tools packages have been removed, or vmware-tools service has stopped :param vmcheck: VMCheck object for vm checking :param check: Checkpoint of different cases :return: None """ if "service" not in check: LOG.info('Check if packages been removed') pkgs = vmcheck.session.cmd('rpm -qa').strip() removed_pkgs = params.get('removed_pkgs').strip().split(',') if not removed_pkgs: test.error('Missing param "removed_pkgs"') for pkg in removed_pkgs: if pkg in pkgs: log_fail('Package "%s" not removed' % pkg) else: LOG.info('Check if service stopped') vmtools_service = params.get('service_name') status = utils_misc.get_guest_service_status( vmcheck.session, vmtools_service) LOG.info('Service %s status: %s', vmtools_service, status) if status != 'inactive': log_fail('Service "%s" is not stopped' % vmtools_service) def check_modprobe(vmcheck): """ Check whether content of /etc/modprobe.conf meets expectation """ content = vmcheck.session.cmd('cat /etc/modprobe.conf').strip() LOG.debug(content) cfg_content = params.get('cfg_content') if not cfg_content: test.error('Missing content for search') LOG.info('Search "%s" in /etc/modprobe.conf', cfg_content) pattern = r'\s+'.join(cfg_content.split()) if not re.search(pattern, content): log_fail('Not found "%s"' % cfg_content) def check_device_map(vmcheck): """ Check if the content of device.map meets expectation. """ LOG.info(vmcheck.session.cmd('fdisk -l').strip()) device_map = params.get('device_map_path') content = vmcheck.session.cmd('cat %s' % device_map) LOG.debug('Content of device.map:\n%s', content) LOG.info('Found device: %d', content.count('/dev/')) LOG.info('Found virtio device: %d', content.count('/dev/vd')) if content.count('/dev/') != content.count('/dev/vd'): log_fail('Content of device.map not correct') else: LOG.info('device.map has been remaped to "/dev/vd*"') def check_resume_swap(vmcheck): """ Check the content of grub files meet expectation. """ if os_version == 'rhel7': chkfiles = [ '/etc/default/grub', '/boot/grub2/grub.cfg', '/etc/grub2.cfg' ] if os_version == 'rhel6': chkfiles = ['/boot/grub/grub.conf', '/etc/grub.conf'] for file_i in chkfiles: status, content = vmcheck.run_cmd('cat %s' % file_i) if status != 0: log_fail('%s does not exist' % file_i) resume_dev_count = content.count('resume=/dev/') if resume_dev_count == 0 or resume_dev_count != content.count( 'resume=/dev/vd'): reason = 'Maybe the VM\'s swap pariton is lvm' log_fail('Content of %s is not correct or %s' % (file_i, reason)) content = vmcheck.session.cmd('cat /proc/cmdline') LOG.debug('Content of /proc/cmdline:\n%s', content) if 'resume=/dev/vd' not in content: log_fail('Content of /proc/cmdline is not correct') def check_rhev_file_exist(vmcheck): """ Check if rhev files exist """ file_path = { 'rhev-apt.exe': r'C:\rhev-apt.exe', 'rhsrvany.exe': r'"C:\Program Files\Guestfs\Firstboot\rhsrvany.exe"' } # rhev-apt.ext is removed on rhel9 if utils_v2v.multiple_versions_compare(V2V_UNSUPPORT_RHEV_APT_VER): file_path.pop('rhev-apt.exe') for key in file_path: status = vmcheck.session.cmd_status('dir %s' % file_path[key]) if status == 0: LOG.info('%s exists' % key) else: log_fail('%s does not exist after convert to rhv' % key) def check_file_architecture(vmcheck): """ Check the 3rd party module info :param vmcheck: VMCheck object for vm checking """ content = vmcheck.session.cmd('uname -r').strip() status = vmcheck.session.cmd_status( 'rpm -qf /lib/modules/%s/fileaccess/fileaccess_mod.ko ' % content) if status == 0: log_fail('3rd party module info is not correct') else: LOG.info( 'file /lib/modules/%s/fileaccess/fileaccess_mod.ko is not owned by any package' % content) def check_windows_signature(vmcheck, full_name): """ Check signature of a file in windows VM :param vmcheck: VMCheck object for vm checking :param full_name: a file's full path name """ LOG.info('powershell or signtool needs to be installed in guest first') cmds = [('powershell "Get-AuthenticodeSignature %s | format-list"' % full_name, r'SignerCertificate.*?Not After](.*?)\[Thumbprint', '%m/%d/%Y %I:%M:%S %p'), ('signtool verify /v %s' % full_name, r'Issued to: Red Hat.*?Expires:(.*?)SHA1 hash', '')] for cmd, ptn, fmt in cmds: _, output = vmcheck.run_cmd(cmd) if re.search(ptn, output, re.S): expire_time = re.search(ptn, output, re.S).group(1).strip() if fmt: expire_time = time.strptime(expire_time, fmt) else: expire_time = time.strptime(expire_time) if time.time() > time.mktime(expire_time): test.fail("Signature of '%s' has expired" % full_name) return # Get here means the guest doesn't have powershell or signtool test.error("Powershell or Signtool must be installed in guest") def check_windows_vmware_tools(vmcheck): """ Check vmware tools is uninstalled in VM :param vmcheck: VMCheck object for vm checking """ def _get_vmware_info(cmd): _, res = vmcheck.run_cmd(cmd) if res and not re.search('vmtools', res, re.I): return True return False cmds = ['tasklist', 'sc query vmtools'] for cmd in cmds: res = utils_misc.wait_for(lambda: _get_vmware_info(cmd), 600, step=30) if not res: test.fail("Failed to verification vmtools uninstallation") def check_windows_service(vmcheck, service_name): """ Check service in VM :param vmcheck: VMCheck object for vm checking :param service_name: a service's name """ try: res = utils_misc.wait_for(lambda: re.search( 'running', vmcheck.get_service_info(service_name), re.I), 600, step=30) except (ShellProcessTerminatedError, ShellStatusError): # Windows guest may reboot after installing qemu-ga service LOG.debug('Windows guest is rebooting') if vmcheck.session: vmcheck.session.close() vmcheck.session = None # VM boots up is extremely slow when all testing in running on # rhv server simultaneously, so set timeout to 1200. vmcheck.create_session(timeout=1200) res = utils_misc.wait_for(lambda: re.search( 'running', vmcheck.get_service_info(service_name), re.I), 600, step=30) if not res: test.fail('Not found running %s service' % service_name) def check_linux_ogac(vmcheck): """ Check qemu-guest-agent service in VM :param vmcheck: VMCheck object for vm checking """ def get_pkgs(pkg_path): """ Get all qemu-guest-agent pkgs """ pkgs = [] for _, _, files in os.walk(pkg_path): for file_name in files: pkgs.append(file_name) return pkgs def get_pkg_version_vm(): """ Get qemu-guest-agent version in VM """ vendor = vmcheck.get_vm_os_vendor() if vendor in ['Ubuntu', 'Debian']: cmd = 'dpkg -l qemu-guest-agent' else: cmd = 'rpm -q qemu-guest-agent' _, output = vmcheck.run_cmd(cmd) pkg_ver_ptn = [ r'qemu-guest-agent +[0-9]+:(.*?dfsg.*?) +', r'qemu-guest-agent-(.*?)\.x86_64' ] for ptn in pkg_ver_ptn: if re.search(ptn, output): return re.search(ptn, output).group(1) return '' if os.path.isfile(os.getenv('VIRTIO_WIN')): mount_point = utils_v2v.v2v_mount(os.getenv('VIRTIO_WIN'), 'rhv_tools_setup_iso', fstype='iso9660') export_path = params['tmp_mount_point'] = mount_point else: export_path = os.getenv('VIRTIO_WIN') qemu_guest_agent_dir = os.path.join(export_path, qa_path) all_pkgs = get_pkgs(qemu_guest_agent_dir) LOG.debug('The installing qemu-guest-agent is: %s' % all_pkgs) vm_pkg_ver = get_pkg_version_vm() LOG.debug('qemu-guest-agent version in vm: %s' % vm_pkg_ver) # Check the service status of qemu-guest-agent in VM status_ptn = r'Active: active \(running\)|qemu-ga \(pid +[0-9]+\) is running' cmd = 'service qemu-ga status;systemctl status qemu-guest-agent;systemctl status qemu-ga*' _, output = vmcheck.run_cmd(cmd) if not re.search(status_ptn, output): log_fail('qemu-guest-agent service exception') def check_ubuntools(vmcheck): """ Check open-vm-tools, ubuntu-server in VM :param vmcheck: VMCheck object for vm checking """ LOG.info('Check if open-vm-tools service stopped') status = utils_misc.get_guest_service_status(vmcheck.session, 'open-vm-tools') LOG.info('Service open-vm-tools status: %s', status) if status != 'inactive': log_fail('Service open-vm-tools is not stopped') else: LOG.info('Check if the ubuntu-server exist') content = vmcheck.session.cmd('dpkg -s ubuntu-server') if 'install ok installed' in content: LOG.info('ubuntu-server has not been removed.') else: log_fail('ubuntu-server has been removed') def global_pem_setup(f_pem): """ Setup global rhv server ca :param f_pem: ca file path """ ca_anchors_dir = '/etc/pki/ca-trust/source/anchors' shutil.copy(f_pem, ca_anchors_dir) process.run('update-ca-trust extract', shell=True) os.unlink(os.path.join(ca_anchors_dir, os.path.basename(f_pem))) def global_pem_cleanup(): """ Cleanup global rhv server ca """ process.run('update-ca-trust extract', shell=True) def find_net(bridge_name): """ Find which network use specified bridge :param bridge_name: bridge name you want to find """ net_list = virsh.net_state_dict(only_names=True) net_name = '' if len(net_list): for net in net_list: net_info = virsh.net_info(net).stdout.strip() search = re.search(r'Bridge:\s+(\S+)', net_info) if search: if bridge_name == search.group(1): net_name = net else: LOG.info('Conversion server has no network') return net_name def destroy_net(net_name): """ destroy network in conversion server """ if virsh.net_state_dict()[net_name]['active']: LOG.info("Remove network %s in conversion server", net_name) virsh.net_destroy(net_name) if virsh.net_state_dict()[net_name]['autostart']: virsh.net_autostart(net_name, "--disable") output = virsh.net_list("--all").stdout.strip() LOG.info(output) def start_net(net_name): """ start network in conversion server """ LOG.info("Recover network %s in conversion server", net_name) virsh.net_autostart(net_name) if not virsh.net_state_dict()[net_name]['active']: virsh.net_start(net_name) output = virsh.net_list("--all").stdout.strip() LOG.info(output) def check_static_ip_conf(vmcheck): """ Check static IP configuration in VM :param vmcheck: VMCheck object for vm checking """ def _static_ip_check(): cmd = 'ipconfig /all' _, output = vmcheck.run_cmd(cmd, debug=False) v2v_cmd = params_get(params, 'v2v_command') # --mac 00:50:56:ac:7a:4d:ip:192.168.1.2,192.168.1.1,22,192.168.1.100,10.73.2.108,10.66.127.10' mac_ip_pattern = '--mac (([0-9a-zA-Z]{2}:){6})ip:([0-9,.]+)' ip_config_list = re.search(mac_ip_pattern, v2v_cmd).group(3) mac_addr = re.search(mac_ip_pattern, v2v_cmd).group(1)[0:-1].upper().replace( ':', '-') eth_adapter_ptn = r'Ethernet adapter Ethernet.*?NetBIOS over Tcpip' try: ipconfig = [ v for v in re.findall(eth_adapter_ptn, output, re.S) if mac_addr in v ][0] except IndexError: return False for i, value in enumerate(ip_config_list.split(',')): if not value: continue # IP address if i == 0: ip_addr = r'IPv4 Address.*?: %s' % value if not re.search(ip_addr, ipconfig, re.S): LOG.debug('Found IP addr failed') return False # Default gateway if i == 1: ip_gw = r'Default Gateway.*?: .*?%s' % value if not re.search(ip_gw, ipconfig, re.S): LOG.debug('Found Gateway failed') return False # Subnet mask if i == 2: # convert subnet mask to cidr bin_mask = '1' * int(value) + '0' * (32 - int(value)) cidr = '.'.join([ str(int(bin_mask[i * 8:i * 8 + 8], 2)) for i in range(4) ]) sub_mask = r'Subnet Mask.*?: %s' % cidr if not re.search(sub_mask, ipconfig, re.S): LOG.debug('Found subnet mask failed') return False # DNS server list if i >= 3: dns_server = r'DNS Servers.*?:.*?%s' % value if not re.search(dns_server, ipconfig, re.S): LOG.debug('Found DNS Server failed') return False return True try: vmcheck.create_session() res = utils_misc.wait_for(_static_ip_check, 1800, step=300) except (ShellTimeoutError, ShellProcessTerminatedError): LOG.debug( 'Lost connection to windows guest, the static IP may take effect' ) if vmcheck.session: vmcheck.session.close() vmcheck.session = None vmcheck.create_session() res = utils_misc.wait_for(_static_ip_check, 300, step=30) vmcheck.run_cmd('ipconfig /all') # debug msg if not res: test.fail('Checking static IP configuration failed') def check_rhsrvany_checksums(vmcheck): """ Check if MD5 and SHA1 of rhsrvany.exe are correct """ def _get_expected_checksums(tool_exec, file): val = process.run('%s %s' % (tool_exec, rhsrvany_path), shell=True).stdout_text.split()[0] if not val: test.error('Get checksum failed') LOG.info('%s: Expect %s: %s', file, tool_exec, val) return val def _get_real_checksums(algorithm, file): certutil_cmd = r'certutil -hashfile "%s"' % file if algorithm == 'md5': certutil_cmd += ' MD5' res = vmcheck.session.cmd_output(certutil_cmd, safe=True) LOG.debug('%s output:\n%s', certutil_cmd, res) val = res.strip().splitlines()[1].strip() LOG.info('%s: Real %s: %s', file, algorithm, val) return val LOG.info('Check md5 and sha1 of rhsrvany.exe') algorithms = {'md5': 'md5sum', 'sha1': 'sha1sum'} rhsrvany_path = r'/usr/share/virt-tools/rhsrvany.exe' rhsrvany_path_windows = r"C:\Program Files\Guestfs\Firstboot\rhsrvany.exe" for key, val in algorithms.items(): expect_val = _get_expected_checksums(val, rhsrvany_path) real_val = _get_real_checksums(key, rhsrvany_path_windows) if expect_val == real_val: LOG.info('%s are correct', key) else: test.fail('%s of rhsrvany.exe is not correct' % key) def check_result(result, status_error): """ Check virt-v2v command result """ def vm_check(status_error): """ Checking the VM """ if status_error: return if output_mode == 'json' and not check_json_output(params): test.fail('check json output failed') if output_mode == 'local' and not check_local_output(params): test.fail('check local output failed') if output_mode in ['null', 'json', 'local']: return # vmchecker must be put before skip_vm_check in order to clean up # the VM. vmchecker = VMChecker(test, params, env) params['vmchecker'] = vmchecker if skip_vm_check == 'yes': LOG.info('Skip checking vm after conversion: %s' % skip_reason) return if output_mode == 'rhev': if not utils_v2v.import_vm_to_ovirt( params, address_cache, timeout=v2v_timeout): test.fail('Import VM failed') elif output_mode == 'libvirt': virsh.start(vm_name, debug=True) # Check guest following the checkpoint document after conversion LOG.info('Checking common checkpoints for v2v') if 'ogac' in checkpoint: # windows guests will reboot at any time after qemu-ga is # installed. The process cannot be controlled. In order to # don't break vmchecker.run() process, It's better to put # check_windows_ogac before vmchecker.run(). Because in # check_windows_ogac, it waits until rebooting completes. vmchecker.checker.create_session() if os_type == 'windows': services = ['qemu-ga'] if not utils_v2v.multiple_versions_compare( V2V_UNSUPPORT_RHEV_APT_VER): services.append('rhev-apt') if 'rhv-guest-tools' in os.getenv('VIRTIO_WIN'): services.append('spice-ga') for ser in services: check_windows_service(vmchecker.checker, ser) else: check_linux_ogac(vmchecker.checker) if 'mac_ip' in checkpoint: check_static_ip_conf(vmchecker.checker) ret = vmchecker.run() if len(ret) == 0: LOG.info("All common checkpoints passed") # Check specific checkpoints if 'ogac' in checkpoint and 'signature' in checkpoint: if not utils_v2v.multiple_versions_compare( V2V_UNSUPPORT_RHEV_APT_VER): check_windows_signature(vmchecker.checker, r'c:\rhev-apt.exe') if 'cdrom' in checkpoint and "device='cdrom'" not in vmchecker.vmxml: test.fail('CDROM no longer exists') if 'vmtools' in checkpoint: check_vmtools(vmchecker.checker, checkpoint) if 'modprobe' in checkpoint: check_modprobe(vmchecker.checker) if 'device_map' in checkpoint: check_device_map(vmchecker.checker) if 'resume_swap' in checkpoint: check_resume_swap(vmchecker.checker) if 'rhev_file' in checkpoint: check_rhev_file_exist(vmchecker.checker) if 'file_architecture' in checkpoint: check_file_architecture(vmchecker.checker) if 'ubuntu_tools' in checkpoint: check_ubuntools(vmchecker.checker) if 'vmware_tools' in checkpoint: check_windows_vmware_tools(vmchecker.checker) if 'without_default_net' in checkpoint: if virsh.net_state_dict()[net_name]['active']: log_fail("Bridge virbr0 already started during conversion") if 'rhsrvany_checksum' in checkpoint: check_rhsrvany_checksums(vmchecker.checker) if 'block_dev' in checkpoint and not os.path.exists(blk_dev_link): test.fail("checkpoint '%s' failed" % checkpoint) # Merge 2 error lists error_list.extend(vmchecker.errors) # Virtio drivers will not be installed without virtio-win setup if 'virtio_win_unset' in checkpoint: missing_list = params.get('missing').split(',') expect_errors = ['Not find driver: ' + x for x in missing_list] LOG.debug('Expect errors: %s' % expect_errors) LOG.debug('Actual errors: %s' % error_list) if set(error_list) == set(expect_errors): error_list[:] = [] else: LOG.error('Virtio drivers not meet expectation') utils_v2v.check_exit_status(result, status_error) output = result.stdout_text + result.stderr_text # VM or local output checking vm_check(status_error) # Check log size decrease option if 'log decrease' in checkpoint: nbdkit_option = r'nbdkit\.backend\.datapath=0' if not re.search(nbdkit_option, output): test.fail("checkpoint '%s' failed" % checkpoint) if 'fstrim_warning' in checkpoint: # Actually, fstrim has no relationship with v2v, it may be related # to kernel, this warning really doesn't matter and has no harm to # the conversion. V2V_FSTRIM_SUCESS_VER = "[virt-v2v-1.45.1-1.el9,)" if utils_v2v.multiple_versions_compare(V2V_FSTRIM_SUCESS_VER): params.update({'expect_msg': None}) # Log checking log_check = utils_v2v.check_log(params, output) if log_check: log_fail(log_check) if len(error_list): test.fail('%d checkpoints failed: %s' % (len(error_list), error_list)) try: if version_required and not utils_v2v.multiple_versions_compare( version_required): test.cancel("Testing requires version: %s" % version_required) # See man virt-v2v-input-xen(1) if enable_legacy_policy: update_crypto_policy("LEGACY") v2v_params = { 'hostname': remote_host, 'hypervisor': 'esx', 'main_vm': vm_name, 'vpx_dc': vpx_dc, 'esx_ip': esx_ip, 'new_name': vm_name + utils_misc.generate_random_string(4), 'v2v_opts': v2v_opts, 'input_mode': 'libvirt', 'os_storage': os_storage, 'os_pool': os_pool, 'network': params.get('network'), 'bridge': params.get('bridge'), 'target': params.get('target'), 'password': vpx_passwd if src_uri_type != 'esx' else esxi_password, 'input_transport': input_transport, 'vcenter_host': vpx_hostname, 'vcenter_password': vpx_passwd, 'vddk_thumbprint': vddk_thumbprint, 'vddk_libdir': vddk_libdir, 'vddk_libdir_src': vddk_libdir_src, 'src_uri_type': src_uri_type, 'esxi_password': esxi_password, 'esxi_host': esxi_host, 'output_method': output_method, 'os_storage_name': storage_name, 'rhv_upload_opts': rhv_upload_opts, 'oo_json_disk_pattern': json_disk_pattern, 'cmd_has_ip': cmd_has_ip, 'params': params } utils_v2v.set_libguestfs_backend(params) v2v_uri = utils_v2v.Uri('esx') remote_uri = v2v_uri.get_uri(remote_host, vpx_dc, esx_ip) # Create password file for access to ESX hypervisor vpx_passwd_file = params.get("vpx_passwd_file") with open(vpx_passwd_file, 'w') as pwd_f: if src_uri_type == 'esx': pwd_f.write(esxi_password) else: pwd_f.write(vpx_passwd) v2v_params['v2v_opts'] += " -ip %s" % vpx_passwd_file if params.get('output_format'): v2v_params.update({'of_format': params['output_format']}) # Rename guest with special name while converting to rhev if '#' in vm_name and output_mode == 'rhev': v2v_params['new_name'] = v2v_params['new_name'].replace('#', '_') # Create SASL user on the ovirt host if output_mode == 'rhev': # create different sasl_user name for different job params.update({ 'sasl_user': params.get("sasl_user") + utils_misc.generate_random_string(3) }) LOG.info('sals user name is %s' % params.get("sasl_user")) user_pwd = "[['%s', '%s']]" % (params.get("sasl_user"), params.get("sasl_pwd")) v2v_sasl = utils_sasl.SASL(sasl_user_pwd=user_pwd) v2v_sasl.server_ip = params.get("remote_ip") v2v_sasl.server_user = params.get('remote_user') v2v_sasl.server_pwd = params.get('remote_pwd') v2v_sasl.setup(remote=True) LOG.debug('A SASL session %s was created', v2v_sasl) if output_method == 'rhv_upload': # Create password file for '-o rhv_upload' to connect to ovirt with open(rhv_passwd_file, 'w') as f: f.write(rhv_passwd) # Copy ca file from ovirt to local remote.scp_from_remote(ovirt_hostname, 22, 'root', ovirt_engine_passwd, ovirt_ca_file_path, local_ca_file_path) # Create libvirt dir pool if output_mode == 'libvirt': pvt.pre_pool(pool_name, pool_type, pool_target, '') if 'root' in checkpoint and 'ask' in checkpoint: v2v_params['v2v_opts'] += ' --root ask' v2v_params['custom_inputs'] = params.get('choice', '2') if 'root' in checkpoint and 'ask' not in checkpoint: root_option = params.get('root_option') v2v_params['v2v_opts'] += ' --root %s' % root_option if 'with_proxy' in checkpoint: http_proxy = params.get('esx_http_proxy') https_proxy = params.get('esx_https_proxy') LOG.info('Set http_proxy=%s, https_proxy=%s', http_proxy, https_proxy) os.environ['http_proxy'] = http_proxy os.environ['https_proxy'] = https_proxy if 'ogac' in checkpoint: os.environ['VIRTIO_WIN'] = virtio_win_path if not os.path.exists(os.getenv('VIRTIO_WIN')): test.fail('%s does not exist' % os.getenv('VIRTIO_WIN')) if os.path.isdir(os.getenv('VIRTIO_WIN')) and os_type == 'linux': export_path = os.getenv('VIRTIO_WIN') qemu_guest_agent_dir = os.path.join(export_path, qa_path) if not os.path.exists(qemu_guest_agent_dir) and os.access( export_path, os.W_OK) and qa_url: LOG.debug( 'Not found qemu-guest-agent in virtio-win or rhv-guest-tools-iso,' ' Try to prepare it manually. This is not a permanent step, once' ' the official build includes it, this step should be removed.' ) os.makedirs(qemu_guest_agent_dir) rpm_name = os.path.basename(qa_url) download.get_file( qa_url, os.path.join(qemu_guest_agent_dir, rpm_name)) if 'virtio_iso_blk' in checkpoint: if not os.path.exists(virtio_win_path): test.fail('%s does not exist' % virtio_win_path) # Find a free loop device free_loop_dev = process.run("losetup --find", shell=True).stdout_text.strip() # Setup a loop device cmd = 'losetup %s %s' % (free_loop_dev, virtio_win_path) process.run(cmd, shell=True) os.environ['VIRTIO_WIN'] = free_loop_dev if 'block_dev' in checkpoint: os_directory = params_get(params, 'os_directory') block_count = params_get(params, 'block_count') os_directory = tempfile.TemporaryDirectory(prefix='v2v_test_', dir=os_directory) diskimage = '%s/diskimage' % os_directory.name # Update 'os_directory' for '-os' option params['os_directory'] = os_directory.name # Create a 1G image cmd = 'dd if=/dev/zero of=%s bs=10M count=%s' % (diskimage, block_count) process.run(cmd, shell=True) # Build filesystem cmd = 'mkfs.ext4 %s' % diskimage process.run(cmd, shell=True) # Find a free loop device free_loop_dev = process.run("losetup --find", shell=True).stdout_text.strip() # Setup the image as a block device cmd = 'losetup %s %s' % (free_loop_dev, diskimage) process.run(cmd, shell=True) # Create a soft link to the loop device blk_dev_link = '%s/mydisk1' % os_directory.name cmd = 'ln -s %s %s' % (free_loop_dev, blk_dev_link) process.run(cmd, shell=True) if 'invalid_pem' in checkpoint: # simply change the 2nd line to lowercase to get an invalid pem with open(local_ca_file_path, 'r+') as fd: for i in range(2): pos = fd.tell() res = fd.readline() fd.seek(pos) fd.write(res.lower()) fd.flush() if 'without_default_net' in checkpoint: net_name = find_net('virbr0') if net_name: destroy_net(net_name) if 'bandwidth' in checkpoint: dynamic_speeds = params_get(params, 'dynamic_speeds') bandwidth_file = params_get(params, 'bandwidth_file') with open(bandwidth_file, 'w') as fd: fd.write(dynamic_speeds) if checkpoint[0].startswith('virtio_win'): cp = checkpoint[0] src_dir = params.get('virtio_win_dir') dest_dir = os.path.join(data_dir.get_tmp_dir(), 'virtio-win') iso_path = os.path.join(dest_dir, 'virtio-win.iso') if not os.path.exists(dest_dir): shutil.copytree(src_dir, dest_dir) virtio_win_env = params.get('virtio_win_env', 'VIRTIO_WIN') process.run('rpm -e virtio-win') if process.run('rpm -q virtio-win', ignore_status=True).exit_status == 0: test.error('not removed') if cp.endswith('unset'): LOG.info('Unset env %s' % virtio_win_env) os.unsetenv(virtio_win_env) if cp.endswith('custom'): LOG.info('Set env %s=%s' % (virtio_win_env, dest_dir)) os.environ[virtio_win_env] = dest_dir if cp.endswith('iso_mount'): LOG.info('Mount iso to /opt') process.run('mount %s /opt' % iso_path) os.environ[virtio_win_env] = '/opt' if cp.endswith('iso_file'): LOG.info('Set env %s=%s' % (virtio_win_env, iso_path)) os.environ[virtio_win_env] = iso_path if 'luks_dev_keys' in checkpoint: luks_password = params_get(params, 'luks_password', '') luks_keys = params_get(params, 'luks_keys', '') keys_options = ' '.join( list( map(lambda i: '--key %s' % i if i else '', luks_keys.split(';')))) if 'invalid_pwd_file' not in checkpoint: is_file_key = r'--key \S+:file:(\S+)' for file_key in re.findall(is_file_key, keys_options): with open(file_key, 'w') as fd: fd.write(luks_password) v2v_params['v2v_opts'] += ' ' + keys_options if 'empty_cdrom' in checkpoint: virsh_dargs = { 'uri': remote_uri, 'remote_ip': remote_host, 'remote_user': '******', 'remote_pwd': vpx_passwd, 'auto_close': True, 'debug': True } remote_virsh = virsh.VirshPersistent(**virsh_dargs) v2v_result = remote_virsh.dumpxml(vm_name) remote_virsh.close_session() else: if 'exist_uuid' in checkpoint: auto_clean = False if checkpoint[0] in [ 'mismatched_uuid', 'no_uuid', 'invalid_source', 'system_rhv_pem' ]: cmd_only = True auto_clean = False v2v_result = utils_v2v.v2v_cmd(v2v_params, auto_clean, cmd_only, interaction_run) if 'new_name' in v2v_params: vm_name = params['main_vm'] = v2v_params['new_name'] if 'system_rhv_pem' in checkpoint: if 'set' in checkpoint: global_pem_setup(local_ca_file_path) rhv_cafile = r'-oo rhv-cafile=\S+\s*' new_cmd = utils_v2v.cmd_remove_option(v2v_result, rhv_cafile) LOG.debug('New v2v command:\n%s', new_cmd) if 'mismatched_uuid' in checkpoint: # append more uuid new_cmd = v2v_result + ' -oo rhv-disk-uuid=%s' % str(uuid.uuid4()) if 'no_uuid' in checkpoint: rhv_disk_uuid = r'-oo rhv-disk-uuid=\S+\s*' new_cmd = utils_v2v.cmd_remove_option(v2v_result, rhv_disk_uuid) LOG.debug('New v2v command:\n%s', new_cmd) if 'exist_uuid' in checkpoint: # Use to cleanup the VM because it will not be run in check_result vmchecker = VMChecker(test, params, env) params['vmchecker'] = vmchecker # Update name to avoid conflict new_vm_name = v2v_params['new_name'] + '_exist_uuid' new_cmd = v2v_result.command.replace('-on %s' % vm_name, '-on %s' % new_vm_name) new_cmd += ' --no-copy' LOG.debug('re-run v2v command:\n%s', new_cmd) if 'invalid_source' in checkpoint: if params.get('invalid_vpx_hostname'): new_cmd = v2v_result.replace( vpx_hostname, params.get('invalid_vpx_hostname')) if params.get('invalid_esx_hostname'): new_cmd = v2v_result.replace( esxi_host, params.get('invalid_esx_hostname')) if checkpoint[0] in [ 'mismatched_uuid', 'no_uuid', 'invalid_source', 'exist_uuid', 'system_rhv_pem' ]: v2v_result = utils_v2v.cmd_run(new_cmd, params.get('v2v_dirty_resources')) check_result(v2v_result, status_error) finally: if enable_legacy_policy: update_crypto_policy() if checkpoint[0].startswith('virtio_win'): utils_package.package_install(['virtio-win']) if 'virtio_win_iso_mount' in checkpoint: process.run('umount /opt', ignore_status=True) if 'ogac' in checkpoint and params.get('tmp_mount_point'): if os.path.exists(params.get('tmp_mount_point')): utils_misc.umount(os.getenv('VIRTIO_WIN'), params['tmp_mount_point'], 'iso9660') os.environ.pop('VIRTIO_WIN') if 'block_dev' in checkpoint and hasattr(os_directory, 'name'): process.run('losetup -d %s' % free_loop_dev, shell=True) os_directory.cleanup() if 'virtio_iso_blk' in checkpoint: process.run('losetup -d %s' % free_loop_dev, shell=True) os.environ.pop('VIRTIO_WIN') if 'system_rhv_pem' in checkpoint and 'set' in checkpoint: global_pem_cleanup() if 'without_default_net' in checkpoint: if net_name: start_net(net_name) if params.get('vmchecker'): params['vmchecker'].cleanup() if output_mode == 'rhev' and v2v_sasl: v2v_sasl.cleanup() LOG.debug('SASL session %s is closing', v2v_sasl) v2v_sasl.close_session() if output_mode == 'libvirt': pvt.cleanup_pool(pool_name, pool_type, pool_target, '') if 'with_proxy' in checkpoint: LOG.info('Unset http_proxy&https_proxy') os.environ.pop('http_proxy') os.environ.pop('https_proxy') if unprivileged_user: process.system("userdel -fr %s" % unprivileged_user) if params.get('os_directory') and os.path.isdir( params['os_directory']): shutil.rmtree(params['os_directory'], ignore_errors=True) # Cleanup constant files utils_v2v.cleanup_constant_files(params)
# After STEP 1 try: result_name = params.get("result_name", "nfs-perf.RHS") result_file_path = utils_misc.get_path(test.resultsdir, result_name) result_file = open(result_file_path, 'w') except Exception: _clean_up(STEP_1) raise # After STEP 2 error.context("mount nfs server in guest with tcp protocol", logging.info) nfs_server = params.get("nfs_server") nfs_path = params.get("nfs_path") mnt_option = params.get("mnt_option") mnt_point = "/tmp/nfs_perf_%s" % utils_misc.generate_random_string(4) test_file_prefix = os.path.join(mnt_point, "test_%si_" % utils_misc.generate_random_string(4)) blk_size_list = params.get("blk_size_list", "8k").split() test_file_list = map(lambda x: test_file_prefix + x, blk_size_list) if (not nfs_server) or (not nfs_path) or (not mnt_point): _clean_up(STEP_2) raise error.TestError("Missing configuration for nfs partition." " Check your config files") try: session.cmd("mkdir -p %s" % mnt_point) except Exception: _clean_up(STEP_2)
def run(test, params, env): """ vhost is no longer disabled when guest does not use MSI-X. The vhostforce flag is no longer required. 1) Start guest with different NIC option 2) Check virtio device's irq number,irq number should be greater than one. 3) Disable msi of guest 4) Reboot guest,check if msi is disabled and irq number should be equal to 1. 5) Check network and vhost process (transfer data). 6) Check md5 value of both sides. :param test: QEMU test object :param params: Dictionary with the test parameters :param env: Dictionary with test environment. """ def irq_check(session, device_name, devcon_folder): hwid = win_dev.get_hwids(session, device_name, devcon_folder, login_timeout)[0] get_irq_cmd = params["get_irq_cmd"] % (devcon_folder, hwid) irq_list = re.findall(r':\s+(\d+)', session.cmd_output(get_irq_cmd), re.M) if not irq_list: test.error("device %s's irq checked fail" % device_name) return irq_list def get_file_md5sum(file_name, session, timeout): """ return: Return the md5sum value of the guest. """ logging.info("Get md5sum of the file:'%s'", file_name) s, o = session.cmd_status_output("md5sum %s" % file_name, timeout=timeout) if s != 0: test.error("Get file md5sum failed as %s" % o) return re.findall(r"\w{32}", o)[0] tmp_dir = params["tmp_dir"] filesize = int(params.get("filesize")) dd_cmd = params["dd_cmd"] delete_cmd = params["delete_cmd"] file_md5_check_timeout = int(params.get("file_md5_check_timeout")) login_timeout = int(params.get("login_timeout", 360)) vm = env.get_vm(params["main_vm"]) vm.verify_alive() session = vm.wait_for_serial_login() if params.get("os_type") == "linux": error_context.context("Check the pci msi in guest", logging.info) pci_id = session.cmd("lspci |grep Eth |awk {'print $1'}").strip() status = session.cmd("lspci -vvv -s %s|grep MSI-X" % pci_id).strip() enable_status = re.search(r'Enable\+', status, re.M | re.I) if enable_status.group() == "Enable+": error_context.context("Disable pci msi in guest", logging.info) utils_test.update_boot_option(vm, args_added="pci=nomsi") session_msi = vm.wait_for_serial_login(timeout=login_timeout) pci_id = session_msi.cmd( "lspci |grep Eth |awk {'print $1'}").strip() status = session_msi.cmd("lspci -vvv -s %s|grep MSI-X" % pci_id).strip() session_msi.close() change_status = re.search(r'Enable\-', status, re.M | re.I) if change_status.group() != "Enable-": test.fail("virtio device's statuts is not correct") elif enable_status.group() != "Enable+": test.fail("virtio device's statuts is not correct") else: driver = params.get("driver_name") driver_verifier = params.get("driver_verifier", driver) device_name = params["device_name"] devcon_folder = utils_misc.set_winutils_letter(session, params["devcon_folder"]) error_context.context("Boot guest with %s device" % driver, logging.info) session = utils_test.qemu.windrv_check_running_verifier( session, vm, test, driver_verifier, login_timeout) error_context.context("Check %s's irq number" % device_name, logging.info) irq_list = irq_check(session, device_name, devcon_folder) irq_nums = len(irq_list) if not irq_nums > 1 and\ max(ctypes.c_int32(int(irq)).value for irq in irq_list) < 0: test.fail("%s's irq is not correct." % device_name) if params.get("msi_cmd"): error_context.context("Disable MSI in guest", logging.info) hwid_msi = win_dev.get_hwids(session, device_name, devcon_folder, login_timeout)[0] session.cmd(params["msi_cmd"] % (hwid_msi, 0)) session = vm.reboot(session=session) error_context.context("Check %s's irq number" % device_name, logging.info) irq_list = irq_check(session, device_name, devcon_folder) irq_nums = len(irq_list) if not irq_nums == 1 and \ min(ctypes.c_int32(int(irq)).value for irq in irq_list) > 0: test.fail("%s's irq is not correct." % device_name) # prepare test data guest_path = (tmp_dir + "src-%s" % utils_misc.generate_random_string(8)) host_path = os.path.join(test.tmpdir, "tmp-%s" % utils_misc.generate_random_string(8)) logging.info("Test setup: Creating %dMB file on host", filesize) process.run(dd_cmd % host_path, shell=True) try: src_md5 = crypto.hash_file(host_path, algorithm="md5") logging.info("md5 value of data from src: %s", src_md5) # transfer data error_context.context("Transfer data from host to %s" % vm.name, logging.info) vm.copy_files_to(host_path, guest_path) dst_md5 = get_file_md5sum(guest_path, session, timeout=file_md5_check_timeout) logging.info("md5 value of data in %s: %s", vm.name, dst_md5) if dst_md5 != src_md5: test.fail("File changed after transfer host -> %s" % vm.name) finally: os.remove(host_path) session.cmd(delete_cmd % guest_path, timeout=login_timeout, ignore_all_errors=True) session.close()
def run_file_transfer(test, params, env): """ Transfer a file back and forth between host and guest. 1) Boot up a VM. 2) Create a large file by dd on host. 3) Copy this file from host to guest. 4) Copy this file from guest to host. 5) Check if file transfers ended good. :param test: QEMU test object. :param params: Dictionary with the test parameters. :param env: Dictionary with test environment. """ vm = env.get_vm(params["main_vm"]) vm.verify_alive() login_timeout = int(params.get("login_timeout", 360)) error.context("Login to guest", logging.info) session = vm.wait_for_login(timeout=login_timeout) dir_name = test.tmpdir transfer_timeout = int(params.get("transfer_timeout")) transfer_type = params.get("transfer_type") tmp_dir = params.get("tmp_dir", "/tmp/") clean_cmd = params.get("clean_cmd", "rm -f") filesize = int(params.get("filesize", 4000)) count = int(filesize / 10) if count == 0: count = 1 host_path = os.path.join(dir_name, "tmp-%s" % utils_misc.generate_random_string(8)) host_path2 = host_path + ".2" cmd = "dd if=/dev/zero of=%s bs=10M count=%d" % (host_path, count) guest_path = (tmp_dir + "file_transfer-%s" % utils_misc.generate_random_string(8)) try: error.context("Creating %dMB file on host" % filesize, logging.info) utils.run(cmd) if transfer_type != "remote": raise error.TestError("Unknown test file transfer mode %s" % transfer_type) error.context("Transferring file host -> guest," " timeout: %ss" % transfer_timeout, logging.info) t_begin = time.time() vm.copy_files_to(host_path, guest_path, timeout=transfer_timeout) t_end = time.time() throughput = filesize / (t_end - t_begin) logging.info("File transfer host -> guest succeed, " "estimated throughput: %.2fMB/s", throughput) error.context("Transferring file guest -> host," " timeout: %ss" % transfer_timeout, logging.info) t_begin = time.time() vm.copy_files_from(guest_path, host_path2, timeout=transfer_timeout) t_end = time.time() throughput = filesize / (t_end - t_begin) logging.info("File transfer guest -> host succeed, " "estimated throughput: %.2fMB/s", throughput) error.context("Compare md5sum between original file and" " transferred file", logging.info) if (utils.hash_file(host_path, method="md5") != utils.hash_file(host_path2, method="md5")): raise error.TestFail("File changed after transfer host -> guest " "and guest -> host") finally: logging.info('Cleaning temp file on guest') try: session.cmd("%s %s" % (clean_cmd, guest_path)) except aexpect.ShellError, detail: logging.warn("Could not remove temp files in guest: '%s'", detail) logging.info('Cleaning temp files on host') try: os.remove(host_path) os.remove(host_path2) except OSError: pass session.close()
if expect_mtype not in actual_mtype: fail_log += " Assigned to VM: '%s' \n" % expect_mtype fail_log += " Reported by OS: '%s'" % actual_mtype f_fail.append(fail_log) logging.error(fail_log) else: logging.info("MachineType check pass. Expected: %s, Actual: %s" % (expect_mtype, actual_mtype)) return f_fail if params.get("catch_serial_cmd") is not None: length = int(params.get("length", "20")) id_leng = random.randint(0, length) drive_serial = "" convert_str = "!\"#$%&\'()*+./:;<=>?@[\\]^`{|}~" drive_serial = utils_misc.generate_random_string(id_leng, ignore_str=",", convert_str=convert_str) params["drive_serial"] = drive_serial params["start_vm"] = "yes" vm = params["main_vm"] vm_params = params.object_params(vm) env_process.preprocess_vm(test, vm_params, env, vm) vm = env.get_vm(vm) else: vm = env.get_vm(params["main_vm"]) vm.verify_alive() timeout = int(params.get("login_timeout", 360)) chk_timeout = int(params.get("chk_timeout", 240)) session = vm.wait_for_login(timeout=timeout)
def run(test, params, env): """ Convert a remote vm to remote ovirt node. """ for v in list(params.values()): if "V2V_EXAMPLE" in v: test.cancel("Please set real value for %s" % v) vm_name = params.get("main_vm") target = params.get("target") hypervisor = params.get("hypervisor") input_mode = params.get("input_mode") storage = params.get('storage') storage_name = params.get('storage_name') network = params.get('network') bridge = params.get('bridge') source_user = params.get("username", "root") xen_ip = params.get("xen_hostname") xen_pwd = params.get("xen_pwd") vpx_ip = params.get("vpx_hostname") vpx_pwd = params.get("vpx_pwd") vpx_passwd_file = params.get("vpx_passwd_file") vpx_dc = params.get("vpx_dc") esx_ip = params.get("esx_hostname") address_cache = env.get('address_cache') v2v_opts = params.get("v2v_opts") v2v_timeout = int(params.get('v2v_timeout', 1200)) # for construct rhv-upload option in v2v cmd output_method = params.get("output_method") rhv_upload_opts = params.get("rhv_upload_opts") # for get ca.crt file from ovirt engine rhv_passwd = params.get("rhv_upload_passwd") rhv_passwd_file = params.get("rhv_upload_passwd_file") ovirt_engine_passwd = params.get("ovirt_engine_password") ovirt_hostname = params.get("ovirt_engine_url").split('/')[2] ovirt_ca_file_path = params.get("ovirt_ca_file_path") local_ca_file_path = params.get("local_ca_file_path") # create different sasl_user name for different job params.update({ 'sasl_user': params.get("sasl_user") + utils_misc.generate_random_string(3) }) logging.info('sals user name is %s' % params.get("sasl_user")) # Prepare step for different hypervisor if hypervisor == "esx": source_ip = vpx_ip source_pwd = vpx_pwd # Create password file to access ESX hypervisor with open(vpx_passwd_file, 'w') as f: f.write(vpx_pwd) elif hypervisor == "xen": source_ip = xen_ip source_pwd = xen_pwd # Set up ssh access using ssh-agent and authorized_keys ssh_key.setup_ssh_key(source_ip, source_user, source_pwd) try: utils_misc.add_identities_into_ssh_agent() except: process.run("ssh-agent -k") test.error("Fail to setup ssh-agent") elif hypervisor == "kvm": source_ip = None source_pwd = None else: test.cancel("Unspported hypervisor: %s" % hypervisor) if output_method == 'rhv_upload': # Create password file for '-o rhv_upload' to connect to ovirt with open(rhv_passwd_file, 'w') as f: f.write(rhv_passwd) # Copy ca file from ovirt to local remote.scp_from_remote(ovirt_hostname, 22, 'root', ovirt_engine_passwd, ovirt_ca_file_path, local_ca_file_path) # Create libvirt URI v2v_uri = utils_v2v.Uri(hypervisor) remote_uri = v2v_uri.get_uri(source_ip, vpx_dc, esx_ip) logging.debug("libvirt URI for converting: %s", remote_uri) # Make sure the VM exist before convert v2v_virsh = None close_virsh = False if hypervisor == 'kvm': v2v_virsh = virsh else: virsh_dargs = { 'uri': remote_uri, 'remote_ip': source_ip, 'remote_user': source_user, 'remote_pwd': source_pwd, 'debug': True } v2v_virsh = virsh.VirshPersistent(**virsh_dargs) close_virsh = True try: if not v2v_virsh.domain_exists(vm_name): test.error("VM '%s' not exist" % vm_name) finally: if close_virsh: v2v_virsh.close_session() # Create SASL user on the ovirt host user_pwd = "[['%s', '%s']]" % (params.get("sasl_user"), params.get("sasl_pwd")) v2v_sasl = utils_sasl.SASL(sasl_user_pwd=user_pwd) v2v_sasl.server_ip = params.get("remote_ip") v2v_sasl.server_user = params.get('remote_user') v2v_sasl.server_pwd = params.get('remote_pwd') v2v_sasl.setup(remote=True) # Maintain a single params for v2v to avoid duplicate parameters v2v_params = { 'target': target, 'hypervisor': hypervisor, 'main_vm': vm_name, 'input_mode': input_mode, 'network': network, 'bridge': bridge, 'storage': storage, 'hostname': source_ip, 'new_name': vm_name + utils_misc.generate_random_string(3), 'output_method': output_method, 'storage_name': storage_name } if vpx_dc: v2v_params.update({"vpx_dc": vpx_dc}) if esx_ip: v2v_params.update({"esx_ip": esx_ip}) if v2v_opts: v2v_params.update({"v2v_opts": v2v_opts}) if rhv_upload_opts: v2v_params.update({"rhv_upload_opts": rhv_upload_opts}) output_format = params.get('output_format') # output_format will be set to 'raw' in utils_v2v.v2v_cmd if it's None if output_format: v2v_params.update({'output_format': output_format}) # Set libguestfs environment variable if hypervisor in ('xen', 'kvm'): os.environ['LIBGUESTFS_BACKEND'] = 'direct' try: # Execute virt-v2v command v2v_ret = utils_v2v.v2v_cmd(v2v_params) logging.debug("virt-v2v verbose messages:\n%s", v2v_ret) if v2v_ret.exit_status != 0: test.fail("Convert VM failed") params['main_vm'] = v2v_params['new_name'] logging.info("output_method is %s" % output_method) # Import the VM to oVirt Data Center from export domain, and start it if not utils_v2v.import_vm_to_ovirt( params, address_cache, timeout=v2v_timeout): test.error("Import VM failed") # Check all checkpoints after convert vmchecker = VMChecker(test, params, env) ret = vmchecker.run() # Other checks err_list = [] os_list = [ 'win8', 'win8.1', 'win10', 'win2012', 'win2012r2', 'win2008' ] win_version = ['6.2', '6.3', '10.0', '6.2', '6.3'] os_map = dict(list(zip(os_list, win_version))) vm_arch = params.get('vm_arch') os_ver = params.get('os_version') if os_ver in os_list: vga_log = 'The guest will be configured to use a basic VGA ' \ 'display driver' if re.search(vga_log, v2v_ret.stdout): logging.debug('Found vga log') else: err_list.append('Not find vga log') if os_ver != 'win2008': qxl_warn = 'virt-v2v: warning: there is no QXL driver for ' \ 'this version of Windows \(%s[.\s]*?%s\)' %\ (os_map[os_ver], vm_arch) if re.search(qxl_warn, v2v_ret.stdout): logging.debug('Found QXL warning') else: err_list.append('Not find QXL warning') ret.extend(err_list) if len(ret) == 0: logging.info("All checkpoints passed") else: test.fail("%d checkpoints failed: %s" % (len(ret), ret)) finally: vmcheck = utils_v2v.VMCheck(test, params, env) vmcheck.cleanup() if v2v_sasl: v2v_sasl.cleanup() if hypervisor == "xen": process.run("ssh-agent -k") tmpfiles = [vpx_passwd_file, rhv_passwd_file, local_ca_file_path] for i in [x for x in tmpfiles if x and os.path.exists(x)]: os.remove(i)
def run(test, params, env): """ Test command: virsh net-dhcp-leases 1. Create a new network and run virsh command to check dhcp leases info. 2. Attach an interface before or after start the domain, then check the dhcp leases info. 3. Clean the environment. """ vm_name = params.get("main_vm") vm = env.get_vm(vm_name) net_name = params.get("net_name", "default") net_option = params.get("net_option", "") status_error = "yes" == params.get("status_error", "no") prepare_net = "yes" == params.get("prepare_net", "yes") hotplug_iface = "yes" == params.get("hotplug_interface", "no") filter_by_mac = "yes" == params.get("filter_by_mac", "no") invalid_mac = "yes" == params.get("invalid_mac", "no") expect_msg = params.get("leases_err_msg") # Generate a random string as the MAC address nic_mac = None if invalid_mac: nic_mac = utils_misc.generate_random_string(17) # Command won't fail on old libvirt if not libvirt_version.version_compare(1, 3, 1) and invalid_mac: logging.debug("Reset case to positive as BZ#1261432") status_error = False def create_network(): """ Create a network """ net_ip_addr = params.get("net_ip_addr", "192.168.200.1") net_ip_netmask = params.get("net_ip_netmask", "255.255.255.0") net_dhcp_start = params.get("net_dhcp_start", "192.168.200.2") net_dhcp_end = params.get("net_dhcp_end", "192.168.200.254") netxml = network_xml.NetworkXML() netxml.name = net_name netxml.forward = {'mode': "nat"} ipxml = network_xml.IPXML() ipxml.address = net_ip_addr ipxml.netmask = net_ip_netmask ipxml.dhcp_ranges = {'start': net_dhcp_start, "end": net_dhcp_end} netxml.set_ip(ipxml) netxml.create() def get_net_dhcp_leases(output): """ Return the dhcp lease info in a list """ leases = [] lines = output.splitlines() if not lines: return leases try: pat = r"\S+\ ?\S+\ ?\S+\ ?\S+|\S+" keys = re.findall(pat, lines[0]) for line in lines[2:]: values = re.findall(pat, line) leases.append(dict(list(zip(keys, values)))) return leases except Exception: test.error("Fail to parse output: %s" % output) def get_ip_by_mac(mac_addr, try_dhclint=False, timeout=120): """ Get interface IP address by given MAC addrss. If try_dhclint is True, then try to allocate IP addrss for the interface. """ session = vm.wait_for_login(login_nic_index, timeout=timeout, serial=True) def f(): return utils_net.get_guest_ip_addr(session, mac_addr) try: ip_addr = utils_misc.wait_for(f, 10) if ip_addr is None: iface_name = utils_net.get_linux_ifname(session, mac_addr) if try_dhclint: session.cmd("dhclient %s" % iface_name) ip_addr = utils_misc.wait_for(f, 10) else: # No IP for the interface, just print the interface name logging.warn( "Find '%s' with MAC address '%s', " "but which has no IP address", iface_name, mac_addr) finally: session.close() return ip_addr def check_net_lease(net_leases, expected_find=True): """ Check the dhcp lease info. """ if not net_leases: if expected_find: test.fail("Lease info is empty") else: logging.debug("No dhcp lease info find as expected") else: if not expected_find: test.fail("Find unexpected dhcp lease info: %s" % net_leases) find_mac = False for net_lease in net_leases: net_mac = net_lease['MAC address'] net_ip = net_lease['IP address'][:-3] if vm_xml.VMXML.get_iface_by_mac(vm_name, net_mac): find_mac = True logging.debug("Find '%s' in domain XML", net_mac) else: logging.debug("Not find '%s' in domain XML", net_mac) continue iface_ip = get_ip_by_mac(net_mac) if iface_ip and iface_ip != net_ip: test.fail("Address '%s' is not expected" % iface_ip) if expected_find and not find_mac: test.fail("No matched MAC address") vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) vmxml_backup = vmxml.copy() if vm.is_alive(): vm.destroy(gracefully=False) login_nic_index = 0 new_nic_index = 0 # Cleanup dirty dnsmaq, firstly get all network,and destroy all networks except # default net_state = virsh.net_state_dict(only_names=True) logging.debug( "current networks: %s, destroy and undefine networks " "except default!", net_state) for net in net_state: if net != "default": virsh.net_destroy(net) virsh.net_undefine(net) cmd = "ps aux|grep dnsmasq|grep -v grep | grep -v default | awk '{print $2}'" pid_list = results_stdout_52lts(process.run( cmd, shell=True)).strip().split('\n') for pid in pid_list: utils_misc.safe_kill(pid, signal.SIGKILL) # Create new network if prepare_net: create_network() nets = virsh.net_state_dict() if net_name not in list(nets.keys()) and not status_error: test.error("Not find network '%s'" % net_name) expected_find = False try: result = virsh.net_dhcp_leases(net_name, mac=nic_mac, options=net_option, debug=True, ignore_status=True) utlv.check_exit_status(result, status_error) lease = get_net_dhcp_leases(result.stdout.strip()) check_net_lease(lease, expected_find) if not status_error: iface_mac = utils_net.generate_mac_address_simple() if filter_by_mac: nic_mac = iface_mac op = "--type network --model virtio --source %s --mac %s" \ % (net_name, iface_mac) nic_params = { 'mac': iface_mac, 'nettype': 'bridge', 'ip_version': 'ipv4' } login_timeout = 120 if not hotplug_iface: op += " --config" virsh.attach_interface(vm_name, option=op, debug=True, ignore_status=False) vm.add_nic(**nic_params) vm.start() new_nic_index = vm.get_nic_index_by_mac(iface_mac) if new_nic_index > 0: login_nic_index = new_nic_index else: vm.start() # wait for VM start before hotplug interface vm.wait_for_serial_login() virsh.attach_interface(vm_name, option=op, debug=True, ignore_status=False) vm.add_nic(**nic_params) # As VM already started, so the login timeout could be shortened login_timeout = 10 new_interface_ip = get_ip_by_mac(iface_mac, try_dhclint=True, timeout=login_timeout) # Allocate IP address for the new interface may fail, so only # check the result if get new IP address if new_interface_ip: expected_find = True result = virsh.net_dhcp_leases(net_name, mac=nic_mac, debug=False, ignore_status=True) utlv.check_exit_status(result, status_error) lease = get_net_dhcp_leases(result.stdout.strip()) check_net_lease(lease, expected_find) else: if expect_msg: utlv.check_result(result, expect_msg.split(';')) finally: # Delete the new attached interface if new_nic_index > 0: vm.del_nic(new_nic_index) if vm.is_alive(): vm.destroy(gracefully=False) vmxml_backup.sync() if prepare_net: virsh.net_destroy(net_name)
def run(test, params, env): """ Hotplug/unhotplug virtio-vsock device 1. Boot guest without virtio-vsock-pci device 2. Hotplug virtio-vsock device 3. Check device inside guest(lspci/dmesg) 4. Transfer data from guest to host 5. Unplug virtio-vsock device 6. Cancel the vsock process on host 7. Reboot guest :param test: QEMU test object :param params: Dictionary with the test parameters :param env: Dictionary with test environment """ linux_modules.load_module('vhost_vsock') vm = env.get_vm(params['main_vm']) session = vm.wait_for_login() guest_cid = utils_vsock.get_guest_cid(3) vsock_id = 'hotplugged_vsock' vsock_params = {'id': vsock_id, 'guest-cid': guest_cid} vsock_test_tool = params["vsock_test_tool"] if '-mmio:' in params.get('machine_type'): dev_vsock = qdevices.QDevice('vhost-vsock-device', vsock_params) elif params.get('machine_type').startswith("s390"): vsock_params['devno'] = params.get('devno') dev_vsock = qdevices.QDevice("vhost-vsock-ccw", vsock_params) else: dev_vsock = qdevices.QDevice('vhost-vsock-pci', vsock_params) vm.devices.simple_hotplug(dev_vsock, vm.monitor) error_context.context( 'Check vsock device exist in guest lspci and ' 'dmesg output.', logging.info) addr_pattern = params['addr_pattern'] device_pattern = params['device_pattern'] check_vsock_cmd = params.get('check_vsock_cmd', 'lspci') time.sleep(10) lspci_output = session.cmd_output(check_vsock_cmd) device_str = re.findall(r'%s\s%s' % (addr_pattern, device_pattern), lspci_output) if params.get('dmesg_check') == 'yes': if not device_str: test.fail('check_vsock_cmd failed, no device "%s"' % device_pattern) else: address = re.findall(addr_pattern, device_str[0])[0] chk_dmesg_cmd = 'dmesg' output = re.findall(address, session.cmd_output(chk_dmesg_cmd)) if not output: test.fail('dmesg failed, no info related to %s' % address) else: error_msg = '' for o in output: if re.search(r'fail|error', o, re.I): error_msg += '%s' % o break if error_msg: test.fail("dmesg check failed: %s" % error_msg) # Transfer data from guest to host try: if vsock_test_tool == "nc_vsock": tool_bin = vsock_test.compile_nc_vsock(test, vm, session) if vsock_test_tool == "ncat": tool_bin = path.find_command("ncat") tmp_file = "/tmp/vsock_file_%s" % utils_misc.generate_random_string(6) rec_session = vsock_test.send_data_from_guest_to_host(session, tool_bin, guest_cid, tmp_file, file_size=10000) vsock_negative_test.check_data_received(test, rec_session, tmp_file) vm.devices.simple_unplug(dev_vsock, vm.monitor) vsock_negative_test.kill_host_receive_process(test, rec_session) vsock_test.check_guest_vsock_conn_exit(test, session) finally: session.cmd_output("rm -f %s" % tmp_file) session.close() vm.reboot()
def run(test, params, env): """ Test virsh reset command """ if not virsh.has_help_command('reset'): raise error.TestNAError("This version of libvirt does not support " "the reset test") vm_name = params.get("main_vm", "virt-tests-vm1") vm_ref = params.get("reset_vm_ref") readonly = params.get("readonly", False) status_error = ("yes" == params.get("status_error", "no")) start_vm = ("yes" == params.get("start_vm")) vm = env.get_vm(vm_name) domid = vm.get_id() domuuid = vm.get_uuid() bef_pid = commands.getoutput("pidof -s qemu-kvm") if vm_ref == 'id': vm_ref = domid elif vm_ref == 'uuid': vm_ref = domuuid else: vm_ref = vm_name 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.") # change the disk cache to default vmxml_backup = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) def change_cache(vmxml, mode): """ Change the cache mode :param vmxml: instance of VMXML :param mode: cache mode you want to change """ devices = vmxml.devices disk_index = devices.index(devices.by_device_tag('disk')[0]) disk = devices[disk_index] disk_driver = disk.driver disk_driver['cache'] = mode disk.driver = disk_driver vmxml.devices = devices vmxml.define() try: change_cache(vmxml_backup.copy(), "default") tmpfile = "/home/%s" % utils_misc.generate_random_string(6) logging.debug("tmpfile is %s", tmpfile) if start_vm: session = vm.wait_for_login() session.cmd("rm -rf %s && sync" % tmpfile) status = session.get_command_status("touch %s && ls %s" % (tmpfile, tmpfile)) if status == 0: logging.info("Succeed generate file %s", tmpfile) else: raise error.TestFail("Touch command failed!") # record the pid before reset for compare output = virsh.reset(vm_ref, readonly=readonly, unprivileged_user=unprivileged_user, uri=uri, ignore_status=True, debug=True) if output.exit_status != 0: if status_error: logging.info("Failed to reset guest as expected, Error:%s.", output.stderr) return else: raise error.TestFail("Failed to reset guest, Error:%s." % output.stderr) elif status_error: raise error.TestFail("Expect fail, but succeed indeed.") session.close() session = vm.wait_for_login() status = session.get_command_status("ls %s" % tmpfile) if status == 0: raise error.TestFail("Fail to reset guest, tmpfile still exist!") else: aft_pid = commands.getoutput("pidof -s qemu-kvm") if bef_pid == aft_pid: logging.info("Succeed to check reset, tmpfile is removed.") else: raise error.TestFail("Domain pid changed after reset!") session.close() finally: vmxml_backup.sync()
def run_format_disk(test, params, env): """ Format guest disk: 1) Boot guest with second disk 2) Login to the guest 3) Get disk list in guest 4) Create partition on disk 5) Format the disk 6) Mount the disk 7) Read in the file to see whether content has changed 8) Umount the disk (Optional) 9) Check dmesg output in guest (Optional) :param test: QEMU test object :param params: Dictionary with the test parameters :param env: Dictionary with test environment. """ vm = env.get_vm(params["main_vm"]) vm.verify_alive() error.context("Login to the guest", logging.info) session = vm.wait_for_login(timeout=int(params.get("login_timeout", 360))) cmd_timeout = int(params.get("cmd_timeout", 360)) # Create a partition on disk create_partition_cmd = params.get("create_partition_cmd") if create_partition_cmd: has_dispart = re.findall("diskpart", create_partition_cmd, re.I) if (params.get("os_type") == 'windows' and has_dispart): error.context("Get disk list in guest") list_disk_cmd = params.get("list_disk_cmd") s, o = session.cmd_status_output(list_disk_cmd, timeout=cmd_timeout) for i in re.findall("Disk*.(\d+)\s+Offline", o): error.context("Set disk '%s' to online status" % i, logging.info) set_online_cmd = params.get("set_online_cmd") % i s, o = session.cmd_status_output(set_online_cmd, timeout=cmd_timeout) if s != 0: raise error.TestFail("Can not set disk online %s" % o) error.context("Create partition on disk", logging.info) s, o = session.cmd_status_output(create_partition_cmd, timeout=cmd_timeout) if s != 0: raise error.TestFail("Failed to create partition with error: %s" % o) logging.info("Output of command of create partition on disk: %s" % o) format_cmd = params.get("format_cmd") if format_cmd: error.context("Format the disk with cmd '%s'" % format_cmd, logging.info) s, o = session.cmd_status_output(format_cmd, timeout=cmd_timeout) if s != 0: raise error.TestFail("Failed to format with error: %s" % o) logging.info("Output of format disk command: %s" % o) mount_cmd = params.get("mount_cmd") if mount_cmd: error.context("Mount the disk with cmd '%s'" % mount_cmd, logging.info) s, o = session.cmd_status_output(mount_cmd, timeout=cmd_timeout) if s != 0: raise error.TestFail("Failed to mount with error: %s" % o) logging.info("Output of mount disk command: %s" % o) testfile_name = params.get("testfile_name") if testfile_name: error.context("Write some random string to test file", logging.info) ranstr = utils_misc.generate_random_string(100) writefile_cmd = params["writefile_cmd"] writefile_cmd = writefile_cmd % (ranstr, testfile_name) s, o = session.cmd_status_output(writefile_cmd, timeout=cmd_timeout) if s != 0: raise error.TestFail("Write to file error: %s" % o) error.context("Read in the file to see whether content has changed", logging.info) readfile_cmd = params["readfile_cmd"] readfile_cmd = readfile_cmd % testfile_name s, o = session.cmd_status_output(readfile_cmd, timeout=cmd_timeout) if s != 0: raise error.TestFail("Read file error: %s" % o) if o.strip() != ranstr: raise error.TestFail("The content written to file has changed") umount_cmd = params.get("umount_cmd") if umount_cmd: error.context("Unmounting disk(s) after file write/read operation") session.cmd(umount_cmd) output = "" try: output = session.cmd("dmesg -c") error.context("Checking if there are I/O error messages in dmesg") except aexpect.ShellCmdError: pass io_error_msg = [] for line in output.splitlines(): if "Buffer I/O error" in line: io_error_msg.append(line) if re.search("reset \w+ speed USB device", line): io_error_msg.append(line) if io_error_msg: e_msg = "IO error found on guest's dmesg when formatting USB device" logging.error(e_msg) for line in io_error_msg: logging.error(line) raise error.TestFail(e_msg) session.close()
def generate_serial_num(): length = int(params.get("length", "10")) id_leng = random.randint(6, length) ignore_str = ",!\"#$%&\'()*+./:;<=>?@[\\]^`{|}~" return utils_misc.generate_random_string(id_leng, ignore_str)
def test_libvirt(self): style = self.get_style('libvirt', utils_misc.generate_random_string(16)) self.assertEqual(style['container_class'], utils_net.LibvirtIface) self.assert_(issubclass(style['container_class'], utils_net.VirtIface))
def run(test, params, env): """ Test command: virsh blockcommit <domain> <path> 1) Prepare test environment. 2) Commit changes from a snapshot down to its backing image. 3) Recover test environment. 4) Check result. """ def make_disk_snapshot(postfix_n, snapshot_take, is_check_snapshot_tree=False, is_create_image_file_in_vm=False): """ Make external snapshots for disks only. :param postfix_n: postfix option :param snapshot_take: snapshots taken. :param is_create_image_file_in_vm: create image file in VM. """ # Add all disks into command line. disks = vm.get_disk_devices() # Make three external snapshots for disks only for count in range(1, snapshot_take): options = "%s_%s %s%s-desc " % (postfix_n, count, postfix_n, count) options += "--disk-only --atomic --no-metadata" if needs_agent: options += " --quiesce" for disk in disks: disk_detail = disks[disk] basename = os.path.basename(disk_detail['source']) # Remove the original suffix if any, appending # ".postfix_n[0-9]" diskname = basename.split(".")[0] snap_name = "%s.%s%s" % (diskname, postfix_n, count) disk_external = os.path.join(tmp_dir, snap_name) snapshot_external_disks.append(disk_external) options += " %s,snapshot=external,file=%s" % (disk, disk_external) if is_check_snapshot_tree: options = options.replace("--no-metadata", "") cmd_result = virsh.snapshot_create_as(vm_name, options, ignore_status=True, debug=True) status = cmd_result.exit_status if status != 0: test.fail("Failed to make snapshots for disks!") if is_create_image_file_in_vm: create_file_cmd = "dd if=/dev/urandom of=/mnt/snapshot_%s.img bs=1M count=2" % count session.cmd_status_output(create_file_cmd) created_image_files_in_vm.append("snapshot_%s.img" % count) # Create a file flag in VM after each snapshot flag_file = tempfile.NamedTemporaryFile(prefix=("snapshot_test_"), dir="/tmp") file_path = flag_file.name flag_file.close() status, output = session.cmd_status_output("touch %s" % file_path) if status: test.fail("Touch file in vm failed. %s" % output) snapshot_flag_files.append(file_path) def check_snapshot_tree(): """ Check whether predefined snapshot names are equals to snapshot names by virsh snapshot-list --tree """ predefined_snapshot_name_list = [] for count in range(1, snapshot_take): predefined_snapshot_name_list.append("%s_%s" % (postfix_n, count)) snapshot_list_cmd = "virsh snapshot-list %s --tree" % vm_name result_output = process.run(snapshot_list_cmd, ignore_status=True, shell=True).stdout_text virsh_snapshot_name_list = [] for line in result_output.rsplit("\n"): strip_line = line.strip() if strip_line and "|" not in strip_line: virsh_snapshot_name_list.append(strip_line) # Compare two lists in their order and values, all need to be same. compare_list = [ out_p for out_p, out_v in zip(predefined_snapshot_name_list, virsh_snapshot_name_list) if out_p not in out_v ] if compare_list: test.fail("snapshot tree not correctly returned.") # If check_snapshot_tree is True, check snapshot tree output. if is_check_snapshot_tree: check_snapshot_tree() def get_first_disk_source(): """ Get disk source of first device :return: first disk of first device. """ first_device = vm.get_first_disk_devices() first_disk_src = first_device['source'] return first_disk_src def make_relative_path_backing_files(pre_set_root_dir=None): """ Create backing chain files of relative path. :param pre_set_root_dir: preset root dir :return: absolute path of top active file """ first_disk_source = get_first_disk_source() basename = os.path.basename(first_disk_source) if pre_set_root_dir is None: root_dir = os.path.dirname(first_disk_source) else: root_dir = pre_set_root_dir cmd = "mkdir -p %s" % os.path.join(root_dir, '{b..d}') ret = process.run(cmd, shell=True) libvirt.check_exit_status(ret) # Make three external relative path backing files. backing_file_dict = collections.OrderedDict() backing_file_dict["b"] = "../%s" % basename backing_file_dict["c"] = "../b/b.img" backing_file_dict["d"] = "../c/c.img" if pre_set_root_dir: backing_file_dict["b"] = "%s" % first_disk_source backing_file_dict["c"] = "%s/b/b.img" % root_dir backing_file_dict["d"] = "%s/c/c.img" % root_dir disk_format = params.get("disk_format", "qcow2") for key, value in list(backing_file_dict.items()): backing_file_path = os.path.join(root_dir, key) cmd = ( "cd %s && qemu-img create -f %s -o backing_file=%s,backing_fmt=%s %s.img" % (backing_file_path, "qcow2", value, disk_format, key)) ret = process.run(cmd, shell=True) disk_format = "qcow2" libvirt.check_exit_status(ret) return os.path.join(backing_file_path, "d.img") def check_chain_backing_files(disk_src_file, expect_backing_file=False): """ Check backing chain files of relative path after blockcommit. :param disk_src_file: first disk src file. :param expect_backing_file: whether it expect to have backing files. """ first_disk_source = get_first_disk_source() # Validate source image need refer to original one after active blockcommit if not expect_backing_file and disk_src_file not in first_disk_source: test.fail( "The disk image path:%s doesn't include the origin image: %s" % (first_disk_source, disk_src_file)) # Validate source image doesn't have backing files after active blockcommit cmd = "qemu-img info %s --backing-chain" % first_disk_source if qemu_img_locking_feature_support: cmd = "qemu-img info -U %s --backing-chain" % first_disk_source ret = process.run(cmd, shell=True).stdout_text.strip() if expect_backing_file: if 'backing file' not in ret: test.fail("The disk image doesn't have backing files") else: logging.debug("The actual qemu-img output:%s\n", ret) else: if 'backing file' in ret: test.fail("The disk image still have backing files") else: logging.debug("The actual qemu-img output:%s\n", ret) def create_reuse_external_snapshots(pre_set_root_dir=None): """ Create reuse external snapshots :param pre_set_root_dir: preset root directory :return: absolute path of base file """ if pre_set_root_dir is None: first_disk_source = get_first_disk_source() basename = os.path.basename(first_disk_source) root_dir = os.path.dirname(first_disk_source) else: root_dir = pre_set_root_dir meta_options = " --reuse-external --disk-only --no-metadata" # Make three external relative path backing files. backing_file_dict = collections.OrderedDict() backing_file_dict["b"] = "b.img" backing_file_dict["c"] = "c.img" backing_file_dict["d"] = "d.img" for key, value in list(backing_file_dict.items()): backing_file_path = os.path.join(root_dir, key) external_snap_shot = "%s/%s" % (backing_file_path, value) snapshot_external_disks.append(external_snap_shot) options = "%s --diskspec %s,file=%s" % (meta_options, disk_target, external_snap_shot) cmd_result = virsh.snapshot_create_as(vm_name, options, ignore_status=False, debug=True) libvirt.check_exit_status(cmd_result) logging.debug('reuse external snapshots:%s' % snapshot_external_disks) return root_dir def check_file_in_vm(): """ Check whether certain image files exists in VM internal. """ for img_file in created_image_files_in_vm: status, output = session.cmd_status_output("ls -l /mnt/%s" % img_file) logging.debug(output) if status: test.fail( "blockcommit from top to base failed when ls image file in VM: %s" % output) def do_blockcommit_pivot_repeatedly(): """ Validate bugzilla:https://bugzilla.redhat.com/show_bug.cgi?id=1857735 """ # Make external snapshot,pivot and delete snapshot file repeatedly. tmp_snapshot_name = "external_snapshot_" + "repeated.qcow2" block_target = 'vda' for count in range(0, 5): options = "%s " % tmp_snapshot_name options += "--disk-only --atomic" disk_external = os.path.join(tmp_dir, tmp_snapshot_name) options += " --diskspec %s,snapshot=external,file=%s" % ( block_target, disk_external) virsh.snapshot_create_as(vm_name, options, ignore_status=False, debug=True) virsh.blockcommit(vm_name, block_target, " --active --pivot ", ignore_status=False, debug=True) virsh.snapshot_delete(vm_name, tmp_snapshot_name, " --metadata") libvirt.delete_local_disk('file', disk_external) # MAIN TEST CODE ### # Process cartesian parameters vm_name = params.get("main_vm") vm = env.get_vm(vm_name) snapshot_take = int(params.get("snapshot_take", '0')) vm_state = params.get("vm_state", "running") needs_agent = "yes" == params.get("needs_agent", "yes") replace_vm_disk = "yes" == params.get("replace_vm_disk", "no") top_inactive = ("yes" == params.get("top_inactive")) with_timeout = ("yes" == params.get("with_timeout_option", "no")) cmd_timeout = params.get("cmd_timeout", "1") status_error = ("yes" == params.get("status_error", "no")) base_option = params.get("base_option", "none") middle_base = "yes" == params.get("middle_base", "no") pivot_opt = "yes" == params.get("pivot_opt", "no") snap_in_mirror = "yes" == params.get("snap_in_mirror", "no") snap_in_mirror_err = "yes" == params.get("snap_in_mirror_err", "no") with_active_commit = "yes" == params.get("with_active_commit", "no") multiple_chain = "yes" == params.get("multiple_chain", "no") virsh_dargs = {'debug': True} check_snapshot_tree = "yes" == params.get("check_snapshot_tree", "no") bandwidth = params.get("blockcommit_bandwidth", "") bandwidth_byte = "yes" == params.get("bandwidth_byte", "no") disk_target = params.get("disk_target", "vda") disk_format = params.get("disk_format", "qcow2") reuse_external_snapshot = "yes" == params.get("reuse_external_snapshot", "no") restart_vm_before_commit = "yes" == params.get("restart_vm_before_commit", "no") check_image_file_in_vm = "yes" == params.get("check_image_file_in_vm", "no") pre_set_root_dir = None blk_source_folder = None convert_qcow2_image_to_raw = "yes" == params.get( "convert_qcow2_image_to_raw", "no") repeatedly_do_blockcommit_pivot = "yes" == params.get( "repeatedly_do_blockcommit_pivot", "no") from_top_without_active_option = "yes" == params.get( "from_top_without_active_option", "no") top_to_middle_keep_overlay = "yes" == params.get( "top_to_middle_keep_overlay", "no") # Check whether qemu-img need add -U suboption since locking feature was added afterwards qemu-2.10 qemu_img_locking_feature_support = libvirt_storage.check_qemu_image_lock_support( ) backing_file_relative_path = "yes" == params.get( "backing_file_relative_path", "no") # Process domain disk device parameters disk_type = params.get("disk_type") disk_src_protocol = params.get("disk_source_protocol") restart_tgtd = params.get("restart_tgtd", 'no') vol_name = params.get("vol_name") tmp_dir = data_dir.get_tmp_dir() pool_name = params.get("pool_name", "gluster-pool") brick_path = os.path.join(tmp_dir, pool_name) if not top_inactive: if not libvirt_version.version_compare(1, 2, 4): test.cancel("live active block commit is not supported" " in current libvirt version.") # This is brought by new feature:block-dev if (libvirt_version.version_compare(6, 0, 0) and params.get("transport", "") == "rdma"): test.cancel("If blockdev is enabled, the transport protocol 'rdma' is " "not yet supported.") # A backup of original vm vmxml_backup = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) # Abort the test if there are snapshots already exsiting_snaps = virsh.snapshot_list(vm_name) if len(exsiting_snaps) != 0: test.fail("There are snapshots created for %s already" % vm_name) snapshot_external_disks = [] cmd_session = None # Prepare a blank params to confirm if delete the configure at the end of the test ceph_cfg = '' try: if disk_src_protocol == 'iscsi' and disk_type == 'block' and reuse_external_snapshot: first_disk = vm.get_first_disk_devices() pre_set_root_dir = os.path.dirname(first_disk['source']) if disk_src_protocol == 'iscsi' and disk_type == 'network': if not libvirt_version.version_compare(1, 0, 4): test.cancel("'iscsi' disk doesn't support in" " current libvirt version.") # Set vm xml and guest agent if replace_vm_disk: if disk_src_protocol == "rbd" and disk_type == "network": src_host = params.get("disk_source_host", "EXAMPLE_HOSTS") mon_host = params.get("mon_host", "EXAMPLE_MON_HOST") # Create config file if it doesn't exist ceph_cfg = ceph.create_config_file(mon_host) if src_host.count("EXAMPLE") or mon_host.count("EXAMPLE"): test.cancel("Please provide rbd host first.") params.update({ "disk_source_name": os.path.join( pool_name, 'rbd_' + utils_misc.generate_random_string(4) + '.img') }) if utils_package.package_install(["ceph-common"]): ceph.rbd_image_rm( mon_host, *params.get("disk_source_name").split('/')) else: test.error('Failed to install ceph-common to clean image.') if backing_file_relative_path: if vm.is_alive(): vm.destroy(gracefully=False) first_src_file = get_first_disk_source() blk_source_image = os.path.basename(first_src_file) blk_source_folder = os.path.dirname(first_src_file) replace_disk_image = make_relative_path_backing_files() params.update({ 'disk_source_name': replace_disk_image, 'disk_type': 'file', 'disk_src_protocol': 'file' }) vm.start() if convert_qcow2_image_to_raw: if vm.is_alive(): vm.destroy(gracefully=False) first_src_file = get_first_disk_source() blk_source_image = os.path.basename(first_src_file) blk_source_folder = os.path.dirname(first_src_file) blk_source_image_after_converted = "%s/converted_%s" % ( blk_source_folder, blk_source_image) # Convert the image from qcow2 to raw convert_disk_cmd = ("qemu-img convert" " -O %s %s %s" % (disk_format, first_src_file, blk_source_image_after_converted)) process.run(convert_disk_cmd, ignore_status=False, shell=True) params.update({ 'disk_source_name': blk_source_image_after_converted, 'disk_type': 'file', 'disk_src_protocol': 'file' }) libvirt.set_vm_disk(vm, params, tmp_dir) if needs_agent: vm.prepare_guest_agent() if repeatedly_do_blockcommit_pivot: do_blockcommit_pivot_repeatedly() # The first disk is supposed to include OS # We will perform blockcommit operation for it. first_disk = vm.get_first_disk_devices() blk_source = first_disk['source'] blk_target = first_disk['target'] snapshot_flag_files = [] created_image_files_in_vm = [] # get a vm session before snapshot session = vm.wait_for_login() # do snapshot postfix_n = 'snap' if reuse_external_snapshot: make_relative_path_backing_files(pre_set_root_dir) blk_source_folder = create_reuse_external_snapshots( pre_set_root_dir) else: make_disk_snapshot(postfix_n, snapshot_take, check_snapshot_tree, check_image_file_in_vm) basename = os.path.basename(blk_source) diskname = basename.split(".")[0] snap_src_lst = [blk_source] if multiple_chain: snap_name = "%s.%s1" % (diskname, postfix_n) snap_top = os.path.join(tmp_dir, snap_name) top_index = snapshot_external_disks.index(snap_top) + 1 omit_list = snapshot_external_disks[top_index:] vm.destroy(gracefully=False) vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) disk_xml = '' disk_xmls = vmxml.get_devices(device_type="disk") for disk in disk_xmls: if disk.get('device_tag') == 'disk': disk_xml = disk break vmxml.del_device(disk_xml) disk_dict = {'attrs': {'file': snap_top}} disk_xml.source = disk_xml.new_disk_source(**disk_dict) if libvirt_version.version_compare(6, 0, 0): bs_source = {'file': blk_source} bs_dict = { "type": params.get("disk_type", "file"), "format": { 'type': params.get("disk_format", "qcow2") } } new_bs = disk_xml.new_backingstore(**bs_dict) new_bs["source"] = disk_xml.backingstore.new_source( **bs_source) disk_xml.backingstore = new_bs vmxml.add_device(disk_xml) vmxml.sync() vm.start() session = vm.wait_for_login() postfix_n = 'new_snap' make_disk_snapshot(postfix_n, snapshot_take) snap_src_lst = [blk_source] snap_src_lst += snapshot_external_disks logging.debug("omit list is %s", omit_list) for i in omit_list: snap_src_lst.remove(i) else: # snapshot src file list snap_src_lst += snapshot_external_disks backing_chain = '' for i in reversed(list(range(snapshot_take))): if i == 0: backing_chain += "%s" % snap_src_lst[i] else: backing_chain += "%s -> " % snap_src_lst[i] logging.debug("The backing chain is: %s" % backing_chain) # check snapshot disk xml backingStore is expected vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) disks = vmxml.devices.by_device_tag('disk') disk_xml = None for disk in disks: if disk.target['dev'] != blk_target: continue else: if disk.device != 'disk': continue disk_xml = disk.xmltreefile logging.debug("the target disk xml after snapshot is %s", disk_xml) break if not disk_xml: test.fail("Can't find disk xml with target %s" % blk_target) elif libvirt_version.version_compare(1, 2, 4): # backingStore element introduced in 1.2.4 chain_lst = snap_src_lst[::-1] ret = check_chain_xml(disk_xml, chain_lst) if not ret: test.fail("Domain image backing chain check failed") # set blockcommit_options top_image = None blockcommit_options = "--wait --verbose" if with_timeout: blockcommit_options += " --timeout %s" % cmd_timeout if base_option == "shallow": blockcommit_options += " --shallow" elif base_option == "base": if middle_base: snap_name = "%s.%s1" % (diskname, postfix_n) blk_source = os.path.join(tmp_dir, snap_name) blockcommit_options += " --base %s" % blk_source if len(bandwidth): blockcommit_options += " --bandwidth %s" % bandwidth if bandwidth_byte: blockcommit_options += " --bytes" if top_inactive: snap_name = "%s.%s2" % (diskname, postfix_n) top_image = os.path.join(tmp_dir, snap_name) if reuse_external_snapshot: index = len(snapshot_external_disks) - 2 top_image = snapshot_external_disks[index] blockcommit_options += " --top %s" % top_image else: blockcommit_options += " --active" if pivot_opt: blockcommit_options += " --pivot" if from_top_without_active_option: blockcommit_options = blockcommit_options.replace("--active", "") if top_to_middle_keep_overlay: blockcommit_options = blockcommit_options.replace("--active", "") blockcommit_options = blockcommit_options.replace("--pivot", "") blockcommit_options += " --keep-overlay" if restart_vm_before_commit: top = 2 base = len(snapshot_external_disks) blockcommit_options = ( "--top %s[%d] --base %s[%d] --verbose --wait --keep-relative" % (disk_target, top, disk_target, base)) vm.destroy(gracefully=True) vm.start() if vm_state == "shut off": vm.destroy(gracefully=True) if with_active_commit: # inactive commit follow active commit will fail with bug 1135339 cmd = "virsh blockcommit %s %s --active --pivot" % (vm_name, blk_target) cmd_session = aexpect.ShellSession(cmd) if backing_file_relative_path: blockcommit_options = " --active --verbose --shallow --pivot --keep-relative" block_commit_index = snapshot_take expect_backing_file = False # Do block commit using --active for count in range(1, snapshot_take): res = virsh.blockcommit(vm_name, blk_target, blockcommit_options, **virsh_dargs) libvirt.check_exit_status(res, status_error) if top_inactive: vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) disk_xml = '' disk_xmls = vmxml.get_devices(device_type="disk") for disk in disk_xmls: if disk.get('device_tag') == 'disk': disk_xml = disk break top_index = 1 try: top_index = disk_xml.backingstore.index except AttributeError: pass else: top_index = int(top_index) block_commit_index = snapshot_take - 1 expect_backing_file = True for count in range(1, block_commit_index): # Do block commit with --wait if top_inactive if top_inactive: blockcommit_options = (" --wait --verbose --top vda[%d] " "--base vda[%d] --keep-relative" % (top_index, top_index + 1)) if not libvirt_version.version_compare(6, 0, 0): top_index = 1 else: top_index += 1 res = virsh.blockcommit(vm_name, blk_target, blockcommit_options, **virsh_dargs) libvirt.check_exit_status(res, status_error) check_chain_backing_files(blk_source_image, expect_backing_file) return if reuse_external_snapshot and not top_inactive: block_commit_index = len(snapshot_external_disks) - 1 for index in range(block_commit_index): # Do block commit with --shallow --wait external_blockcommit_options = ( " --shallow --wait --verbose --top %s " % (snapshot_external_disks[index])) res = virsh.blockcommit(vm_name, blk_target, external_blockcommit_options, **virsh_dargs) libvirt.check_exit_status(res, status_error) # Do blockcommit with top active result = virsh.blockcommit(vm_name, blk_target, blockcommit_options, **virsh_dargs) # Check status_error libvirt.check_exit_status(result, status_error) return # Start one thread to check the bandwidth in output if bandwidth and bandwidth_byte: bandwidth += 'B' pool = ThreadPool(processes=1) pool.apply_async( check_bandwidth_thread, (libvirt.check_blockjob, vm_name, blk_target, bandwidth, test)) # Run test case # Active commit does not support on rbd based disk with bug 1200726 result = virsh.blockcommit(vm_name, blk_target, blockcommit_options, **virsh_dargs) # Check status_error libvirt.check_exit_status(result, status_error) # Skip check chain file as per test case description if restart_vm_before_commit: return if check_image_file_in_vm: check_file_in_vm() if result.exit_status and status_error: return while True: vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) disks = vmxml.devices.by_device_tag('disk') for disk in disks: if disk.target['dev'] != blk_target: continue else: disk_xml = disk.xmltreefile break if not top_inactive: disk_mirror = disk_xml.find('mirror') if '--pivot' not in blockcommit_options: if disk_mirror is not None: job_type = disk_mirror.get('job') job_ready = disk_mirror.get('ready') src_element = disk_mirror.find('source') disk_src_file = None for elem in ('file', 'name', 'dev'): elem_val = src_element.get(elem) if elem_val: disk_src_file = elem_val break err_msg = "blockcommit base source " err_msg += "%s not expected" % disk_src_file if '--shallow' in blockcommit_options: if not multiple_chain: if disk_src_file != snap_src_lst[2]: test.fail(err_msg) else: if disk_src_file != snap_src_lst[3]: test.fail(err_msg) else: if disk_src_file != blk_source: test.fail(err_msg) if libvirt_version.version_compare(1, 2, 7): # The job attribute mentions which API started the # operation since 1.2.7. if job_type != 'active-commit': test.fail("blockcommit job type '%s'" " not expected" % job_type) if job_ready != 'yes': # The attribute ready, if present, tracks # progress of the job: yes if the disk is known # to be ready to pivot, or, since 1.2.7, abort # or pivot if the job is in the process of # completing. continue else: logging.debug( "after active block commit job " "ready for pivot, the target disk" " xml is %s", disk_xml) break else: break else: break else: if disk_mirror is None: logging.debug(disk_xml) if "--shallow" in blockcommit_options: chain_lst = snap_src_lst[::-1] chain_lst.pop(0) ret = check_chain_xml(disk_xml, chain_lst) if not ret: test.fail("Domain image backing " "chain check failed") cmd_result = virsh.blockjob(vm_name, blk_target, '', ignore_status=True, debug=True) libvirt.check_exit_status(cmd_result) elif "--base" in blockcommit_options: chain_lst = snap_src_lst[::-1] base_index = chain_lst.index(blk_source) chain_lst = chain_lst[base_index:] ret = check_chain_xml(disk_xml, chain_lst) if not ret: test.fail("Domain image backing " "chain check failed") break else: # wait pivot after commit is synced continue else: logging.debug("after inactive commit the disk xml is: %s" % disk_xml) if libvirt_version.version_compare(1, 2, 4): if "--shallow" in blockcommit_options: chain_lst = snap_src_lst[::-1] chain_lst.remove(top_image) ret = check_chain_xml(disk_xml, chain_lst) if not ret: test.fail("Domain image backing chain " "check failed") elif "--base" in blockcommit_options: chain_lst = snap_src_lst[::-1] top_index = chain_lst.index(top_image) base_index = chain_lst.index(blk_source) val_tmp = [] for i in range(top_index, base_index): val_tmp.append(chain_lst[i]) for i in val_tmp: chain_lst.remove(i) ret = check_chain_xml(disk_xml, chain_lst) if not ret: test.fail("Domain image backing chain " "check failed") break else: break # Check flag files if not vm_state == "shut off" and not multiple_chain: for flag in snapshot_flag_files: status, output = session.cmd_status_output("cat %s" % flag) if status: test.fail("blockcommit failed: %s" % output) if not pivot_opt and snap_in_mirror: # do snapshot during mirror phase snap_path = "%s/%s.snap" % (tmp_dir, vm_name) snap_opt = "--disk-only --atomic --no-metadata " snap_opt += "vda,snapshot=external,file=%s" % snap_path snapshot_external_disks.append(snap_path) cmd_result = virsh.snapshot_create_as(vm_name, snap_opt, ignore_statues=True, debug=True) libvirt.check_exit_status(cmd_result, snap_in_mirror_err) finally: if vm.is_alive(): vm.destroy(gracefully=False) # Clean ceph image if used in test if 'mon_host' in locals(): if utils_package.package_install(["ceph-common"]): disk_source_name = params.get("disk_source_name") cmd = ("rbd -m {0} info {1} && rbd -m {0} rm " "{1}".format(mon_host, disk_source_name)) cmd_result = process.run(cmd, ignore_status=True, shell=True) logging.debug("result of rbd removal: %s", cmd_result) else: logging.debug('Failed to install ceph-common to clean ceph.') # Recover xml of vm. vmxml_backup.sync("--snapshots-metadata") # Remove ceph configure file if created if ceph_cfg: os.remove(ceph_cfg) if cmd_session: cmd_session.close() for disk in snapshot_external_disks: if os.path.exists(disk): os.remove(disk) if backing_file_relative_path or reuse_external_snapshot: libvirt.clean_up_snapshots(vm_name, domxml=vmxml_backup) if blk_source_folder: process.run("cd %s && rm -rf b c d" % blk_source_folder, shell=True) if disk_src_protocol == 'iscsi': libvirt.setup_or_cleanup_iscsi(is_setup=False, restart_tgtd=restart_tgtd) elif disk_src_protocol == 'gluster': gluster.setup_or_cleanup_gluster(False, brick_path=brick_path, **params) libvirtd = utils_libvirtd.Libvirtd() libvirtd.restart() elif disk_src_protocol == 'netfs': restore_selinux = params.get('selinux_status_bak') libvirt.setup_or_cleanup_nfs(is_setup=False, restore_selinux=restore_selinux) # Recover images xattr if having some dirty_images = get_images_with_xattr(vm) if dirty_images: clean_images_with_xattr(dirty_images) test.fail("VM's image(s) having xattr left")
def run(test, params, env): """ convert specific kvm guest to rhev """ for v in list(params.values()): if "V2V_EXAMPLE" in v: test.cancel("Please set real value for %s" % v) if utils_v2v.V2V_EXEC is None: raise ValueError('Missing command: virt-v2v') enable_legacy_policy = params_get(params, "enable_legacy_policy") == 'yes' version_required = params.get("version_required") hypervisor = params.get("hypervisor") vm_name = params.get('main_vm', 'EXAMPLE') target = params.get('target') remote_host = params.get('remote_host', 'EXAMPLE') input_mode = params.get("input_mode") output_mode = params.get('output_mode') output_format = params.get('output_format') source_user = params.get("username", "root") os_pool = storage = params.get('output_storage') bridge = params.get('bridge') network = params.get('network') ntp_server = params.get('ntp_server') vpx_dc = params.get("vpx_dc") esx_ip = params.get("esx_hostname") address_cache = env.get('address_cache') pool_name = params.get('pool_name', 'v2v_test') pool_type = params.get('pool_type', 'dir') pool_target = params.get('pool_target_path', 'v2v_pool') pvt = utlv.PoolVolumeTest(test, params) v2v_opts = '-v -x' if params.get('v2v_debug', 'on') in ['on', 'force_on'] else '' if params.get("v2v_opts"): # Add a blank by force v2v_opts += ' ' + params.get("v2v_opts") v2v_timeout = int(params.get('v2v_timeout', 3600)) skip_vm_check = params.get('skip_vm_check', 'no') status_error = 'yes' == params.get('status_error', 'no') checkpoint = params.get('checkpoint', '') debug_kernel = 'debug_kernel' == checkpoint backup_list = ['floppy', 'floppy_devmap', 'fstab_cdrom', 'sata_disk', 'network_rtl8139', 'network_e1000', 'spice', 'spice_encrypt', 'spice_qxl', 'spice_cirrus', 'vnc_qxl', 'vnc_cirrus', 'blank_2nd_disk', 'listen_none', 'listen_socket', 'only_net', 'only_br'] error_list = [] # For construct rhv-upload option in v2v cmd output_method = params.get("output_method") rhv_upload_opts = params.get("rhv_upload_opts") storage_name = params.get('storage_name') # for get ca.crt file from ovirt engine rhv_passwd = params.get("rhv_upload_passwd") rhv_passwd_file = params.get("rhv_upload_passwd_file") ovirt_engine_passwd = params.get("ovirt_engine_password") ovirt_hostname = params.get("ovirt_engine_url").split( '/')[2] if params.get("ovirt_engine_url") else None ovirt_ca_file_path = params.get("ovirt_ca_file_path") local_ca_file_path = params.get("local_ca_file_path") # For VDDK input_transport = params.get("input_transport") vddk_libdir = params.get('vddk_libdir') # nfs mount source vddk_libdir_src = params.get('vddk_libdir_src') vddk_thumbprint = params.get('vddk_thumbprint') if version_required and not utils_v2v.multiple_versions_compare( version_required): test.cancel("Testing requires version: %s" % version_required) # Prepare step for different hypervisor if enable_legacy_policy: update_crypto_policy("LEGACY") if hypervisor == "esx": source_ip = params.get("vpx_hostname") source_pwd = params.get("vpx_password") vpx_passwd_file = params.get("vpx_passwd_file") # Create password file to access ESX hypervisor with open(vpx_passwd_file, 'w') as f: f.write(source_pwd) elif hypervisor == "xen": source_ip = params.get("xen_hostname") source_pwd = params.get("xen_host_passwd") # Set up ssh access using ssh-agent and authorized_keys xen_pubkey, xen_session = utils_v2v.v2v_setup_ssh_key( source_ip, source_user, source_pwd, auto_close=False) try: utils_misc.add_identities_into_ssh_agent() except Exception as e: process.run("ssh-agent -k") test.error("Fail to setup ssh-agent \n %s" % str(e)) elif hypervisor == "kvm": source_ip = None source_pwd = None else: test.cancel("Unsupported hypervisor: %s" % hypervisor) # Create libvirt URI v2v_uri = utils_v2v.Uri(hypervisor) remote_uri = v2v_uri.get_uri(source_ip, vpx_dc, esx_ip) LOG.debug("libvirt URI for converting: %s", remote_uri) # Make sure the VM exist before convert v2v_virsh = None close_virsh = False if hypervisor == 'kvm': v2v_virsh = virsh else: virsh_dargs = {'uri': remote_uri, 'remote_ip': source_ip, 'remote_user': source_user, 'remote_pwd': source_pwd, 'auto_close': True, 'debug': True} v2v_virsh = virsh.VirshPersistent(**virsh_dargs) LOG.debug('a new virsh session %s was created', v2v_virsh) close_virsh = True if not v2v_virsh.domain_exists(vm_name): test.error("VM '%s' not exist" % vm_name) def log_fail(msg): """ Log error and update error list """ LOG.error(msg) error_list.append(msg) def vm_shell(func): """ Decorator of shell session to vm """ def wrapper(*args, **kwargs): vm = libvirt_vm.VM(vm_name, params, test.bindir, env.get('address_cache')) if vm.is_dead(): LOG.info('VM is down. Starting it now.') vm.start() session = vm.wait_for_login() kwargs['session'] = session kwargs['vm'] = vm func(*args, **kwargs) if session: session.close() vm.shutdown() return wrapper def check_disks(vmcheck): """ Check disk counts inside the VM """ # Initialize windows boot up os_type = params.get("os_type", "linux") expected_disks = int(params.get("ori_disks", "1")) LOG.debug("Expect %s disks im VM after convert", expected_disks) # Get disk counts if os_type == "linux": cmd = "lsblk |grep disk |wc -l" disks = int(vmcheck.session.cmd(cmd).strip()) else: cmd = r"echo list disk > C:\list_disk.txt" vmcheck.session.cmd(cmd) cmd = r"diskpart /s C:\list_disk.txt" output = vmcheck.session.cmd(cmd).strip() LOG.debug("Disks in VM: %s", output) disks = len(re.findall(r'Disk\s\d', output)) LOG.debug("Find %s disks in VM after convert", disks) if disks == expected_disks: LOG.info("Disk counts is expected") else: log_fail("Disk counts is wrong") def check_vmlinuz_initramfs(v2v_output): """ Check if vmlinuz matches initramfs on multi-kernel case """ LOG.debug('Checking if vmlinuz matches initramfs') kernel_strs = re.findall( r'(\* kernel.*?\/boot\/config){1,}', v2v_output, re.DOTALL) if len(kernel_strs) == 0: test.error("Not find kernel information") # Remove duplicate items by set LOG.debug('Boots and kernel info: %s' % set(kernel_strs)) for str_i in set(kernel_strs): # Fine all versions kernel_vers = re.findall( r'((?:\d+\.){1,}\d+-(?:\d+\.){1,}\w+)', str_i) LOG.debug('kernel related versions: %s' % kernel_vers) # kernel_vers = [kernel, vmlinuz, initramfs] and they should be # same if len(kernel_vers) < 3 or len(set(kernel_vers)) != 1: log_fail("kernel versions does not match: %s" % kernel_vers) def check_boot_kernel(vmcheck): """ Check if converted vm use the latest kernel """ _, current_kernel = vmcheck.run_cmd('uname -r') if 'debug' in current_kernel: log_fail('Current kernel is a debug kernel: %s' % current_kernel) # 'sort -V' can satisfy our testing, even though it's not strictly perfect. # The last one is always the latest kernel version kernel_normal_list = vmcheck.run_cmd( 'rpm -q kernel | sort -V')[1].strip().splitlines() status, kernel_debug = vmcheck.run_cmd('rpm -q kernel-debug') if status != 0: test.error('Not found kernel-debug package') all_kernel_list = kernel_normal_list + kernel_debug.strip().splitlines() LOG.debug('All kernels: %s' % all_kernel_list) if len(all_kernel_list) < 3: test.error( 'Needs at least 2 normal kernels and 1 debug kernel in VM') # The latest non-debug kernel must be kernel_normal_list[-1] if current_kernel.strip() != kernel_normal_list[-1].lstrip('kernel-'): log_fail('Check boot kernel failed') def check_floppy_exist(vmcheck): """ Check if floppy exists after conversion """ blk = vmcheck.session.cmd('lsblk') LOG.info(blk) if not re.search('fd0', blk): log_fail('Floppy not found') def attach_removable_media(type, source, dev): bus = {'cdrom': 'ide', 'floppy': 'fdc', 'disk': 'virtio'} args = {'driver': 'qemu', 'subdriver': 'raw', 'sourcetype': 'file', 'type': type, 'targetbus': bus[type]} if type == 'cdrom': args.update({'mode': 'readonly'}) config = '' # Join all options together to get command line for key in list(args.keys()): config += ' --%s %s' % (key, args[key]) config += ' --current' virsh.attach_disk(vm_name, source, dev, extra=config) def change_disk_bus(dest): """ Change all disks' bus type to $dest """ bus_list = ['ide', 'sata', 'virtio'] if dest not in bus_list: test.error('Bus type not support') dev_prefix = ['h', 's', 'v'] dev_table = dict(list(zip(bus_list, dev_prefix))) LOG.info('Change disk bus to %s' % dest) vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) disks = vmxml.get_disk_all_by_expr('device==disk') index = 0 for disk in list(disks.values()): if disk.get('device') != 'disk': continue target = disk.find('target') target.set('bus', dest) target.set( 'dev', dev_table[dest] + 'd' + string.ascii_lowercase[index]) disk.remove(disk.find('address')) index += 1 vmxml.sync() def change_network_model(model): """ Change network model to $model """ vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) network_list = vmxml.get_iface_all() for node in list(network_list.values()): if node.get('type') == 'network': node.find('model').set('type', model) vmxml.sync() def attach_network_card(model): """ Attach network card based on model """ if model not in ('e1000', 'virtio', 'rtl8139'): test.error('Network model not support') options = {'type': 'network', 'source': 'default', 'model': model} line = '' for key in options: line += ' --' + key + ' ' + options[key] line += ' --current' LOG.debug(virsh.attach_interface(vm_name, option=line)) def check_multi_netcards(mac_list, vmxml): """ Check if number and type of network cards meet expectation """ xmltree = xml_utils.XMLTreeFile(vmxml) iface_nodes = xmltree.find('devices').findall('interface') iflist = {} for node in iface_nodes: mac_addr = node.find('mac').get('address') iflist[mac_addr] = node LOG.debug('MAC list before v2v: %s' % mac_list) LOG.debug('MAC list after v2v: %s' % list(iflist.keys())) if set(mac_list).difference(list(iflist.keys())): log_fail('Missing network interface') for mac in iflist: if iflist[mac].find('model').get('type') != 'virtio': log_fail('Network not convert to virtio') @vm_shell def insert_floppy_devicemap(**kwargs): """ Add an entry of floppy to device.map """ session = kwargs['session'] line = '(fd0) /dev/fd0' devmap = '/boot/grub/device.map' if session.cmd_status('ls %s' % devmap): devmap = '/boot/grub2/device.map' cmd_exist = 'grep \'(fd0)\' %s' % devmap cmd_set = 'sed -i \'2i%s\' %s' % (line, devmap) if session.cmd_status(cmd_exist): session.cmd(cmd_set) def make_label(session): """ Label a volume, swap or root volume """ # swaplabel for rhel7 with xfs, e2label for rhel6 or ext* cmd_map = {'root': 'e2label %s ROOT', 'swap': 'swaplabel -L SWAPPER %s'} if not session.cmd_status('swaplabel --help'): blk = 'swap' elif not session.cmd_status('which e2label'): blk = 'root' else: test.error('No tool to make label') entry = session.cmd('blkid|grep %s' % blk).strip() path = entry.split()[0].strip(':') cmd_label = cmd_map[blk] % path if 'LABEL' not in entry: session.cmd(cmd_label) return blk @vm_shell def specify_fstab_entry(type, **kwargs): """ Specify entry in fstab file """ type_list = ['cdrom', 'uuid', 'label', 'sr0', 'invalid'] if type not in type_list: test.error('Not support %s in fstab' % type) session = kwargs['session'] # Specify cdrom device if type == 'cdrom': line = '/dev/cdrom /media/CDROM auto exec' if 'grub2' in utils_misc.get_bootloader_cfg(session): line += ',nofail' line += ' 0 0' LOG.debug('fstab entry is "%s"', line) cmd = [ 'mkdir -p /media/CDROM', 'mount /dev/cdrom /media/CDROM', 'echo "%s" >> /etc/fstab' % line ] for i in range(len(cmd)): session.cmd(cmd[i]) elif type == 'sr0': line = params.get('fstab_content') session.cmd('echo "%s" >> /etc/fstab' % line) elif type == 'invalid': line = utils_misc.generate_random_string(6) session.cmd('echo "%s" >> /etc/fstab' % line) else: map = {'uuid': 'UUID', 'label': 'LABEL'} LOG.info(type) if session.cmd_status('cat /etc/fstab|grep %s' % map[type]): # Specify device by UUID if type == 'uuid': entry = session.cmd( 'blkid -s UUID|grep swap').strip().split() # Replace path for UUID origin = entry[0].strip(':') replace = entry[1].replace('"', '') # Specify device by label elif type == 'label': blk = make_label(session) entry = session.cmd('blkid|grep %s' % blk).strip() # Remove " from LABEL="****" replace = entry.split()[1].strip().replace('"', '') # Replace the original id/path with label origin = entry.split()[0].strip(':') cmd_fstab = "sed -i 's|%s|%s|' /etc/fstab" % (origin, replace) session.cmd(cmd_fstab) fstab = session.cmd_output('cat /etc/fstab') LOG.debug('Content of /etc/fstab:\n%s', fstab) def create_large_file(session, left_space): """ Create a large file to make left space of root less than $left_space MB """ cmd_guestfish = "guestfish get-cachedir" tmp_dir = session.cmd_output(cmd_guestfish).split()[-1] LOG.debug('Command output of tmp_dir: %s', tmp_dir) cmd_df = "df -m %s --output=avail" % tmp_dir df_output = session.cmd(cmd_df).strip() LOG.debug('Command output: %s', df_output) avail = int(df_output.strip().split('\n')[-1]) LOG.info('Available space: %dM' % avail) if avail <= left_space - 1: return None if not os.path.exists(tmp_dir): os.mkdir(tmp_dir) large_file = os.path.join(tmp_dir, 'file.large') cmd_create = 'dd if=/dev/zero of=%s bs=1M count=%d' % \ (large_file, avail - left_space + 2) session.cmd(cmd_create, timeout=v2v_timeout) newAvail = int(session.cmd(cmd_df).strip().split('\n')[-1]) LOG.info('New Available space: %sM' % newAvail) return large_file @vm_shell def corrupt_rpmdb(**kwargs): """ Corrupt rpm db """ session = kwargs['session'] session.cmd('rm -f /var/lib/rpm/__db.*') session.cmd('touch /var/lib/rpm/__db.001') output = session.cmd_output('yum update --assumeno') LOG.debug(output) if 'rpmdb open failed' not in output: test.error('Prepare corrupt rpmdb failed') @vm_shell def grub_serial_terminal(**kwargs): """ Edit the serial and terminal lines of grub.conf """ session = kwargs['session'] vm = kwargs['vm'] grub_file = utils_misc.get_bootloader_cfg(session) if 'grub2' in grub_file: test.cancel('Skip this case on grub2') cmd = "sed -i '1iserial -unit=0 -speed=115200\\n" cmd += "terminal -timeout=10 serial console' %s" % grub_file session.cmd(cmd) @vm_shell def set_selinux(value, **kwargs): """ Set selinux stat of guest """ session = kwargs['session'] current_stat = session.cmd_output('getenforce').strip() LOG.debug('Current selinux status: %s', current_stat) if current_stat != value: cmd = "sed -E -i 's/(^SELINUX=).*?/\\1%s/' /etc/selinux/config" % value LOG.info('Set selinux stat with command %s', cmd) session.cmd(cmd) @vm_shell def get_firewalld_status(**kwargs): """ Return firewalld service status of vm """ session = kwargs['session'] # Example: Active: active (running) since Fri 2019-03-15 01:03:39 CST; # 3min 48s ago firewalld_status = session.cmd( 'systemctl status firewalld.service|grep Active:', ok_status=[ 0, 3]).strip() # Exclude the time string because time changes if vm restarts firewalld_status = re.search( r'Active:\s\w*\s\(\w*\)', firewalld_status).group() LOG.info('Status of firewalld: %s', firewalld_status) params[checkpoint] = firewalld_status def check_firewalld_status(vmcheck, expect_status): """ Check if status of firewalld meets expectation """ firewalld_status = vmcheck.session.cmd( 'systemctl status ' 'firewalld.service|grep Active:', ok_status=[ 0, 3]).strip() # Exclude the time string because time changes if vm restarts firewalld_status = re.search( r'Active:\s\w*\s\(\w*\)', firewalld_status).group() LOG.info('Status of firewalld after v2v: %s', firewalld_status) if firewalld_status != expect_status: log_fail('Status of firewalld changed after conversion') @vm_shell def vm_cmd(cmd_list, **kwargs): """ Execute a list of commands on guest. """ session = kwargs['session'] for cmd in cmd_list: LOG.info('Send command "%s"', cmd) # 'chronyc waitsync' needs more than 2mins to sync clock, # We set timeout to 300s will not have side-effects for other # commands. status, output = session.cmd_status_output(cmd, timeout=300) LOG.debug('Command output:\n%s', output) if status != 0: test.error('Command "%s" failed' % cmd) LOG.info('All commands executed') def check_time_keep(vmcheck): """ Check time drift after conversion. """ LOG.info('Check time drift') output = vmcheck.session.cmd('chronyc tracking') LOG.debug(output) if 'Not synchronised' in output: log_fail('Time not synchronised') lst_offset = re.search('Last offset *?: *(.*) ', output).group(1) drift = abs(float(lst_offset)) LOG.debug('Time drift is: %f', drift) if drift > 3: log_fail('Time drift exceeds 3 sec') def check_boot(): """ Check if guest can boot up after configuration """ try: vm = libvirt_vm.VM(vm_name, params, test.bindir, env.get('address_cache')) if vm.is_alive(): vm.shutdown() LOG.info('Booting up %s' % vm_name) vm.start() vm.wait_for_login() vm.shutdown() LOG.info('%s is down' % vm_name) except Exception as e: test.error('Bootup guest and login failed: %s' % str(e)) def check_result(result, status_error): """ Check virt-v2v command result """ utlv.check_exit_status(result, status_error) output = result.stdout_text + result.stderr_text if not status_error: if output_mode == 'json' and not check_json_output(params): test.fail('check json output failed') if output_mode == 'local' and not check_local_output(params): test.fail('check local output failed') if output_mode in ['null', 'json', 'local']: return vmchecker = VMChecker(test, params, env) params['vmchecker'] = vmchecker if output_mode == 'rhev': if not utils_v2v.import_vm_to_ovirt(params, address_cache, timeout=v2v_timeout): test.fail('Import VM failed') if output_mode == 'libvirt': try: virsh.start(vm_name, debug=True, ignore_status=False) except Exception as e: test.fail('Start vm failed: %s' % str(e)) # Check guest following the checkpoint document after conversion if params.get('skip_vm_check') != 'yes': ret = vmchecker.run() if len(ret) == 0: LOG.info("All common checkpoints passed") LOG.debug(vmchecker.vmxml) if checkpoint == 'multi_kernel': check_boot_kernel(vmchecker.checker) check_vmlinuz_initramfs(output) if checkpoint == 'floppy': # Convert to rhv will remove all removable devices(floppy, # cdrom) if output_mode in ['local', 'libvirt']: check_floppy_exist(vmchecker.checker) if checkpoint == 'multi_disks': check_disks(vmchecker.checker) if checkpoint == 'multi_netcards': check_multi_netcards(params['mac_address'], vmchecker.vmxml) if checkpoint.startswith(('spice', 'vnc')): if checkpoint == 'spice_encrypt': vmchecker.check_graphics(params[checkpoint]) else: graph_type = checkpoint.split('_')[0] vmchecker.check_graphics({'type': graph_type}) video_type = vmchecker.xmltree.find( './devices/video/model').get('type') if utils_v2v.multiple_versions_compare(V2V_ADAPTE_SPICE_REMOVAL_VER): expect_video_type = 'vga' else: expect_video_type = 'qxl' if video_type.lower() != expect_video_type: log_fail('Video expect %s, actual %s' % (expect_video_type, video_type)) if checkpoint.startswith('listen'): listen_type = vmchecker.xmltree.find( './devices/graphics/listen').get('type') LOG.info('listen type is: %s', listen_type) if listen_type != checkpoint.split('_')[-1]: log_fail('listen type changed after conversion') if checkpoint.startswith('selinux'): status = vmchecker.checker.session.cmd( 'getenforce').strip().lower() LOG.info('Selinux status after v2v:%s', status) if status != checkpoint[8:]: log_fail('Selinux status not match') if checkpoint == 'check_selinuxtype': expect_output = vmchecker.checker.session.cmd( 'cat /etc/selinux/config') expect_selinuxtype = re.search( r'^SELINUXTYPE=\s*(\S+)$', expect_output, re.MULTILINE).group(1) actual_output = vmchecker.checker.session.cmd('sestatus') actual_selinuxtype = re.search( r'^Loaded policy name:\s*(\S+)$', actual_output, re.MULTILINE).group(1) if actual_selinuxtype != expect_selinuxtype: log_fail('Seliunx type not match') if checkpoint == 'guest_firewalld_status': check_firewalld_status(vmchecker.checker, params[checkpoint]) if checkpoint in ['ntpd_on', 'sync_ntp']: check_time_keep(vmchecker.checker) # Merge 2 error lists error_list.extend(vmchecker.errors) log_check = utils_v2v.check_log(params, output) if log_check: log_fail(log_check) if len(error_list): test.fail('%d checkpoints failed: %s' % (len(error_list), error_list)) try: v2v_sasl = None v2v_params = { 'target': target, 'hypervisor': hypervisor, 'main_vm': vm_name, 'input_mode': input_mode, 'network': network, 'bridge': bridge, 'os_storage': storage, 'os_pool': os_pool, 'hostname': source_ip, 'password': source_pwd, 'v2v_opts': v2v_opts, 'new_name': vm_name + utils_misc.generate_random_string(3), 'output_method': output_method, 'os_storage_name': storage_name, 'rhv_upload_opts': rhv_upload_opts, 'input_transport': input_transport, 'vcenter_host': source_ip, 'vcenter_password': source_pwd, 'vddk_thumbprint': vddk_thumbprint, 'vddk_libdir': vddk_libdir, 'vddk_libdir_src': vddk_libdir_src, 'params': params, } if vpx_dc: v2v_params.update({"vpx_dc": vpx_dc}) if esx_ip: v2v_params.update({"esx_ip": esx_ip}) output_format = params.get('output_format') if output_format: v2v_params.update({'of_format': output_format}) # Build rhev related options if output_mode == 'rhev': # Create different sasl_user name for different job params.update({'sasl_user': params.get("sasl_user") + utils_misc.generate_random_string(3)}) LOG.info('sals user name is %s' % params.get("sasl_user")) # Create SASL user on the ovirt host user_pwd = "[['%s', '%s']]" % (params.get("sasl_user"), params.get("sasl_pwd")) v2v_sasl = utils_sasl.SASL(sasl_user_pwd=user_pwd) v2v_sasl.server_ip = params.get("remote_ip") v2v_sasl.server_user = params.get('remote_user') v2v_sasl.server_pwd = params.get('remote_pwd') v2v_sasl.setup(remote=True) LOG.debug('A SASL session %s was created', v2v_sasl) if output_method == 'rhv_upload': # Create password file for '-o rhv_upload' to connect to ovirt with open(rhv_passwd_file, 'w') as f: f.write(rhv_passwd) # Copy ca file from ovirt to local remote.scp_from_remote(ovirt_hostname, 22, 'root', ovirt_engine_passwd, ovirt_ca_file_path, local_ca_file_path) if output_mode == 'local': v2v_params['os_directory'] = data_dir.get_tmp_dir() if output_mode == 'libvirt': pvt.pre_pool(pool_name, pool_type, pool_target, '') # Set libguestfs environment variable utils_v2v.set_libguestfs_backend(params) # Save origin graphic type for result checking if source is KVM if hypervisor == 'kvm': ori_vm_xml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) params['ori_graphic'] = ori_vm_xml.xmltreefile.find( 'devices').find('graphics').get('type') params['vm_machine'] = ori_vm_xml.xmltreefile.find( './os/type').get('machine') backup_xml = None # Only kvm guest's xml needs to be backup currently if checkpoint in backup_list and hypervisor == 'kvm': backup_xml = ori_vm_xml if checkpoint == 'multi_disks': new_xml = vm_xml.VMXML.new_from_inactive_dumpxml( vm_name, virsh_instance=v2v_virsh) disk_count = len(new_xml.get_disk_all_by_expr('device==disk')) if disk_count <= 1: test.error('Not enough disk devices') params['ori_disks'] = disk_count if checkpoint == 'sata_disk': change_disk_bus('sata') if checkpoint.startswith('floppy'): if params['vm_machine'] and 'q35' in params['vm_machine'] and int( re.search(r'pc-q35-rhel(\d+)\.', params['vm_machine']).group(1)) >= 8: test.cancel( 'Device isa-fdc is not supported with machine type %s' % params['vm_machine']) img_path = data_dir.get_tmp_dir() + '/floppy.img' utlv.create_local_disk('floppy', img_path) attach_removable_media('floppy', img_path, 'fda') if checkpoint == 'floppy_devmap': insert_floppy_devicemap() if checkpoint.startswith('fstab'): if checkpoint == 'fstab_cdrom': img_path = data_dir.get_tmp_dir() + '/cdrom.iso' utlv.create_local_disk('iso', img_path) attach_removable_media('cdrom', img_path, 'hdc') specify_fstab_entry(checkpoint[6:]) if checkpoint == 'running': virsh.start(vm_name) LOG.info('VM state: %s' % virsh.domstate(vm_name).stdout.strip()) if checkpoint == 'paused': virsh.start(vm_name, '--paused') LOG.info('VM state: %s' % virsh.domstate(vm_name).stdout.strip()) if checkpoint == 'serial_terminal': grub_serial_terminal() check_boot() if checkpoint.startswith('host_no_space'): session = aexpect.ShellSession('sh') large_file = create_large_file(session, 800) if checkpoint == 'host_no_space_setcache': LOG.info('Set LIBGUESTFS_CACHEDIR=/home') os.environ['LIBGUESTFS_CACHEDIR'] = '/home' if checkpoint == 'corrupt_rpmdb': corrupt_rpmdb() if checkpoint.startswith('network'): change_network_model(checkpoint[8:]) if checkpoint == 'multi_netcards': params['mac_address'] = [] vmxml = vm_xml.VMXML.new_from_inactive_dumpxml( vm_name, virsh_instance=v2v_virsh) network_list = vmxml.get_iface_all() for mac in network_list: if network_list[mac].get('type') in ['bridge', 'network']: params['mac_address'].append(mac) if len(params['mac_address']) < 2: test.error('Not enough network interface') LOG.debug('MAC address: %s' % params['mac_address']) if checkpoint.startswith(('spice', 'vnc')): if checkpoint == 'spice_encrypt': spice_passwd = {'type': 'spice', 'passwd': params.get('spice_passwd', 'redhat')} vm_xml.VMXML.set_graphics_attr(vm_name, spice_passwd) params[checkpoint] = {'type': 'spice', 'passwdValidTo': '1970-01-01T00:00:01'} else: graphic_video = checkpoint.split('_') graphic = graphic_video[0] LOG.info('Set graphic type to %s', graphic) vm_xml.VMXML.set_graphics_attr(vm_name, {'type': graphic}) if len(graphic_video) > 1: video_type = graphic_video[1] LOG.info('Set video type to %s', video_type) vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) video = vmxml.xmltreefile.find( 'devices').find('video').find('model') video.set('type', video_type) # cirrus doesn't support 'ram' and 'vgamem' attribute if video_type == 'cirrus': [video.attrib.pop(attr_i) for attr_i in [ 'ram', 'vgamem'] if attr_i in video.attrib] vmxml.sync() if checkpoint.startswith('listen'): listen_type = checkpoint.split('_')[-1] vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) listen = vmxml.xmltreefile.find( 'devices').find('graphics').find('listen') listen.set('type', listen_type) vmxml.sync() if checkpoint == 'host_selinux_on': params['selinux_stat'] = utils_selinux.get_status() utils_selinux.set_status('enforcing') if checkpoint.startswith('selinux'): set_selinux(checkpoint[8:]) if checkpoint.startswith('host_firewalld'): service_mgr = service.ServiceManager() LOG.info('Backing up firewall services status') params['bk_firewalld_status'] = service_mgr.status('firewalld') if 'start' in checkpoint: service_mgr.start('firewalld') if 'stop' in checkpoint: service_mgr.stop('firewalld') if checkpoint == 'guest_firewalld_status': get_firewalld_status() if checkpoint == 'remove_securetty': LOG.info('Remove /etc/securetty file from guest') cmd = ['rm -f /etc/securetty'] vm_cmd(cmd) if checkpoint == 'ntpd_on': LOG.info('Set service chronyd on') cmd = ['yum -y install chrony', 'systemctl start chronyd', 'chronyc add server %s' % ntp_server] vm_cmd(cmd) if checkpoint == 'sync_ntp': LOG.info('Sync time with %s', ntp_server) cmd = ['yum -y install chrony', 'systemctl start chronyd', 'chronyc add server %s' % ntp_server, 'chronyc waitsync'] vm_cmd(cmd) if checkpoint == 'blank_2nd_disk': disk_path = os.path.join(data_dir.get_tmp_dir(), 'blank.img') LOG.info('Create blank disk %s', disk_path) process.run('truncate -s 1G %s' % disk_path) LOG.info('Attach blank disk to vm') attach_removable_media('disk', disk_path, 'vdc') LOG.debug(virsh.dumpxml(vm_name)) if checkpoint in ['only_net', 'only_br']: LOG.info('Detatch all networks') virsh.detach_interface(vm_name, 'network --current', debug=True) LOG.info('Detatch all bridges') virsh.detach_interface(vm_name, 'bridge --current', debug=True) if checkpoint == 'only_net': LOG.info('Attach network') virsh.attach_interface( vm_name, 'network default --current', debug=True) if checkpoint == 'only_br': LOG.info('Attatch bridge') virsh.attach_interface( vm_name, 'bridge virbr0 --current', debug=True) if checkpoint == 'no_libguestfs_backend': os.environ.pop('LIBGUESTFS_BACKEND') if checkpoint == 'file_image': vm = env.get_vm(vm_name) disk = vm.get_first_disk_devices() LOG.info('Disk type is %s', disk['type']) if disk['type'] != 'file': test.error('Guest is not with file image') v2v_result = utils_v2v.v2v_cmd(v2v_params) if v2v_params.get('new_name'): vm_name = params['main_vm'] = v2v_params['new_name'] check_result(v2v_result, status_error) finally: if close_virsh and v2v_virsh: LOG.debug('virsh session %s is closing', v2v_virsh) v2v_virsh.close_session() if params.get('vmchecker'): params['vmchecker'].cleanup() if enable_legacy_policy: update_crypto_policy() if hypervisor == "xen": utils_v2v.v2v_setup_ssh_key_cleanup(xen_session, xen_pubkey) process.run('ssh-agent -k') if output_mode == 'rhev' and v2v_sasl: v2v_sasl.cleanup() LOG.debug('SASL session %s is closing', v2v_sasl) v2v_sasl.close_session() if output_mode == 'libvirt': pvt.cleanup_pool(pool_name, pool_type, pool_target, '') if backup_xml: backup_xml.sync() if params.get('selinux_stat') and params['selinux_stat'] != 'disabled': utils_selinux.set_status(params['selinux_stat']) if 'bk_firewalld_status' in params: service_mgr = service.ServiceManager() if service_mgr.status( 'firewalld') != params['bk_firewalld_status']: if params['bk_firewalld_status']: service_mgr.start('firewalld') else: service_mgr.stop('firewalld') if checkpoint.startswith('host_no_space'): if large_file and os.path.isfile(large_file): os.remove(large_file) # Cleanup constant files utils_v2v.cleanup_constant_files(params)
def run(test, params, env): """ KVM migration test: 1) Get a live VM and clone it. 2) Verify that the source VM supports migration. If it does, proceed with the test. 3) Transfer file from host to guest. 4) Repeatedly migrate VM and wait until transfer's finished. 5) Transfer file from guest back to host. 6) Repeatedly migrate VM and wait until transfer's finished. :param test: QEMU test object. :param params: Dictionary with test parameters. :param env: Dictionary with the test environment. """ vm = env.get_vm(params["main_vm"]) vm.verify_alive() login_timeout = int(params.get("login_timeout", 360)) session = vm.wait_for_login(timeout=login_timeout) mig_timeout = float(params.get("mig_timeout", "3600")) mig_protocol = params.get("migration_protocol", "tcp") mig_cancel_delay = int(params.get("mig_cancel") == "yes") * 2 host_path = "/tmp/file-%s" % utils_misc.generate_random_string(6) host_path_returned = "%s-returned" % host_path guest_path = params.get("guest_path", "/tmp/file") file_size = params.get("file_size", "500") transfer_timeout = int(params.get("transfer_timeout", "240")) migrate_between_vhost_novhost = params.get("migrate_between_vhost_novhost") try: utils.run("dd if=/dev/urandom of=%s bs=1M count=%s" % (host_path, file_size)) def run_and_migrate(bg): bg.start() try: while bg.isAlive(): logging.info( "File transfer not ended, starting a round of " "migration...") if migrate_between_vhost_novhost == "yes": vhost_status = vm.params.get("vhost") if vhost_status == "vhost=on": vm.params["vhost"] = "vhost=off" elif vhost_status == "vhost=off": vm.params["vhost"] = "vhost=on" vm.migrate(mig_timeout, mig_protocol, mig_cancel_delay, env=env) except Exception: # If something bad happened in the main thread, ignore # exceptions raised in the background thread bg.join(suppress_exception=True) raise else: bg.join() error.context("transferring file to guest while migrating", logging.info) bg = utils.InterruptedThread( vm.copy_files_to, (host_path, guest_path), dict(verbose=True, timeout=transfer_timeout)) run_and_migrate(bg) error.context("transferring file back to host while migrating", logging.info) bg = utils.InterruptedThread( vm.copy_files_from, (guest_path, host_path_returned), dict(verbose=True, timeout=transfer_timeout)) run_and_migrate(bg) # Make sure the returned file is identical to the original one error.context("comparing hashes", logging.info) orig_hash = client_utils.hash_file(host_path) returned_hash = client_utils.hash_file(host_path_returned) if orig_hash != returned_hash: raise error.TestFail("Returned file hash (%s) differs from " "original one (%s)" % (returned_hash, orig_hash)) error.context() finally: session.close() if os.path.isfile(host_path): os.remove(host_path) if os.path.isfile(host_path_returned): os.remove(host_path_returned)
def run(test, params, env): """ Transfer a file back and forth between host and guest. 1) Boot up a VM. 2) Create a large file by dd on host. 3) Copy this file from host to guest. 4) Copy this file from guest to host. 5) Check if file transfers ended good. :param test: QEMU test object. :param params: Dictionary with the test parameters. :param env: Dictionary with test environment. """ @error.context_aware def do_file_copy(src_file, guest_file, dst_file, transfer_timeout): error.context( "Transferring file host -> guest," " timeout: %ss" % transfer_timeout, logging.info) vm.copy_files_to(src_file, guest_file, timeout=transfer_timeout) error.context( "Transferring file guest -> host," " timeout: %ss" % transfer_timeout, logging.info) vm.copy_files_from(guest_file, dst_file, timeout=transfer_timeout) error.context( "Compare md5sum between original file and" " transferred file", logging.info) if (utils.hash_file(src_file, method="md5") != utils.hash_file( dst_file, method="md5")): raise error.TestFail("File changed after transfer host -> guest " "and guest -> host") login_timeout = int(params.get("login_timeout", 360)) vm = env.get_vm(params["main_vm"]) vm.verify_alive() error.context("Login to guest", logging.info) session = vm.wait_for_login(timeout=login_timeout) dir_name = data_dir.get_tmp_dir() tmp_dir = params.get("tmp_dir", "/var/tmp/") clean_cmd = params.get("clean_cmd", "rm -f") scp_sessions = int(params.get("scp_para_sessions", 1)) filesize = float(params.get("filesize", 4000)) transfer_timeout = float(params.get("transfer_timeout", 600)) src_path = [] dst_path = [] guest_path = [] for _ in range(scp_sessions): random_file_name = utils_misc.generate_random_string(8) src_path.append(os.path.join(dir_name, "h-src-%s" % random_file_name)) guest_path.append(tmp_dir + "g-tmp-%s" % random_file_name) dst_path.append(os.path.join(dir_name, "h-dst-%s" % random_file_name)) cmd = "dd if=/dev/zero of=%s bs=1M count=%d" try: for src_file in src_path: error.context("Create %dMB file on host" % filesize, logging.info) utils.run(cmd % (src_file, filesize)) stress_timeout = float(params.get("stress_timeout", "3600")) error.context("Do file transfer between host and guest", logging.info) start_time = time.time() stop_time = start_time + stress_timeout #here when set a run flag, when other case call this case as a #subprocess backgroundly, can set this run flag to False to stop #the stress test. env["file_transfer_run"] = True while (env["file_transfer_run"] and time.time() < stop_time): scp_threads = [] for index in range(scp_sessions): scp_threads.append( (do_file_copy, (src_path[index], guest_path[index], dst_path[index], transfer_timeout))) utils_misc.parallel(scp_threads) finally: env["file_transfer_run"] = False logging.info('Cleaning temp file on host and guest') for del_file in guest_path: session.cmd("%s %s" % (clean_cmd, del_file), ignore_all_errors=True) for del_file in src_path + dst_path: utils.system("%s %s" % (clean_cmd, del_file), ignore_status=True) if session: session.close()
def run(test, params, env): """ Test mtu feature from virtual network """ vm_name = params.get('main_vm') vm = env.get_vm(vm_name) mtu_type = params.get('mtu_type') mtu_size = params.get('mtu_size', '') net = params.get('net', DEFAULT_NET) net_type = params.get('net_type', '') with_iface = 'yes' == params.get('with_iface', 'no') with_net = 'yes' == params.get('with_net', 'no') status_error = 'yes' == params.get('status_error', 'no') check = params.get('check', '') error_msg = params.get('error_msg', '') bridge_name = 'br_mtu' + utils_misc.generate_random_string(3) add_pkg = params.get('add_pkg', '') model = params.get('model', 'virtio') def set_network(size, net='default'): """ Set mtu size to a certain network """ logging.info('Set mtu size of network "%s" to %s', net, size) default_xml = NetworkXML.new_from_net_dumpxml(net) default_xml.mtu = size default_xml.sync() logging.debug(virsh.net_dumpxml(net)) def set_interface(mtu_size='', source_network='default', iface_type='network', iface_model='virtio'): """ Set mtu size to a certain interface """ interface_type = 'bridge' if iface_type in ( 'bridge', 'openvswitch') else iface_type iface_dict = { 'type': interface_type, 'source': "{'%s': '%s'}" % (interface_type, source_network), 'model': iface_model } if iface_type == 'openvswitch': iface_dict.update({'virtualport_type': 'openvswitch'}) if mtu_size: iface_dict.update({'mtu': "{'size': %s}" % mtu_size}) libvirt.modify_vm_iface(vm_name, 'update_iface', iface_dict) logging.debug(virsh.dumpxml(vm_name).stdout) def get_default_if(): """ Get default interface that is using by vm """ ifaces = utils_net.get_sorted_net_if() logging.debug('Interfaces on host: %s', ifaces) for iface in ifaces[0]: if 'Link detected: yes' in process.run('ethtool %s' % iface).stdout_text: logging.debug('Found host interface "%s"', iface) return iface def create_bridge(): """ Create a bridge on host for test """ cmd_create_br = 'nmcli con add type bridge con-name %s ifname %s' con_name = 'con_' + utils_misc.generate_random_string(3) bridge_name = 'br_' + utils_misc.generate_random_string(3) process.run(cmd_create_br % (con_name, bridge_name), verbose=True) return con_name, bridge_name def create_network_xml(name, network_type, base_if='', **kwargs): """ Create a network xml to be defined """ m_net = NetworkXML(name) m_net.forward = {'mode': 'bridge'} if network_type in ('bridge', 'openvswitch'): m_net.bridge = {'name': kwargs['bridge_name']} elif network_type == 'macvtap': if base_if: m_net.forward_interface = [{'dev': base_if}] if network_type == 'openvswitch': m_net.virtualport_type = 'openvswitch' if 'mtu' in kwargs: m_net.mtu = kwargs['mtu'] logging.debug(m_net) return m_net.xml def create_iface(iface_type, **kwargs): """ Create a interface to be attached to vm """ m_iface = Interface(iface_type) m_iface.mac_address = utils_net.generate_mac_address_simple() if 'base_if' in kwargs: m_iface.source = {'dev': kwargs['base_if'], 'mode': 'vepa'} if 'source_net' in kwargs: m_iface.source = {'network': kwargs['source_net']} if 'mtu' in kwargs: m_iface.mtu = {'size': kwargs['mtu']} if 'model_net' in kwargs: m_iface.model = kwargs['model_net'] logging.debug(m_iface.get_xml()) logging.debug(m_iface) return m_iface def check_mtu(mtu_size, qemu=False): """ Check if mtu meets expectation on host """ error = '' live_vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) iface_xml = live_vmxml.get_devices('interface')[0] logging.debug(iface_xml.target) dev = iface_xml.target['dev'] ifconfig_info = process.run('ifconfig|grep mtu|grep %s' % dev, shell=True, verbose=True).stdout_text if 'mtu %s' % mtu_size in ifconfig_info: logging.info('PASS on ifconfig check for vnet.') else: error += 'Fail on ifconfig check for vnet.' if qemu: qemu_mtu_info = process.run('ps aux|grep qemu-kvm', shell=True, verbose=True).stdout_text if 'host_mtu=%s' % mtu_size in qemu_mtu_info: logging.info('PASS on qemu cmd line check.') else: error += 'Fail on qemu cmd line check.' if error: test.fail(error) def check_mtu_in_vm(fn_login, mtu_size): """ Check if mtu meets expectations in vm """ session = fn_login() check_cmd = 'ifconfig' output = session.cmd(check_cmd) session.close() logging.debug(output) if 'mtu %s' % mtu_size not in output: test.fail('MTU check inside vm failed.') else: logging.debug("MTU check inside vm passed.") try: bk_xml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) bk_netxml = NetworkXML.new_from_net_dumpxml(DEFAULT_NET) if add_pkg: add_pkg = add_pkg.split() utils_package.package_install(add_pkg) if 'openvswitch' in add_pkg: br = 'ovsbr0' + utils_misc.generate_random_string(3) process.run('systemctl start openvswitch.service', shell=True, verbose=True) process.run('ovs-vsctl add-br %s' % br, shell=True, verbose=True) process.run('ovs-vsctl show', shell=True, verbose=True) if not check or check in ['save', 'managedsave', 'hotplug_save']: # Create bridge or network and set mtu iface_type = 'network' if net_type in ('bridge', 'openvswitch'): if net_type == 'bridge': params['con_name'], br = create_bridge() if mtu_type == 'network': test_net = create_network_xml(bridge_name, net_type, bridge_name=br) virsh.net_create(test_net, debug=True) virsh.net_dumpxml(bridge_name, debug=True) if mtu_type == 'interface': iface_type = net_type bridge_name = br elif net_type == 'network': if mtu_type == 'network': set_network(mtu_size) iface_mtu = 0 if mtu_type == 'interface': iface_mtu = mtu_size if mtu_type == 'network' and with_iface: mtu_size = str(int(mtu_size) // 2) iface_mtu = mtu_size source_net = bridge_name if net_type in ( 'bridge', 'openvswitch') else 'default' # set mtu in vm interface set_interface(iface_mtu, source_network=source_net, iface_type=iface_type, iface_model=model) vm.start() vm_login = vm.wait_for_serial_login if net_type in ( 'bridge', 'openvswitch') else vm.wait_for_login vm_login().close() check_qemu = True if mtu_type == 'interface' else False # Test mtu after save vm if check in ('save', 'hotplug_save'): if check == 'hotplug_save': iface = create_iface('network', source_net='default', mtu=mtu_size, model_net=model) params['mac'] = iface.mac_address virsh.attach_device(vm_name, iface.xml, debug=True) virsh.dumpxml(vm_name, debug=True) dom_xml = vm_xml.VMXML.new_from_dumpxml(vm_name) if params['mac'] not in str(dom_xml): test.fail('Failed to attach interface with mtu') save_path = os.path.join(data_dir.get_tmp_dir(), vm_name + '.save') virsh.save(vm_name, save_path, debug=True) virsh.restore(save_path, debug=True) if check == 'managedsave': virsh.managedsave(vm_name, debug=True) virsh.start(vm_name, debug=True) # Check in both host and vm check_mtu(mtu_size, check_qemu) if mtu_type == 'interface' or with_iface: check_mtu_in_vm(vm_login, mtu_size) vm_login(timeout=60).close() if check == 'hotplug_save': virsh.detach_interface(vm_name, 'network %s' % params['mac'], debug=True) time.sleep(5) dom_xml = vm_xml.VMXML.new_from_dumpxml(vm_name) if params['mac'] in str(dom_xml): test.fail( 'Failed to detach interface with mtu after save-restore' ) else: hotplug = 'yes' == params.get('hotplug', 'False') if check == 'net_update': result = virsh.net_update(DEFAULT_NET, 'modify', 'mtu', '''"<mtu size='%s'/>"''' % mtu_size, debug=True) if check in ('macvtap', 'bridge_net', 'ovswitch_net'): base_if = get_default_if() macv_name = 'direct-macvtap' + utils_misc.generate_random_string( 3) # Test mtu in different type of network if mtu_type == 'network': if check == 'macvtap': test_net = create_network_xml(macv_name, 'macvtap', base_if, mtu=mtu_size) if check == 'bridge_net': params['con_name'], br = create_bridge() test_net = create_network_xml(bridge_name, 'bridge', mtu=mtu_size, bridge_name=br) if check == 'ovswitch_net': test_net = create_network_xml(bridge_name, 'openvswitch', mtu=mtu_size, bridge_name=br) if 'net_create' in params['id']: result = virsh.net_create(test_net, debug=True) if 'net_define' in params['id']: result = virsh.net_define(test_net, debug=True) # Test mtu with or without a binding network elif mtu_type == 'interface': vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) if with_net: test_net = create_network_xml(macv_name, 'macvtap', base_if) virsh.net_create(test_net, debug=True) iface = create_iface('network', source_net=macv_name, mtu=mtu_size, model_net=model) if hotplug: result = virsh.attach_device(vm_name, iface.xml, debug=True) else: vmxml.add_device(iface) vmxml.sync() result = virsh.start(vm_name) else: iface = create_iface('direct', base_if=base_if, mtu=mtu_size, model_net=model) if hotplug: result = virsh.attach_device(vm_name, iface.xml, debug=True) else: vmxml.add_device(iface) result = virsh.define(vmxml.xml, debug=True) if check == 'invalid_val': iface = create_iface('network', source_net='default', mtu=mtu_size, model_net=model) result = virsh.attach_device(vm_name, iface.xml, debug=True) # Check result libvirt.check_exit_status(result, status_error) libvirt.check_result(result, [error_msg]) finally: bk_xml.sync() bk_netxml.sync() if 'test_net' in locals(): virsh.net_destroy(bridge_name, debug=True) if params.get('con_name'): process.run('nmcli con del %s' % params['con_name'], verbose=True) if add_pkg: process.run("ovs-vsctl del-br %s" % br, verbose=True) utils_package.package_remove(add_pkg)
def run(test, params, env): """ Test various options of virt-v2v. """ if utils_v2v.V2V_EXEC is None: raise ValueError('Missing command: virt-v2v') for v in list(params.values()): if "V2V_EXAMPLE" in v: test.cancel("Please set real value for %s" % v) version_requried = params.get("version_requried") vm_name = params.get("main_vm", "EXAMPLE") new_vm_name = params.get("new_vm_name") input_mode = params.get("input_mode") input_file = params.get("input_file") v2v_options = params.get("v2v_options", "") hypervisor = params.get("hypervisor", "kvm") remote_host = params.get("remote_host", "EXAMPLE") vpx_dc = params.get("vpx_dc", "EXAMPLE") esx_ip = params.get("esx_ip", "EXAMPLE") source_user = params.get("username", "root") output_mode = params.get("output_mode") output_storage = params.get("output_storage", "default") disk_img = params.get("input_disk_image", "") nfs_storage = params.get("storage") no_root = 'yes' == params.get('no_root', 'no') mnt_point = params.get("mnt_point") export_domain_uuid = params.get("export_domain_uuid", "") fake_domain_uuid = params.get("fake_domain_uuid") vdsm_image_uuid = params.get("vdsm_image_uuid") vdsm_vol_uuid = params.get("vdsm_vol_uuid") vdsm_vm_uuid = params.get("vdsm_vm_uuid") vdsm_ovf_output = params.get("vdsm_ovf_output") v2v_user = params.get("unprivileged_user", "") v2v_timeout = int(params.get("v2v_timeout", 1200)) status_error = "yes" == params.get("status_error", "no") su_cmd = "su - %s -c " % v2v_user output_uri = params.get("oc_uri", "") pool_name = params.get("pool_name", "v2v_test") pool_type = params.get("pool_type", "dir") pool_target = params.get("pool_target", "v2v_pool") emulated_img = params.get("emulated_image_path", "v2v-emulated-img") pvt = utlv.PoolVolumeTest(test, params) new_v2v_user = False address_cache = env.get('address_cache') params['vmcheck_flag'] = False checkpoint = params.get('checkpoint', '') error_flag = 'strict' estimate_file = '' def create_pool(user_pool=False, pool_name=pool_name, pool_target=pool_target): """ Create libvirt pool as the output storage """ if output_uri == "qemu:///session" or user_pool: target_path = os.path.join("/home", v2v_user, pool_target) cmd = su_cmd + "'mkdir -p %s'" % target_path process.system(cmd, verbose=True) # Sometimes pool_creat_as returns sucess, but the pool can # not be found in user session. virsh.pool_create_as(pool_name, 'dir', target_path, unprivileged_user=v2v_user, debug=True) res = virsh.pool_info(pool_name, unprivileged_user=v2v_user, debug=True) if res.exit_status != 0: return False else: pvt.pre_pool(pool_name, pool_type, pool_target, emulated_img) return True def cleanup_pool(user_pool=False, pool_name=pool_name, pool_target=pool_target): """ Clean up libvirt pool """ if output_uri == "qemu:///session" or user_pool: virsh.pool_destroy(pool_name, unprivileged_user=v2v_user, debug=True) target_path = os.path.join("/home", v2v_user, pool_target) cmd = su_cmd + "'rm -rf %s'" % target_path process.system(cmd, verbose=True) else: pvt.cleanup_pool(pool_name, pool_type, pool_target, emulated_img) def get_all_uuids(output): """ Get export domain uuid, image uuid and vol uuid from command output. """ tmp_target = re.findall(r"qemu-img\s'convert'\s.+\s'(\S+)'\n", output) if len(tmp_target) < 1: test.error("Fail to find tmp target file name when converting vm" " disk image") targets = tmp_target[0].split('/') return (targets[3], targets[5], targets[6]) def get_ovf_content(output): """ Find and read ovf file. """ export_domain_uuid, _, vol_uuid = get_all_uuids(output) export_vm_dir = os.path.join(mnt_point, export_domain_uuid, 'master/vms') ovf_content = "" if os.path.isdir(export_vm_dir): ovf_id = "ovf:id='%s'" % vol_uuid ret = to_text( process.system_output("grep -R \"%s\" %s" % (ovf_id, export_vm_dir))) ovf_file = ret.split(":")[0] if os.path.isfile(ovf_file): ovf_f = open(ovf_file, "r") ovf_content = ovf_f.read() ovf_f.close() else: logging.error("Can't find ovf file to read") return ovf_content def get_img_path(output): """ Get the full path of the converted image. """ img_name = vm_name + "-sda" if output_mode == "libvirt": img_path = virsh.vol_path(img_name, output_storage).stdout.strip() elif output_mode == "local": img_path = os.path.join(output_storage, img_name) elif output_mode in ["rhev", "vdsm"]: export_domain_uuid, image_uuid, vol_uuid = get_all_uuids(output) img_path = os.path.join(mnt_point, export_domain_uuid, 'images', image_uuid, vol_uuid) return img_path def check_vmtype(ovf, expected_vmtype): """ Verify vmtype in ovf file. """ if output_mode != "rhev": return if expected_vmtype == "server": vmtype_int = 1 elif expected_vmtype == "desktop": vmtype_int = 0 else: return if "<VmType>%s</VmType>" % vmtype_int in ovf: logging.info("Find VmType=%s in ovf file", expected_vmtype) else: test.fail("VmType check failed") def check_image(img_path, check_point, expected_value): """ Verify image file allocation mode and format """ if not img_path or not os.path.isfile(img_path): test.error("Image path: '%s' is invalid" % img_path) img_info = utils_misc.get_image_info(img_path) logging.debug("Image info: %s", img_info) if check_point == "allocation": if expected_value == "sparse": if img_info['vsize'] > img_info['dsize']: logging.info("%s is a sparse image", img_path) else: test.fail("%s is not a sparse image" % img_path) elif expected_value == "preallocated": if img_info['vsize'] <= img_info['dsize']: logging.info("%s is a preallocated image", img_path) else: test.fail("%s is not a preallocated image" % img_path) if check_point == "format": if expected_value == img_info['format']: logging.info("%s format is %s", img_path, expected_value) else: test.fail("%s format is not %s" % (img_path, expected_value)) def check_new_name(output, expected_name): """ Verify guest name changed to the new name. """ found = False if output_mode == "libvirt": found = virsh.domain_exists(expected_name) if output_mode == "local": found = os.path.isfile( os.path.join(output_storage, expected_name + "-sda")) if output_mode in ["rhev", "vdsm"]: ovf = get_ovf_content(output) found = "<Name>%s</Name>" % expected_name in ovf else: return if found: logging.info("Guest name renamed when converting it") else: test.fail("Rename guest failed") def check_nocopy(output): """ Verify no image created if convert command use --no-copy option """ img_path = get_img_path(output) if not os.path.isfile(img_path): logging.info("No image created with --no-copy option") else: test.fail("Find %s" % img_path) def check_connection(output, expected_uri): """ Check output connection uri used when converting guest """ init_msg = "Initializing the target -o libvirt -oc %s" % expected_uri if init_msg in output: logging.info("Find message: %s", init_msg) else: test.fail("Not find message: %s" % init_msg) def check_ovf_snapshot_id(ovf_content): """ Check if snapshot id in ovf file consists of '0's """ search = re.search("ovf:vm_snapshot_id='(.*?)'", ovf_content) if search: snapshot_id = search.group(1) logging.debug('vm_snapshot_id = %s', snapshot_id) if snapshot_id.count('0') >= 32: test.fail('vm_snapshot_id consists with "0"') else: test.fail('Fail to find snapshot_id') def check_source(output): """ Check if --print-source option print the correct info """ # Parse source info source = output.split('\n')[2:] for i in range(len(source)): if source[i].startswith('\t'): source[i - 1] += source[i] source[i] = '' source_strip = [x.strip() for x in source if x.strip()] source_info = {} for line in source_strip: source_info[line.split(':')[0]] = line.split(':', 1)[1].strip() logging.debug('Source info to check: %s', source_info) checklist = [ 'nr vCPUs', 'hypervisor type', 'source name', 'memory', 'disks', 'NICs' ] if hypervisor in ['kvm', 'xen']: checklist.extend(['display', 'CPU features']) for key in checklist: if key not in source_info: test.fail('%s info missing' % key) v2v_virsh = None close_virsh = False if hypervisor == 'kvm': v2v_virsh = virsh else: virsh_dargs = { 'uri': ic_uri, 'remote_ip': remote_host, 'remote_user': source_user, 'remote_pwd': source_pwd, 'auto_close': True, 'debug': True } v2v_virsh = virsh.VirshPersistent(**virsh_dargs) logging.debug('a new virsh session %s was created', v2v_virsh) close_virsh = True # Check single values fail = [] try: xml = vm_xml.VMXML.new_from_inactive_dumpxml( vm_name, virsh_instance=v2v_virsh) finally: if close_virsh: logging.debug('virsh session %s is closing', v2v_virsh) v2v_virsh.close_session() check_map = {} check_map['nr vCPUs'] = xml.vcpu check_map['hypervisor type'] = xml.hypervisor_type check_map['source name'] = xml.vm_name check_map['memory'] = str(int(xml.max_mem) * 1024) + ' (bytes)' if hypervisor in ['kvm', 'xen']: check_map['display'] = xml.get_graphics_devices()[0].type_name logging.info('KEY:\tSOURCE<-> XML') for key in check_map: logging.info('%-15s:%18s <-> %s', key, source_info[key], check_map[key]) if str(check_map[key]) not in source_info[key]: fail.append(key) # Check disk info disk = list(xml.get_disk_all_by_expr('device==disk').values())[0] def _get_disk_subelement_attr_value(obj, attr, subattr): if obj.find(attr) is not None: return obj.find(attr).get(subattr) bus = _get_disk_subelement_attr_value(disk, 'target', 'bus') driver_type = _get_disk_subelement_attr_value(disk, 'driver', 'type') path = _get_disk_subelement_attr_value(disk, 'source', 'file') # For esx, disk output is like "disks: json: { ... } (raw) [scsi]" # For xen, disk output is like "disks: json: { ... } [ide]" # For kvm, disk output is like "/rhel8.0-2.qcow2 (qcow2) [virtio-blk]" if hypervisor == 'kvm': disks_info_pattern = r"%s \(%s\) \[%s" % (path, driver_type, bus) elif hypervisor == 'esx': # replace '.vmdk' with '-flat.vmdk', this is done in v2v path_pattern1 = path.split()[1].replace('.vmdk', '-flat.vmdk') # In newer qemu version, '_' is replaced with '%5f'. path_pattern2 = path_pattern1.replace('_', '%5f') # nbd:unix:/tmp/v2vnbdkit.u44G6C/nbdkit1.sock:exportname=/ (raw) # [scsi] path_pattern_nbd = r'nbd:unix:/.*? \(raw\) \[%s\]' % bus # For esx, '(raw)' is fixed? Let's see if others will be met. disks_info_pattern = '|'.join([path_pattern_nbd] + [ r"https://%s/folder/%s\?dcPath=data&dsName=esx.*} \(raw\) \[%s" % (remote_host, i, bus) for i in [path_pattern1, path_pattern2] ]) elif hypervisor == 'xen': disks_info_pattern = "file\.path.*%s.*file\.host.*%s.* \[%s" % ( path, remote_host, bus) source_disks = source_info['disks'].split() logging.info('disks:%s<->%s', source_info['disks'], disks_info_pattern) if not re.search(disks_info_pattern, source_info['disks']): fail.append('disks') # Check nic info nic = list(xml.get_iface_all().values())[0] type = nic.get('type') mac = nic.find('mac').get('address') nic_source = nic.find('source') name = nic_source.get(type) nic_info = '%s "%s" mac: %s' % (type, name, mac) logging.info('NICs:%s<->%s', source_info['NICs'], nic_info) if nic_info.lower() not in source_info['NICs'].lower(): fail.append('NICs') # Check cpu features if hypervisor in ['kvm', 'xen']: feature_list = xml.features.get_feature_list() logging.info('CPU features:%s<->%s', source_info['CPU features'], feature_list) if sorted(source_info['CPU features'].split(',')) != sorted( feature_list): fail.append('CPU features') if fail: test.fail('Source info not correct for: %s' % fail) def check_man_page(in_man, not_in_man): """ Check if content of man page or help info meets expectation """ man_page = process.run('man virt-v2v', verbose=False).stdout_text.strip() if in_man: logging.info('Checking man page of virt-v2v for "%s"', in_man) if in_man not in man_page: test.fail('"%s" not in man page' % in_man) if not_in_man: logging.info('Checking man page of virt-v2v for "%s"', not_in_man) if not_in_man in man_page: test.fail('"%s" not removed from man page' % not_in_man) def check_print_estimate(estimate_file): """ Check disk size and total size in file of estimate created by v2v """ import json content = None buf = '' with open(estimate_file) as fp: all_content = fp.read() fp.seek(0) for line in fp: buf += line if '}' not in line: continue if 'disks' in buf and 'total' in buf: content = json.loads(buf) break buf = '' logging.debug('json file content:\n%s' % all_content) if not content or sum(content['disks']) != content['total']: test.fail("The disks' size doesn't same as total value") def check_result(cmd, result, status_error): """ Check virt-v2v command result """ utils_v2v.check_exit_status(result, status_error, error_flag) output = to_text(result.stdout + result.stderr, errors=error_flag) output_stdout = to_text(result.stdout, errors=error_flag) if status_error: if checkpoint == 'length_of_error': log_lines = output.split('\n') v2v_start = False for line in log_lines: if line.startswith('virt-v2v:'): v2v_start = True if line.startswith('libvirt:'): v2v_start = False # 76 is the max length in v2v if v2v_start and len(line) > 76: test.fail('Error log longer than 76 charactors: %s' % line) if checkpoint == 'disk_not_exist': vol_list = virsh.vol_list(pool_name) logging.info(vol_list) if vm_name in vol_list.stdout: test.fail('Disk exists for vm %s' % vm_name) else: if output_mode == "rhev" and checkpoint != 'quiet': ovf = get_ovf_content(output) logging.debug("ovf content: %s", ovf) check_ovf_snapshot_id(ovf) if '--vmtype' in cmd: expected_vmtype = re.findall(r"--vmtype\s(\w+)", cmd)[0] check_vmtype(ovf, expected_vmtype) if '-oa' in cmd and '--no-copy' not in cmd: expected_mode = re.findall(r"-oa\s(\w+)", cmd)[0] img_path = get_img_path(output) def check_alloc(): try: check_image(img_path, "allocation", expected_mode) return True except exceptions.TestFail: pass if not utils_misc.wait_for(check_alloc, timeout=600, step=10.0): test.fail('Allocation check failed.') if '-of' in cmd and '--no-copy' not in cmd and '--print-source' not in cmd and checkpoint != 'quiet' and not no_root: expected_format = re.findall(r"-of\s(\w+)", cmd)[0] img_path = get_img_path(output) check_image(img_path, "format", expected_format) if '-on' in cmd: expected_name = re.findall(r"-on\s(\w+)", cmd)[0] check_new_name(output, expected_name) if '--no-copy' in cmd: check_nocopy(output) if '-oc' in cmd: expected_uri = re.findall(r"-oc\s(\S+)", cmd)[0] check_connection(output, expected_uri) if output_mode == "rhev": if not utils_v2v.import_vm_to_ovirt(params, address_cache): test.fail("Import VM failed") else: vmchecker = VMChecker(test, params, env) params['vmchecker'] = vmchecker params['vmcheck_flag'] = True if output_mode == "libvirt": if "qemu:///session" not in v2v_options and not no_root: virsh.start(vm_name, debug=True, ignore_status=False) if checkpoint in ['vmx', 'vmx_ssh']: vmchecker = VMChecker(test, params, env) params['vmchecker'] = vmchecker params['vmcheck_flag'] = True ret = vmchecker.run() if len(ret) == 0: logging.info("All common checkpoints passed") if checkpoint == 'quiet': if len(output.strip().splitlines()) > 10: test.fail('Output is not empty in quiet mode') if checkpoint == 'dependency': if 'libguestfs-winsupport' not in output: test.fail('libguestfs-winsupport not in dependency') if all(pkg_pattern not in output for pkg_pattern in ['VMF', 'edk2-ovmf']): test.fail('OVMF/AAVMF not in dependency') if 'qemu-kvm-rhev' in output: test.fail('qemu-kvm-rhev is in dependency') if 'libX11' in output: test.fail('libX11 is in dependency') if 'kernel-rt' in output: test.fail('kernel-rt is in dependency') win_img = params.get('win_image') command = 'guestfish -a %s -i' if process.run(command % win_img, ignore_status=True).exit_status == 0: test.fail('Command "%s" success' % command % win_img) if checkpoint == 'no_dcpath': if '--dcpath' in output: test.fail('"--dcpath" is not removed') if checkpoint == 'debug_overlays': search = re.search('Overlay saved as(.*)', output) if not search: test.fail('Not find log of saving overlays') overlay_path = search.group(1).strip() logging.debug('Overlay file location: %s' % overlay_path) if os.path.isfile(overlay_path): logging.info('Found overlay file: %s' % overlay_path) else: test.fail('Overlay file not saved') if checkpoint.startswith('empty_nic_source'): target_str = '%s "eth0" mac: %s' % (params[checkpoint][0], params[checkpoint][1]) logging.info('Expect log: %s', target_str) if target_str not in output_stdout.lower(): test.fail('Expect log not found: %s' % target_str) if checkpoint == 'print_source': check_source(output_stdout) if checkpoint == 'machine_readable': if os.path.exists(params.get('example_file', '')): # Checking items in example_file exist in latest # output regardless of the orders and new items. with open(params['example_file']) as f: for line in f: if line.strip() not in output_stdout.strip(): test.fail( '%s not in --machine-readable output' % line.strip()) else: test.error('No content to compare with') if checkpoint == 'compress': img_path = get_img_path(output) logging.info('Image path: %s', img_path) qemu_img_cmd = 'qemu-img check %s' % img_path qemu_img_locking_feature_support = libvirt_storage.check_qemu_image_lock_support( ) if qemu_img_locking_feature_support: qemu_img_cmd = 'qemu-img check %s -U' % img_path disk_check = process.run(qemu_img_cmd).stdout_text logging.info(disk_check) compress_info = disk_check.split(',')[-1].split('%')[0].strip() compress_rate = float(compress_info) logging.info('%s%% compressed', compress_rate) if compress_rate < 0.1: test.fail('Disk image NOT compressed') if checkpoint == 'tail_log': messages = params['tail'].get_output() logging.info('Content of /var/log/messages during conversion:') logging.info(messages) msg_content = params['msg_content'] if msg_content in messages: test.fail('Found "%s" in /var/log/messages' % msg_content) if checkpoint == 'print_estimate_tofile': check_print_estimate(estimate_file) log_check = utils_v2v.check_log(params, output) if log_check: test.fail(log_check) check_man_page(params.get('in_man'), params.get('not_in_man')) backup_xml = None vdsm_domain_dir, vdsm_image_dir, vdsm_vm_dir = ("", "", "") try: if version_requried and not utils_v2v.multiple_versions_compare( version_requried): test.cancel("Testing requries version: %s" % version_requried) if hypervisor == "xen": # See man virt-v2v-input-xen(1) process.run('update-crypto-policies --set LEGACY', verbose=True, ignore_status=True, shell=True) if checkpoint.startswith('empty_nic_source'): xml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) iface = xml.get_devices('interface')[0] disks = xml.get_devices('disk') del iface.source iface.type_name = checkpoint.split('_')[-1] iface.source = {iface.type_name: ''} params[checkpoint] = [iface.type_name, iface.mac_address] logging.debug(iface.source) devices = vm_xml.VMXMLDevices() devices.extend(disks) devices.append(iface) xml.set_devices(devices) logging.info(xml.xmltreefile) params['input_xml'] = xml.xmltreefile.name # Build input options input_option = "" if input_mode is None: pass elif input_mode == "libvirt": uri_obj = utils_v2v.Uri(hypervisor) ic_uri = uri_obj.get_uri(remote_host, vpx_dc, esx_ip) # Remote libvirt connection is not offically supported by # v2v and may fail. Just use localhost to simulate a remote # connection to test the warnings. if checkpoint == 'remote_libvirt_conn': ic_uri = 'qemu+ssh://localhost/system' input_option = "-i %s -ic %s %s" % (input_mode, ic_uri, vm_name) if checkpoint == 'with_ic': ic_uri = 'qemu:///session' input_option = "-i ova %s -ic %s -of qcow2" % (input_file, ic_uri) if checkpoint == 'without_ic': input_option = "-i ova %s -of raw" % input_file # Build network&bridge option to avoid network error v2v_options += " -b %s -n %s" % (params.get("output_bridge"), params.get("output_network")) elif input_mode == "disk": input_option += "-i %s %s" % (input_mode, disk_img) elif input_mode == 'libvirtxml': input_xml = params.get('input_xml') input_option += '-i %s %s' % (input_mode, input_xml) elif input_mode in ['ova']: test.cancel("Unsupported input mode: %s" % input_mode) else: test.error("Unknown input mode %s" % input_mode) input_format = params.get("input_format", "") input_allo_mode = params.get("input_allo_mode") if input_format: input_option += " -if %s" % input_format if not status_error: logging.info("Check image before convert") check_image(disk_img, "format", input_format) if input_allo_mode: check_image(disk_img, "allocation", input_allo_mode) # Build output options output_option = "" if output_mode: output_option = "-o %s" % output_mode if output_mode != 'null': output_option += " -os %s" % output_storage if checkpoint == 'rhv': output_option = output_option.replace('rhev', 'rhv') if checkpoint in ['with_ic', 'without_ic']: output_option = output_option.replace('v2v_dir', 'src_pool') output_format = params.get("output_format") if output_format and output_format != input_format: output_option += " -of %s" % output_format output_allo_mode = params.get("output_allo_mode") if output_allo_mode: output_option += " -oa %s" % output_allo_mode # Build vdsm related options if output_mode in ['vdsm', 'rhev']: if not os.path.isdir(mnt_point): os.mkdir(mnt_point) if not utils_misc.mount(nfs_storage, mnt_point, "nfs"): test.error("Mount NFS Failed") if output_mode == 'vdsm': v2v_options += " --vdsm-image-uuid %s" % vdsm_image_uuid v2v_options += " --vdsm-vol-uuid %s" % vdsm_vol_uuid v2v_options += " --vdsm-vm-uuid %s" % vdsm_vm_uuid v2v_options += " --vdsm-ovf-output %s" % vdsm_ovf_output vdsm_domain_dir = os.path.join(mnt_point, fake_domain_uuid) vdsm_image_dir = os.path.join(mnt_point, export_domain_uuid, "images", vdsm_image_uuid) vdsm_vm_dir = os.path.join(mnt_point, export_domain_uuid, "master/vms", vdsm_vm_uuid) # For vdsm_domain_dir, just create a dir to test BZ#1176591 os.makedirs(vdsm_domain_dir) os.makedirs(vdsm_image_dir) os.makedirs(vdsm_vm_dir) if output_mode == 'rhev': # create different sasl_user name for different job params.update({ 'sasl_user': params.get("sasl_user") + utils_misc.generate_random_string(3) }) logging.info('sals user name is %s' % params.get("sasl_user")) user_pwd = "[['%s', '%s']]" % (params.get("sasl_user"), params.get("sasl_pwd")) v2v_sasl = utils_sasl.SASL(sasl_user_pwd=user_pwd) v2v_sasl.server_ip = params.get("remote_ip") v2v_sasl.server_user = params.get('remote_user') v2v_sasl.server_pwd = params.get('remote_pwd') v2v_sasl.setup(remote=True) logging.debug('A SASL session %s was created', v2v_sasl) # Output more messages except quiet mode if checkpoint == 'quiet': v2v_options += ' -q' elif checkpoint not in [ 'length_of_error', 'empty_nic_source_network', 'empty_nic_source_bridge', 'machine_readable' ]: v2v_options += " -v -x" # Prepare for libvirt unprivileged user session connection if "qemu:///session" in v2v_options or no_root: try: pwd.getpwnam(v2v_user) except KeyError: # create new user process.system("useradd %s" % v2v_user, ignore_status=True) new_v2v_user = True user_info = pwd.getpwnam(v2v_user) logging.info("Convert to qemu:///session by user '%s'", v2v_user) if input_mode == "disk": # Copy image from souce and change the image owner and group disk_path = os.path.join(data_dir.get_tmp_dir(), os.path.basename(disk_img)) logging.info('Copy image file %s to %s', disk_img, disk_path) shutil.copyfile(disk_img, disk_path) input_option = input_option.replace(disk_img, disk_path) os.chown(disk_path, user_info.pw_uid, user_info.pw_gid) elif not no_root: test.cancel("Only support convert local disk") # Setup ssh-agent access to xen hypervisor if hypervisor == 'xen': user = params.get("xen_host_user", "root") source_pwd = passwd = params.get("xen_host_passwd", "redhat") logging.info("set up ssh-agent access ") xen_pubkey, xen_session = utils_v2v.v2v_setup_ssh_key( remote_host, user, passwd, auto_close=False) utils_misc.add_identities_into_ssh_agent() # Check if xen guest exists uri = utils_v2v.Uri(hypervisor).get_uri(remote_host) if not virsh.domain_exists(vm_name, uri=uri): logging.error('VM %s not exists', vm_name) # If the input format is not define, we need to either define # the original format in the source metadata(xml) or use '-of' # to force the output format, see BZ#1141723 for detail. if '-of' not in v2v_options and checkpoint != 'xen_no_output_format': v2v_options += ' -of %s' % params.get("default_output_format", "qcow2") # Create password file for access to ESX hypervisor if hypervisor == 'esx': source_pwd = vpx_passwd = params.get("vpx_password") vpx_passwd_file = os.path.join(data_dir.get_tmp_dir(), "vpx_passwd") logging.info("Building ESX no password interactive verification.") pwd_f = open(vpx_passwd_file, 'w') pwd_f.write(vpx_passwd) pwd_f.close() output_option += " -ip %s" % vpx_passwd_file # rhel8 slow stream doesn't support option 'ip' temporarily # so use option 'password-file' instead. if not utils_v2v.v2v_supported_option("-ip <filename>"): output_option = output_option.replace('-ip', '--password-file', 1) # if don't specify any output option for virt-v2v, 'default' pool # will be used. if output_mode is None: # Cleanup first to avoid failure if 'default' pool exists. pvt.cleanup_pool(pool_name, pool_type, pool_target, emulated_img) pvt.pre_pool(pool_name, pool_type, pool_target, emulated_img) # Create libvirt dir pool if output_mode == "libvirt": utils_misc.wait_for(create_pool, timeout=30, step=3) # Work around till bug fixed os.environ['LIBGUESTFS_BACKEND'] = 'direct' if checkpoint in ['with_ic', 'without_ic']: new_v2v_user = True v2v_options += ' -on %s' % new_vm_name utils_misc.wait_for( lambda: create_pool(user_pool=True, pool_name='src_pool', pool_target='v2v_src_pool'), timeout=30, step=3) if checkpoint == 'vmx': mount_point = params.get('mount_point') if not os.path.isdir(mount_point): os.mkdir(mount_point) nfs_vmx = params.get('nfs_vmx') if not utils_misc.mount(nfs_vmx, mount_point, 'nfs', verbose=True): test.error('Mount nfs for vmx failed') vmx = params.get('vmx') input_option = '-i vmx %s' % vmx v2v_options += " -b %s -n %s" % (params.get("output_bridge"), params.get("output_network")) if checkpoint == 'vmx_ssh': esx_user = params.get("esx_host_user", "root") esx_pwd = params.get("esx_host_passwd") vmx = params.get('vmx') esx_pubkey, esx_session = utils_v2v.v2v_setup_ssh_key( esx_ip, esx_user, esx_pwd, server_type='esx', auto_close=False) utils_misc.add_identities_into_ssh_agent() input_option = '-i vmx -it ssh %s' % vmx v2v_options += " -b %s -n %s" % (params.get("output_bridge"), params.get("output_network")) if checkpoint == 'simulate_nfs': simulate_images = params.get("simu_images_path") simulate_vms = params.get("simu_vms_path") simulate_dom_md = params.get("simu_dom_md_path") os.makedirs(simulate_images) os.makedirs(simulate_vms) process.run('touch %s' % simulate_dom_md) process.run('chmod -R 777 /tmp/rhv/') if checkpoint == 'print_estimate_tofile': estimate_file = utils_misc.generate_tmp_file_name( 'v2v_print_estimate') v2v_options += " --machine-readable=file:%s" % estimate_file if checkpoint == 'remote_libvirt_conn': # Add localhost to known_hosts cmd = 'ssh-keyscan -t ecdsa localhost >> ~/.ssh/known_hosts' process.run(cmd, shell=True) # Setup remote login without password public_key = ssh_key.get_public_key().rstrip() cmd = 'echo "%s" >> ~/.ssh/authorized_keys' % public_key process.run(cmd, shell=True) # Running virt-v2v command cmd = "%s %s %s %s" % (utils_v2v.V2V_EXEC, input_option, output_option, v2v_options) if v2v_user: cmd_export_env = 'export LIBGUESTFS_BACKEND=direct' cmd = "%s '%s;%s'" % (su_cmd, cmd_export_env, cmd) if params.get('cmd_free') == 'yes': cmd = params.get('check_command') # only set error to 'ignore' to avoid exception for RHEL7-84978 if "guestfish" in cmd: error_flag = "replace" # Set timeout to kill v2v process before conversion succeed if checkpoint == 'disk_not_exist': v2v_timeout = 30 # Get tail content of /var/log/messages if checkpoint == 'tail_log': params['tail_log'] = os.path.join(data_dir.get_tmp_dir(), 'tail_log') params['tail'] = aexpect.Tail(command='tail -f /var/log/messages', output_func=utils_misc.log_line, output_params=(params['tail_log'], )) cmd_result = process.run(cmd, timeout=v2v_timeout, verbose=True, ignore_status=True) if new_vm_name: vm_name = new_vm_name params['main_vm'] = new_vm_name check_result(cmd, cmd_result, status_error) finally: if hypervisor == "esx": process.run("rm -rf %s" % vpx_passwd_file) if checkpoint == "weak_dendency": utils_package.package_install(['libguestfs-xfs', 'virt-v2v']) for vdsm_dir in [vdsm_domain_dir, vdsm_image_dir, vdsm_vm_dir]: if os.path.exists(vdsm_dir): shutil.rmtree(vdsm_dir) if os.path.exists(mnt_point): utils_misc.umount(nfs_storage, mnt_point, "nfs") os.rmdir(mnt_point) if output_mode == "local": image_name = vm_name + "-sda" img_file = os.path.join(output_storage, image_name) xml_file = img_file + ".xml" for local_file in [img_file, xml_file]: if os.path.exists(local_file): os.remove(local_file) if output_mode == "libvirt": if "qemu:///session" in v2v_options or no_root: cmd = su_cmd + "'virsh undefine %s'" % vm_name try: process.system(cmd) except Exception: logging.error('Undefine "%s" failed', vm_name) if no_root: cleanup_pool(user_pool=True, pool_name='src_pool', pool_target='v2v_src_pool') else: virsh.remove_domain(vm_name) cleanup_pool() if output_mode is None: pvt.cleanup_pool(pool_name, pool_type, pool_target, emulated_img) vmcheck_flag = params.get("vmcheck_flag") if vmcheck_flag and params.get('vmchecker'): params['vmchecker'].cleanup() if new_v2v_user: process.system("userdel -fr %s" % v2v_user) if backup_xml: backup_xml.sync() if output_mode == 'rhev' and v2v_sasl: v2v_sasl.cleanup() logging.debug('SASL session %s is closing', v2v_sasl) v2v_sasl.close_session() if checkpoint == 'vmx': utils_misc.umount(params['nfs_vmx'], params['mount_point'], 'nfs') os.rmdir(params['mount_point']) if checkpoint == 'vmx_ssh': utils_v2v.v2v_setup_ssh_key_cleanup(esx_session, esx_pubkey, 'esx') process.run("ssh-agent -k") if checkpoint == 'simulate_nfs': process.run('rm -rf /tmp/rhv/') if os.path.exists(estimate_file): os.remove(estimate_file) if hypervisor == "xen": # Restore crypto-policies to DEFAULT, the setting is impossible to be # other values by default in testing envrionment. process.run('update-crypto-policies --set DEFAULT', verbose=True, ignore_status=True, shell=True) utils_v2v.v2v_setup_ssh_key_cleanup(xen_session, xen_pubkey) process.run("ssh-agent -k") if checkpoint == 'remote_libvirt_conn': cmd = r"sed -i '/localhost/d' ~/.ssh/known_hosts" process.run(cmd, shell=True, ignore_status=True) if locals().get('public_key'): key = public_key.rstrip().split()[1].split('/')[0] cmd = r"sed -i '/%s/d' ~/.ssh/authorized_keys" % key process.run(cmd, shell=True, ignore_status=True)
def run(test, params, env): """ Test command: virsh domif-setlink and domif-getlink. The command set and get link state of a virtual interface 1. Prepare test environment. 2. Perform virsh domif-setlink and domif-getlink operation. 3. Recover test environment. 4. Confirm the test result. """ def domif_setlink(vm, device, operation, options): """ Set the domain link state :param vm : domain name :param device : domain virtual interface :param opration : domain virtual interface state :param options : some options like --config """ return virsh.domif_setlink(vm, device, operation, options, debug=True) def domif_getlink(vm, device, options): """ Get the domain link state :param vm : domain name :param device : domain virtual interface :param options : some options like --config """ return virsh.domif_getlink(vm, device, options, ignore_status=True, debug=True) def guest_cmd_check(cmd, session, pattern): """ Check cmd output with pattern in session """ try: cmd_status, output = session.cmd_status_output(cmd, timeout=10) logging.info("exit: %s, output: %s", cmd_status, output) return re.search(pattern, output) except (aexpect.ShellTimeoutError, aexpect.ShellStatusError) as e: logging.debug(e) return re.search(pattern, str(e.__str__)) def guest_if_state(if_name, session): """ Get the domain link state from the guest """ # Get link state by ethtool cmd = "ethtool %s" % if_name pattern = "Link detected: ([a-zA-Z]+)" ret = guest_cmd_check(cmd, session, pattern) if ret: return ret.group(1) == "yes" else: return False def check_update_device(vm, if_name, session): """ Change link state by upadte-device command, Check the results """ vmxml = vm_xml.VMXML.new_from_dumpxml(vm.name) # Get interface xml object iface = vmxml.get_devices(device_type="interface")[0] if iface.address: del iface.address # Change link state to up iface.link_state = "up" iface.xmltreefile.write() ret = virsh.update_device(vm.name, iface.xml, ignore_status=True, debug=True) if ret.exit_status: logging.error("Failed to update device to up state") return False if not guest_if_state(if_name, session): logging.error("Guest link should be up now") return False # Change link state to down iface.link_state = "down" iface.xmltreefile.write() ret = virsh.update_device(vm.name, iface.xml, ignore_status=True, debug=True) if ret.exit_status: logging.error("Failed to update device to down state") return False if guest_if_state(if_name, session): logging.error("Guest link should be down now") return False # Passed all test return True vm_name = [] # vm_name list:first element for original name in config vm_name.append(params.get("main_vm", "avocado-vt-vm1")) vm = env.get_vm(vm_name[0]) options = params.get("if_options", "--config") start_vm = params.get("start_vm", "no") domain = params.get("domain", "name") if_device = params.get("if_device", "net") if_name = params.get("if_name", "vnet0") if_operation = params.get("if_operation", "up") status_error = params.get("status_error", "no") mac_address = vm.get_virsh_mac_address(0) check_link_state = "yes" == params.get("check_link_state", "no") check_link_by_update_device = "yes" == params.get("excute_update_device", "no") device = "vnet0" username = params.get("username") password = params.get("password") # Back up xml file. vm_xml_file = os.path.join(test.tmpdir, "vm.xml") virsh.dumpxml(vm_name[0], extra="--inactive", to_file=vm_xml_file) # Vm status if start_vm == "yes" and vm.is_dead(): vm.start() elif start_vm == "no" and vm.is_alive(): vm.destroy() # vm_name list: second element for 'domain' in virsh command if domain == "ID": # Get ID for the running domain vm_name.append(vm.get_id()) elif domain == "UUID": # Get UUID for the domain vm_name.append(vm.get_uuid()) elif domain == "no_match_UUID": # Generate a random UUID vm_name.append(uuid.uuid1()) elif domain == "no_match_name": # Generate a random string as domain name vm_name.append(utils_misc.generate_random_string(6)) elif domain == " ": # Set domain name empty vm_name.append("''") else: # Set domain name vm_name.append(vm_name[0]) try: # Test device net or mac address if if_device == "net" and vm.is_alive(): device = if_name # Get all vm's interface device device = vm_xml.VMXML.get_net_dev(vm_name[0])[0] elif if_device == "mac": device = mac_address # Test no exist device if if_device == "no_exist_net": device = "vnet-1" elif if_device == "no_exist_mac": # Generate random mac address for negative test device = utils_net.VirtIface.complete_mac_address("01:02") elif if_device == " ": device = "''" # Setlink opertation result = domif_setlink(vm_name[1], device, if_operation, options) status = result.exit_status logging.info("Setlink done") # Getlink opertation get_result = domif_getlink(vm_name[1], device, options) getlink_output = get_result.stdout.strip() # Check the getlink command output if status_error == "no": if not re.search(if_operation, getlink_output): test.fail("Getlink result should " "equal with setlink operation") logging.info("Getlink done") # If --config is given should restart the vm then test link status if options == "--config" and vm.is_alive(): vm.destroy() vm.start() logging.info("Restart VM") elif start_vm == "no": vm.start() error_msg = None if status_error == "no": # Serial login the vm to check link status # Start vm check the link statue session = vm.wait_for_serial_login(username=username, password=password) guest_if_name = utils_net.get_linux_ifname(session, mac_address) # Check link state in guest if check_link_state: if (if_operation == "up" and not guest_if_state(guest_if_name, session)): error_msg = "Link state should be up in guest" if (if_operation == "down" and guest_if_state(guest_if_name, session)): error_msg = "Link state should be down in guest" # Test of setting link state by update_device command if check_link_by_update_device: if not check_update_device(vm, guest_if_name, session): error_msg = "Check update_device failed" # Set the link up make host connect with vm domif_setlink(vm_name[0], device, "up", "") if not utils_misc.wait_for( lambda: guest_if_state(guest_if_name, session), 5): error_msg = "Link state isn't up in guest" # Ignore status of this one cmd = 'ifdown %s' % guest_if_name pattern = "Device '%s' successfully disconnected" % guest_if_name guest_cmd_check(cmd, session, pattern) cmd = 'ifup %s' % guest_if_name pattern = "Determining IP information for %s" % guest_if_name pattern += "|Connection successfully activated" if not guest_cmd_check(cmd, session, pattern): error_msg = ("Could not bring up interface %s inside guest" % guest_if_name) else: # negative test # stop guest, so state is always consistent on next start vm.destroy() if error_msg: test.fail(error_msg) # Check status_error if status_error == "yes": if status: logging.info("Expected error (negative testing). Output: %s", result.stderr.strip()) else: test.fail("Unexpected return code %d " "(negative testing)" % status) elif status_error != "no": test.error("Invalid value for status_error '%s' " "(must be 'yes' or 'no')" % status_error) finally: # Recover VM. if vm.is_alive(): vm.destroy(gracefully=False) virsh.undefine(vm_name[0]) virsh.define(vm_xml_file) os.remove(vm_xml_file)
def run(test, params, env): """ Test the tpm virtual devices 1. prepare a guest with different tpm devices 2. check whether the guest can be started 3. check the xml and qemu cmd line, even swtpm for vtpm 4. check tpm usage in guest os """ # Tpm passthrough supported since libvirt 1.0.5. if not libvirt_version.version_compare(1, 0, 5): test.cancel("Tpm device is not supported " "on current libvirt version.") # Tpm passthrough supported since qemu 2.12.0-49. if not utils_misc.compare_qemu_version(2, 9, 0, is_rhev=False): test.cancel("Tpm device is not supported " "on current qemu version.") tpm_model = params.get("tpm_model") backend_type = params.get("backend_type") backend_version = params.get("backend_version") device_path = params.get("device_path") tpm_num = int(params.get("tpm_num", 1)) # After first start of vm with vtpm, do operations, check it still works vm_operate = params.get("vm_operate") # Sub-operation(e.g.domrename) under vm_operate(e.g.restart) vm_oprt = params.get("vm_oprt") secret_uuid = params.get("secret_uuid") secret_value = params.get("secret_value") # Change encryption state: from plain to encrypted, or reverse. encrypt_change = params.get("encrypt_change") secret_uuid = params.get("secret_uuid") prepare_secret = ("yes" == params.get("prepare_secret", "no")) remove_dev = ("yes" == params.get("remove_dev", "no")) multi_vms = ("yes" == params.get("multi_vms", "no")) # Remove swtpm state file rm_statefile = ("yes" == params.get("rm_statefile", "no")) test_suite = ("yes" == params.get("test_suite", "no")) restart_libvirtd = ("yes" == params.get("restart_libvirtd", "no")) no_backend = ("yes" == params.get("no_backend", "no")) status_error = ("yes" == params.get("status_error", "no")) err_msg = params.get("xml_errmsg", "") loader = params.get("loader", "") nvram = params.get("nvram", "") uefi_disk_url = params.get("uefi_disk_url", "") download_file_path = os.path.join(data_dir.get_tmp_dir(), "uefi_disk.qcow2") # Check tpm chip on host for passthrough testing if backend_type == "passthrough": dmesg_info = process.getoutput("dmesg|grep tpm -wi", shell=True) logging.debug("dmesg info about tpm:\n %s", dmesg_info) dmesg_error = re.search("No TPM chip found|TPM is disabled", dmesg_info) if dmesg_error: test.cancel(dmesg_error.group()) else: # Try to check host tpm chip version tpm_v = None if re.search("2.0 TPM", dmesg_info): tpm_v = "2.0" if not utils_package.package_install("tpm2-tools"): # package_install() return 'True' if succeed test.error("Failed to install tpm2-tools on host") else: if re.search("1.2 TPM", dmesg_info): tpm_v = "1.2" # If "1.2 TPM" or no version info in dmesg, try to test a tpm1.2 at first if not utils_package.package_install("tpm-tools"): test.error("Failed to install tpm-tools on host") # Check host env for vtpm testing elif backend_type == "emulator": if not utils_misc.compare_qemu_version(4, 0, 0, is_rhev=False): test.cancel("vtpm(emulator backend) is not supported " "on current qemu version.") # Install swtpm pkgs on host for vtpm emulation if not utils_package.package_install("swtpm*"): test.error("Failed to install swtpm swtpm-tools on host") def replace_os_disk(vm_xml, vm_name, nvram): """ Replace os(nvram) and disk(uefi) for x86 vtpm test :param vm_xml: current vm's xml :param vm_name: current vm name :param nvram: nvram file path of vm """ # Add loader, nvram in <os> nvram = nvram.replace("<VM_NAME>", vm_name) dict_os_attrs = { "loader_readonly": "yes", "secure": "yes", "loader_type": "pflash", "loader": loader, "nvram": nvram } vm_xml.set_os_attrs(**dict_os_attrs) logging.debug("Set smm=on in VMFeaturesXML") # Add smm in <features> features_xml = vm_xml.features features_xml.smm = "on" vm_xml.features = features_xml vm_xml.sync() # Replace disk with an uefi image if not utils_package.package_install("wget"): test.error("Failed to install wget on host") if uefi_disk_url.count("EXAMPLE"): test.error("Please provide the URL %s" % uefi_disk_url) else: download_cmd = ("wget %s -O %s" % (uefi_disk_url, download_file_path)) process.system(download_cmd, verbose=False, shell=True) vm = env.get_vm(vm_name) uefi_disk = {'disk_source_name': download_file_path} libvirt.set_vm_disk(vm, uefi_disk) vm_names = params.get("vms").split() vm_name = vm_names[0] vm = env.get_vm(vm_name) vm_xml = VMXML.new_from_inactive_dumpxml(vm_name) vm_xml_backup = vm_xml.copy() os_xml = getattr(vm_xml, "os") host_arch = platform.machine() if backend_type == "emulator" and host_arch == 'x86_64': if not utils_package.package_install("OVMF"): test.error("Failed to install OVMF or edk2-ovmf pkgs on host") if os_xml.xmltreefile.find('nvram') is None: replace_os_disk(vm_xml, vm_name, nvram) vm_xml = VMXML.new_from_inactive_dumpxml(vm_name) if vm.is_alive(): vm.destroy() vm2 = None if multi_vms: if len(vm_names) > 1: vm2_name = vm_names[1] vm2 = env.get_vm(vm2_name) vm2_xml = VMXML.new_from_inactive_dumpxml(vm2_name) vm2_xml_backup = vm2_xml.copy() else: # Clone additional vms if needed try: utils_path.find_command("virt-clone") except utils_path.CmdNotFoundError: if not utils_package.package_install(["virt-install"]): test.cancel("Failed to install virt-install on host") vm2_name = "vm2_" + utils_misc.generate_random_string(5) ret_clone = utils_libguestfs.virt_clone_cmd(vm_name, vm2_name, True, timeout=360, debug=True) if ret_clone.exit_status: test.error( "Need more than one domains, but error occured when virt-clone." ) vm2 = vm.clone(vm2_name) vm2_xml = VMXML.new_from_inactive_dumpxml(vm2_name) if vm2.is_alive(): vm2.destroy() service_mgr = service.ServiceManager() def check_dumpxml(vm_name): """ Check whether the added devices are shown in the guest xml :param vm_name: current vm name """ logging.info("------Checking guest dumpxml------") if tpm_model: pattern = '<tpm model="%s">' % tpm_model else: # The default tpm model is "tpm-tis" pattern = '<tpm model="tpm-tis">' # Check tpm model xml_after_adding_device = VMXML.new_from_dumpxml(vm_name) logging.debug("xml after add tpm dev is %s", xml_after_adding_device) if pattern not in astring.to_text(xml_after_adding_device): test.fail("Can not find the %s tpm device xml " "in the guest xml file." % tpm_model) # Check backend type pattern = '<backend type="%s"' % backend_type if pattern not in astring.to_text(xml_after_adding_device): test.fail("Can not find the %s backend type xml for tpm dev " "in the guest xml file." % backend_type) # Check backend version if backend_version: pattern = '"emulator" version="%s"' % backend_version if pattern not in astring.to_text(xml_after_adding_device): test.fail( "Can not find the %s backend version xml for tpm dev " "in the guest xml file." % backend_version) # Check device path if backend_type == "passthrough": pattern = '<device path="/dev/tpm0"' if pattern not in astring.to_text(xml_after_adding_device): test.fail("Can not find the %s device path xml for tpm dev " "in the guest xml file." % device_path) # Check encryption secret if prepare_secret: pattern = '<encryption secret="%s" />' % encryption_uuid if pattern not in astring.to_text(xml_after_adding_device): test.fail("Can not find the %s secret uuid xml for tpm dev " "in the guest xml file." % encryption_uuid) logging.info('------PASS on guest dumpxml check------') def check_qemu_cmd_line(vm, vm_name, domid): """ Check whether the added devices are shown in the qemu cmd line :param vm: current vm :param vm_name: current vm name :param domid: domain id for checking vtpm socket file """ logging.info("------Checking qemu cmd line------") if not vm.get_pid(): test.fail('VM pid file missing.') with open('/proc/%s/cmdline' % vm.get_pid()) as cmdline_file: cmdline = cmdline_file.read() logging.debug("Qemu cmd line info:\n %s", cmdline) # Check tpm model pattern_list = ["-device.%s" % tpm_model] # Check backend type if backend_type == "passthrough": dev_num = re.search(r"\d+", device_path).group() backend_segment = "id=tpm-tpm%s" % dev_num else: # emulator backend backend_segment = "id=tpm-tpm0,chardev=chrtpm" pattern_list.append("-tpmdev.%s,%s" % (backend_type, backend_segment)) # Check chardev socket for vtpm if backend_type == "emulator": pattern_list.append( "-chardev.socket,id=chrtpm," "path=.*/run/libvirt/qemu/swtpm/%s-%s-swtpm.sock" % (domid, vm_name)) for pattern in pattern_list: if not re.search(pattern, cmdline): if not remove_dev: test.fail("Can not find the %s for tpm device " "in qemu cmd line." % pattern) elif remove_dev: test.fail("%s still exists after remove vtpm and restart" % pattern) logging.info("------PASS on qemu cmd line check------") def check_swtpm(domid, domuuid, vm_name): """ Check swtpm cmdline and files for vtpm. :param domid: domain id for checking vtpm files :param domuuid: domain uuid for checking vtpm state file :param vm_name: current vm name """ logging.info("------Checking swtpm cmdline and files------") # Check swtpm cmdline swtpm_pid = utils_misc.get_pid("%s-swtpm.pid" % vm_name) if not swtpm_pid: if not remove_dev: test.fail('swtpm pid file missing.') else: return elif remove_dev: test.fail( 'swtpm pid file still exists after remove vtpm and restart') with open('/proc/%s/cmdline' % swtpm_pid) as cmdline_file: cmdline = cmdline_file.read() logging.debug("Swtpm cmd line info:\n %s", cmdline) pattern_list = [ "--daemon", "--ctrl", "--tpmstate", "--log", "--tpm2", "--pid" ] if prepare_secret: pattern_list.extend(["--key", "--migration-key"]) for pattern in pattern_list: if not re.search(pattern, cmdline): test.fail("Can not find the %s for tpm device " "in swtpm cmd line." % pattern) # Check swtpm files file_list = [ "/var/run/libvirt/qemu/swtpm/%s-%s-swtpm.sock" % (domid, vm_name) ] file_list.append("/var/lib/libvirt/swtpm/%s/tpm2" % domuuid) file_list.append("/var/log/swtpm/libvirt/qemu/%s-swtpm.log" % vm_name) file_list.append("/var/run/libvirt/qemu/swtpm/%s-%s-swtpm.pid" % (domid, vm_name)) for swtpm_file in file_list: if not os.path.exists(swtpm_file): test.fail("Swtpm file: %s does not exist" % swtpm_file) logging.info("------PASS on Swtpm cmdline and files check------") def get_tpm2_tools_cmd(session=None): """ Get tpm2-tools pkg version and return corresponding getrandom cmd :session: guest console session :return: tpm2_getrandom cmd usage """ cmd = 'rpm -q tpm2-tools' get_v_tools = session.cmd(cmd) if session else process.run( cmd).stdout_text v_tools_list = get_v_tools.strip().split('-') if session: logging.debug("The tpm2-tools version is %s", v_tools_list[2]) v_tools = int(v_tools_list[2].split('.')[0]) return "tpm2_getrandom 8" if v_tools < 4 else "tpm2_getrandom -T device:/dev/tpm0 8 --hex" def get_host_tpm_bef(tpm_v): """ Test host tpm function and identify its real version before passthrough Since sometimes dmesg info doesn't include tpm msg, need use tpm-tool or tpm2-tools to try the function. :param tpm_v: host tpm version get from dmesg info :return: host tpm version """ logging.info("------Checking host tpm device before passthrough------") # Try tcsd tool for suspected tpm1.2 chip on host tpm_real_v = tpm_v if tpm_v != "2.0": if not service_mgr.start('tcsd'): # service_mgr.start() return 'True' if succeed if tpm_v == "1.2": test.fail("Host tcsd.serivce start failed") else: # Means tpm_v got nothing from dmesg, log failure here and # go to next 'if' to try tpm2.0 tools. logging.info("Host tcsd.serivce start failed") else: tpm_real_v = "1.2" logging.info("Host tpm version info:") result = process.run("tpm_version", ignore_status=False) logging.debug("[host]# tpm_version\n %s", result.stdout) time.sleep(2) service_mgr.stop('tcsd') if tpm_v != "1.2": # Try tpm2.0 tools if not utils_package.package_install("tpm2-tools"): test.error("Failed to install tpm2-tools on host") tpm2_getrandom_cmd = get_tpm2_tools_cmd() if process.run(tpm2_getrandom_cmd, ignore_status=True).exit_status: test.cancel("Both tcsd and tpm2-tools can not work, " "pls check your host tpm version and test env.") else: tpm_real_v = "2.0" logging.info("------PASS on host tpm device check------") return tpm_real_v def test_host_tpm_aft(tpm_real_v): """ Test host tpm function after passthrough :param tpm_real_v: host tpm real version indentified from testing """ logging.info("------Checking host tpm device after passthrough------") if tpm_real_v == "1.2": if service_mgr.start('tcsd'): time.sleep(2) service_mgr.stop('tcsd') test.fail( "Host tpm should not work after passthrough to guest.") else: logging.info("Expected failure: Tpm is being used by guest.") elif tpm_real_v == "2.0": tpm2_getrandom_cmd = get_tpm2_tools_cmd() if not process.run(tpm2_getrandom_cmd, ignore_status=True).exit_status: test.fail( "Host tpm should not work after passthrough to guest.") else: logging.info("Expected failure: Tpm is being used by guest.") logging.info("------PASS on host tpm device check------") def test_guest_tpm(expect_version, session, expect_fail): """ Test tpm function in guest :param expect_version: guest tpm version, as host version, or emulator specified :param session: Guest session to be tested :param expect_fail: guest tpm is expectedly fail to work """ logging.info("------Checking guest tpm device work------") if expect_version == "1.2": # Install tpm-tools and test by tcsd method if not utils_package.package_install(["tpm-tools"], session, 360): test.error("Failed to install tpm-tools package in guest") else: status, output = session.cmd_status_output( "systemctl start tcsd") logging.debug("Command output: %s", output) if status: if expect_fail: test.cancel( "tpm-crb passthrough only works with host tpm2.0, " "but your host tpm version is 1.2") else: test.fail("Failed to start tcsd.service in guest") else: dev_output = session.cmd_output("ls /dev/|grep tpm") logging.debug("Command output: %s", dev_output) status, output = session.cmd_status_output("tpm_version") logging.debug("Command output: %s", output) if status: test.fail("Guest tpm can not work") else: # If expect_version is tpm2.0, install and test by tpm2-tools if not utils_package.package_install(["tpm2-tools"], session, 360): test.error("Failed to install tpm2-tools package in guest") else: tpm2_getrandom_cmd = get_tpm2_tools_cmd(session) status1, output1 = session.cmd_status_output( "ls /dev/|grep tpm") logging.debug("Command output: %s", output1) status2, output2 = session.cmd_status_output( tpm2_getrandom_cmd) logging.debug("Command output: %s", output2) if status1 or status2: if not expect_fail: test.fail("Guest tpm can not work") else: d_status, d_output = session.cmd_status_output("date") if d_status: test.fail("Guest OS doesn't work well") logging.debug("Command output: %s", d_output) elif expect_fail: test.fail("Expect fail but guest tpm still works") logging.info("------PASS on guest tpm device work check------") def run_test_suite_in_guest(session): """ Run kernel test suite for guest tpm. :param session: Guest session to be tested """ logging.info("------Checking kernel test suite for guest tpm------") boot_info = session.cmd('uname -r').strip().split('.') kernel_version = '.'.join(boot_info[:2]) # Download test suite per current guest kernel version parent_path = "https://cdn.kernel.org/pub/linux/kernel" if float(kernel_version) < 5.3: major_version = "5" file_version = "5.3" else: major_version = boot_info[0] file_version = kernel_version src_url = "%s/v%s.x/linux-%s.tar.xz" % (parent_path, major_version, file_version) download_cmd = "wget %s -O %s" % (src_url, "/root/linux.tar.xz") output = session.cmd_output(download_cmd, timeout=480) logging.debug("Command output: %s", output) # Install neccessary pkgs to build test suite if not utils_package.package_install( ["tar", "make", "gcc", "rsync", "python2"], session, 360): test.fail("Failed to install specified pkgs in guest OS.") # Unzip the downloaded test suite status, output = session.cmd_status_output( "tar xvJf /root/linux.tar.xz -C /root") if status: test.fail("Uzip failed: %s" % output) # Specify using python2 to run the test suite per supporting test_path = "/root/linux-%s/tools/testing/selftests" % file_version sed_cmd = "sed -i 's/python -m unittest/python2 -m unittest/g' %s/tpm2/test_*.sh" % test_path output = session.cmd_output(sed_cmd) logging.debug("Command output: %s", output) # Build and and run the .sh files of test suite status, output = session.cmd_status_output( "make -C %s TARGETS=tpm2 run_tests" % test_path, timeout=360) logging.debug("Command output: %s", output) if status: test.fail("Failed to run test suite in guest OS.") for test_sh in ["test_smoke.sh", "test_space.sh"]: pattern = "ok .* selftests: tpm2: %s" % test_sh if not re.search(pattern, output) or ("not ok" in output): test.fail("test suite check failed.") logging.info("------PASS on kernel test suite check------") def reuse_by_vm2(tpm_dev): """ Try to add same tpm to a second guest, when it's being used by one guest. :param tpm_dev: tpm device to be added into guest xml """ logging.info("------Trying to add same tpm to a second domain------") vm2_xml.remove_all_device_by_type('tpm') vm2_xml.add_device(tpm_dev) vm2_xml.sync() ret = virsh.start(vm2_name, ignore_status=True, debug=True) if backend_type == "passthrough": if ret.exit_status: logging.info("Expected failure when try to passthrough a tpm" " that being used by another guest") return test.fail("Reuse a passthroughed tpm should not succeed.") elif ret.exit_status: # emulator backend test.fail( "Vtpm for each guest should not interfere with each other") try: tpm_real_v = None sec_uuids = [] new_name = "" virsh_dargs = {"debug": True, "ignore_status": False} vm_xml.remove_all_device_by_type('tpm') tpm_dev = Tpm() if tpm_model: tpm_dev.tpm_model = tpm_model if not no_backend: backend = tpm_dev.Backend() if backend_type != 'none': backend.backend_type = backend_type if backend_type == "passthrough": tpm_real_v = get_host_tpm_bef(tpm_v) logging.debug("The host tpm real version is %s", tpm_real_v) if device_path: backend.device_path = device_path if backend_type == "emulator": if backend_version != 'none': backend.backend_version = backend_version if prepare_secret: auth_sec_dict = { "sec_ephemeral": "no", "sec_private": "yes", "sec_desc": "sample vTPM secret", "sec_usage": "vtpm", "sec_name": "VTPM_example" } encryption_uuid = libvirt.create_secret(auth_sec_dict) if secret_value != 'none': virsh.secret_set_value(encryption_uuid, "open sesame", encode=True, debug=True) sec_uuids.append(encryption_uuid) if encrypt_change != 'encrpt': # plain_to_encrypt will not add encryption on first start if secret_uuid == 'invalid': encryption_uuid = encryption_uuid[:-1] backend.encryption_secret = encryption_uuid if secret_uuid == "change": auth_sec_dict["sec_desc"] = "sample2 vTPM secret" auth_sec_dict["sec_name"] = "VTPM_example2" new_encryption_uuid = libvirt.create_secret( auth_sec_dict) virsh.secret_set_value(new_encryption_uuid, "open sesame", encode=True, debug=True) sec_uuids.append(new_encryption_uuid) if secret_uuid == 'nonexist': backend.encryption_secret = "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee" tpm_dev.backend = backend logging.debug("tpm dev xml to add is:\n %s", tpm_dev) for num in range(tpm_num): vm_xml.add_device(tpm_dev, True) ret = virsh.define(vm_xml.xml, ignore_status=True, debug=True) expected_match = "" if not err_msg: expected_match = "Domain %s defined from %s" % (vm_name, vm_xml.xml) libvirt.check_result(ret, err_msg, "", False, expected_match) if err_msg: # Stop test when get expected failure return if vm_operate != "restart": check_dumpxml(vm_name) # For default model, no need start guest to test if tpm_model: expect_fail = False try: vm.start() except VMStartError as detail: if secret_value == 'none' or secret_uuid == 'nonexist': logging.debug("Expected failure: %s", detail) return else: test.fail(detail) domuuid = vm.get_uuid() if vm_operate or restart_libvirtd: # Make sure OS works before vm operate or restart libvirtd session = vm.wait_for_login() test_guest_tpm("2.0", session, False) session.close() if restart_libvirtd: utils_libvirtd.libvirtd_restart() swtpm_statedir = "/var/lib/libvirt/swtpm/%s" % domuuid if vm_operate == "resume": virsh.suspend(vm_name, **virsh_dargs) time.sleep(3) virsh.resume(vm_name, **virsh_dargs) elif vm_operate == "snapshot": virsh.snapshot_create_as( vm_name, "sp1 --memspec file=/tmp/testvm_sp1", **virsh_dargs) elif vm_operate in ["restart", "create"]: vm.destroy() if vm_operate == "create": virsh.undefine(vm_name, options="--nvram", **virsh_dargs) if os.path.exists(swtpm_statedir): test.fail( "Swtpm state dir: %s still exist after vm undefine" % swtpm_statedir) virsh.create(vm_xml.xml, **virsh_dargs) else: if vm_oprt == "domrename": new_name = "vm_" + utils_misc.generate_random_string( 5) virsh.domrename(vm_name, new_name, **virsh_dargs) new_vm = libvirt_vm.VM(new_name, vm.params, vm.root_dir, vm.address_cache) vm = new_vm vm_name = new_name elif secret_value == 'change': logging.info("Changing secret value...") virsh.secret_set_value(encryption_uuid, "new sesame", encode=True, debug=True) elif not restart_libvirtd: # remove_dev or do other vm operations during restart vm_xml.remove_all_device_by_type('tpm') if secret_uuid == "change" or encrypt_change: # Change secret uuid, or change encrytion state:from plain to encrypted, or on the contrary if encrypt_change == 'plain': # Change from encrypted state to plain:redefine a tpm dev without encryption tpm_dev = Tpm() tpm_dev.tpm_model = tpm_model backend = tpm_dev.Backend() backend.backend_type = backend_type backend.backend_version = backend_version else: # Use a new secret's uuid if secret_uuid == "change": encryption_uuid = new_encryption_uuid backend.encryption_secret = encryption_uuid tpm_dev.backend = backend logging.debug( "The new tpm dev xml to add for restart vm is:\n %s", tpm_dev) vm_xml.add_device(tpm_dev, True) if encrypt_change in ['encrpt', 'plain']: # Avoid sync() undefine removing the state file vm_xml.define() else: vm_xml.sync() if rm_statefile: swtpm_statefile = "%s/tpm2/tpm2-00.permall" % swtpm_statedir logging.debug("Removing state file: %s", swtpm_statefile) os.remove(swtpm_statefile) ret = virsh.start(vm_name, ignore_status=True, debug=True) libvirt.check_exit_status(ret, status_error) if status_error and ret.exit_status != 0: return if not remove_dev: check_dumpxml(vm_name) elif vm_operate == 'managedsave': virsh.managedsave(vm_name, **virsh_dargs) time.sleep(5) if secret_value == 'change': logging.info("Changing secret value...") virsh.secret_set_value(encryption_uuid, "new sesame", encode=True, debug=True) if rm_statefile: swtpm_statefile = "%s/tpm2/tpm2-00.permall" % swtpm_statedir logging.debug("Removing state file: %s", swtpm_statefile) os.remove(swtpm_statefile) ret = virsh.start(vm_name, ignore_status=True, debug=True) libvirt.check_exit_status(ret, status_error) if status_error and ret.exit_status != 0: return domid = vm.get_id() check_qemu_cmd_line(vm, vm_name, domid) if backend_type == "passthrough": if tpm_real_v == "1.2" and tpm_model == "tpm-crb": expect_fail = True expect_version = tpm_real_v test_host_tpm_aft(tpm_real_v) else: # emulator backend if remove_dev: expect_fail = True expect_version = backend_version check_swtpm(domid, domuuid, vm_name) session = vm.wait_for_login() if test_suite: run_test_suite_in_guest(session) else: test_guest_tpm(expect_version, session, expect_fail) session.close() if multi_vms: reuse_by_vm2(tpm_dev) if backend_type != "passthrough": #emulator backend check_dumpxml(vm2_name) domid = vm2.get_id() domuuid = vm2.get_uuid() check_qemu_cmd_line(vm2, vm2_name, domid) check_swtpm(domid, domuuid, vm2_name) session = vm2.wait_for_login() test_guest_tpm(backend_version, session, expect_fail) session.close() finally: # Remove renamed domain if it exists if new_name: virsh.remove_domain(new_name, "--nvram", debug=True) if os.path.exists("/var/log/swtpm/libvirt/qemu/%s-swtpm.log" % new_name): os.remove("/var/log/swtpm/libvirt/qemu/%s-swtpm.log" % new_name) # Remove snapshot if exists if vm_operate == "snapshot": snapshot_lists = virsh.snapshot_list(vm_name) if len(snapshot_lists) > 0: libvirt.clean_up_snapshots(vm_name, snapshot_lists) for snap in snapshot_lists: virsh.snapshot_delete(vm_name, snap, "--metadata") if os.path.exists("/tmp/testvm_sp1"): os.remove("/tmp/testvm_sp1") # Clear guest os if test_suite: session = vm.wait_for_login() logging.info("Removing dir /root/linux-*") output = session.cmd_output("rm -rf /root/linux-*") logging.debug("Command output:\n %s", output) session.close() if vm_operate == "create": vm.define(vm_xml.xml) vm_xml_backup.sync(options="--nvram --managed-save") # Remove swtpm log file in case of impact on later runs if os.path.exists("/var/log/swtpm/libvirt/qemu/%s-swtpm.log" % vm.name): os.remove("/var/log/swtpm/libvirt/qemu/%s-swtpm.log" % vm.name) for sec_uuid in set(sec_uuids): virsh.secret_undefine(sec_uuid, ignore_status=True, debug=True) if vm2: if len(vm_names) > 1: vm2_xml_backup.sync(options="--nvram") else: virsh.remove_domain(vm2_name, "--nvram --remove-all-storage", debug=True) if os.path.exists("/var/log/swtpm/libvirt/qemu/%s-swtpm.log" % vm2.name): os.remove("/var/log/swtpm/libvirt/qemu/%s-swtpm.log" % vm2.name)
def run(test, params, env): """ Test nic driver load/unload. 1) Boot a VM. 2) Get the NIC driver name. 3) Multi-session TCP transfer on test interface. 4) Repeatedly unload/load NIC driver during file transfer. 5) Check whether the test interface should still work. :param test: QEMU test object. :param params: Dictionary with the test parameters. :param env: Dictionary with test environment. """ def reset_guest_udevrules(session, rules_file, rules_content): """ Write guest udev rules, then reboot the guest and return the new session """ set_cmd = "echo '%s' > %s" % (rules_content, rules_file) session.cmd_output_safe(set_cmd) return vm.reboot() def all_threads_done(threads): """ Check whether all threads have finished """ for thread in threads: if thread.isAlive(): return False else: continue return True def all_threads_alive(threads): """ Check whether all threads is alive """ for thread in threads: if not thread.isAlive(): return False else: continue return True timeout = int(params.get("login_timeout", 360)) transfer_timeout = int(params.get("transfer_timeout", 1000)) filesize = int(params.get("filesize", 512)) vm = env.get_vm(params["main_vm"]) vm.verify_alive() session = vm.wait_for_login(timeout=timeout) vm_mac_address = vm.get_mac_address() udev_rules_file = "/etc/udev/rules.d/70-persistent-net.rules" rules = params.get("rules") if not session.cmd_status("[ -e %s ]" % udev_rules_file): if not rules: raise error.TestNAError("You must set udev rules before test") rules = rules % vm_mac_address session = reset_guest_udevrules(session, udev_rules_file, rules) error.base_context("Test env prepare") error.context("Get NIC interface name in guest.", logging.info) ethname = utils_net.get_linux_ifname(session, vm.get_mac_address(0)) # get ethernet driver from '/sys' directory. # ethtool can do the same thing and doesn't care about os type. # if we make sure all guests have ethtool, we can make a change here. sys_path = params.get("sys_path") % (ethname) # readlink in RHEL4.8 doesn't have '-e' param, should use '-f' in RHEL4.8. readlink_cmd = params.get("readlink_command", "readlink -e") driver = os.path.basename( session.cmd("%s %s" % (readlink_cmd, sys_path)).strip()) logging.info("The guest interface %s using driver %s" % (ethname, driver)) error.context( "Host test file prepare, create %dMB file on host" % filesize, logging.info) tmp_dir = data_dir.get_tmp_dir() host_path = os.path.join( tmp_dir, "host_file_%s" % utils_misc.generate_random_string(8)) guest_path = os.path.join( "/home", "guest_file_%s" % utils_misc.generate_random_string(8)) cmd = "dd if=/dev/zero of=%s bs=1M count=%d" % (host_path, filesize) utils.run(cmd) file_checksum = utils.hash_file(host_path, "md5") error.context( "Guest test file prepare, Copy file %s from host to guest" % host_path, logging.info) vm.copy_files_to(host_path, guest_path, timeout=transfer_timeout) if session.cmd_status("md5sum %s | grep %s" % (guest_path, file_checksum)): raise error.TestNAError("File MD5SUMs changed after copy to guest") logging.info("Test env prepare successfully") error.base_context("Nic driver load/unload testing", logging.info) session_serial = vm.wait_for_serial_login(timeout=timeout) try: error.context("Transfer file between host and guest", logging.info) threads = [] file_paths = [] host_file_paths = [] for sess_index in range(int(params.get("sessions_num", "10"))): sess_path = os.path.join("/home", "dst-%s" % sess_index) host_sess_path = os.path.join(tmp_dir, "dst-%s" % sess_index) thread1 = utils.InterruptedThread(vm.copy_files_to, (host_path, sess_path), {"timeout": transfer_timeout}) thread2 = utils.InterruptedThread(vm.copy_files_from, (guest_path, host_sess_path), {"timeout": transfer_timeout}) thread1.start() threads.append(thread1) thread2.start() threads.append(thread2) file_paths.append(sess_path) host_file_paths.append(host_sess_path) utils_misc.wait_for(lambda: all_threads_alive(threads), 60, 10, 1) time.sleep(5) error.context("Repeatedly unload/load NIC driver during file transfer", logging.info) while not all_threads_done(threads): error.context("Shutdown the driver for NIC interface.", logging.info) session_serial.cmd_output_safe("ifconfig %s down" % ethname) error.context("Unload NIC driver.", logging.info) session_serial.cmd_output_safe("modprobe -r %s" % driver) error.context("Load NIC driver.", logging.info) session_serial.cmd_output_safe("modprobe %s" % driver) error.context("Activate NIC driver.", logging.info) session_serial.cmd_output_safe("ifconfig %s up" % ethname) session_serial.cmd_output_safe("sleep %s" % random.randint(10, 60)) # files md5sums check error.context("File transfer finished, checking files md5sums", logging.info) err_info = [] for copied_file in file_paths: if session_serial.cmd_status("md5sum %s | grep %s" % (copied_file, file_checksum)): err_msg = "Guest file %s md5sum changed" err_info.append(err_msg % copied_file) for copied_file in host_file_paths: if utils.system("md5sum %s | grep %s" % (copied_file, file_checksum)): err_msg = "Host file %s md5sum changed" err_info.append(err_msg % copied_file) if err_info: raise error.TestError("files MD5SUMs changed after copying %s" % err_info) except Exception: for thread in threads: thread.join(suppress_exception=True) raise else: for thread in threads: thread.join() for copied_file in file_paths: session_serial.cmd("rm -rf %s" % copied_file) for copied_file in host_file_paths: utils.system("rm -rf %s" % copied_file) session_serial.cmd("%s %s" % ("rm -rf", guest_path)) os.remove(host_path) session.close() session_serial.close()
def run(test, params, env): """ convert specific kvm guest to rhev """ for v in list(params.values()): if "V2V_EXAMPLE" in v: test.cancel("Please set real value for %s" % v) if utils_v2v.V2V_EXEC is None: test.error('Missing command: virt-v2v') vm_name = params.get('main_vm', 'EXAMPLE') target = params.get('target') input_mode = params.get('input_mode') input_file = params.get('input_file') output_mode = params.get('output_mode') output_format = params.get('output_format') output_storage = params.get('output_storage', 'default') bridge = params.get('bridge') network = params.get('network') address_cache = env.get('address_cache') v2v_timeout = int(params.get('v2v_timeout', 1200)) status_error = 'yes' == params.get('status_error', 'no') skip_check = 'yes' == params.get('skip_check', 'no') pool_name = params.get('pool_name', 'v2v_test') pool_type = params.get('pool_type', 'dir') pool_target = params.get('pool_target_path', 'v2v_pool') pvt = libvirt.PoolVolumeTest(test, params) checkpoint = params.get('checkpoint', '') error_list = [] # create different sasl_user name for different job if output_mode == 'rhev': params.update({ 'sasl_user': params.get("sasl_user") + utils_misc.generate_random_string(3) }) logging.info('sals user name is %s' % params.get("sasl_user")) def log_fail(msg): """ Log error and update error list """ logging.error(msg) error_list.append(msg) def check_BSOD(): """ Check if boot up into BSOD """ bar = 0.999 match_img = params.get('image_to_match') screenshot = '%s/BSOD_screenshot.ppm' % data_dir.get_tmp_dir() if match_img is None: test.error('No BSOD screenshot to match!') cmd_man_page = 'man virt-v2v|grep -i "Boot failure: 0x0000007B"' if process.run(cmd_man_page, shell=True).exit_status != 0: log_fail('Man page not contain boot failure msg') for i in range(100): virsh.screenshot(vm_name, screenshot) similar = ppm_utils.image_histogram_compare(screenshot, match_img) if similar > bar: logging.info('Meet BSOD with similarity %s' % similar) return time.sleep(1) log_fail('No BSOD as expected') def check_result(result, status_error): """ Check virt-v2v command result """ libvirt.check_exit_status(result, status_error) output = result.stdout + result.stderr if skip_check: logging.info('Skip checking vm after conversion') elif not status_error: if output_mode == 'rhev': if not utils_v2v.import_vm_to_ovirt( params, address_cache, timeout=v2v_timeout): test.fail('Import VM failed') if output_mode == 'libvirt': try: virsh.start(vm_name, debug=True, ignore_status=False) except Exception as e: test.fail('Start vm failed: %s' % str(e)) # Check guest following the checkpoint document after convertion vmchecker = VMChecker(test, params, env) params['vmchecker'] = vmchecker if params.get('skip_vm_check') != 'yes': if checkpoint != 'win2008r2_ostk': ret = vmchecker.run() if len(ret) == 0: logging.info("All common checkpoints passed") if checkpoint == 'win2008r2_ostk': check_BSOD() # Merge 2 error lists error_list.extend(vmchecker.errors) log_check = utils_v2v.check_log(params, output) if log_check: log_fail(log_check) if len(error_list): test.fail('%d checkpoints failed: %s' % (len(error_list), error_list)) try: v2v_params = { 'main_vm': vm_name, 'target': target, 'v2v_opts': '-v -x', 'storage': output_storage, 'network': network, 'bridge': bridge, 'input_mode': input_mode, 'input_file': input_file, 'new_name': 'ova_vm_' + utils_misc.generate_random_string(3) } if output_format: v2v_params.update({'output_format': output_format}) # Create libvirt dir pool if output_mode == 'libvirt': pvt.pre_pool(pool_name, pool_type, pool_target, '') # Build rhev related options if output_mode == 'rhev': # Create SASL user on the ovirt host user_pwd = "[['%s', '%s']]" % (params.get("sasl_user"), params.get("sasl_pwd")) v2v_sasl = utils_sasl.SASL(sasl_user_pwd=user_pwd) v2v_sasl.server_ip = params.get("remote_ip") v2v_sasl.server_user = params.get('remote_user') v2v_sasl.server_pwd = params.get('remote_pwd') v2v_sasl.setup(remote=True) if output_mode == 'local': v2v_params['storage'] = data_dir.get_tmp_dir() if checkpoint == 'ova_relative_path': logging.debug('Current dir: %s', os.getcwd()) ova_dir = params.get('ova_dir') logging.info('Change to dir: %s', ova_dir) os.chdir(ova_dir) # Set libguestfs environment variable os.environ['LIBGUESTFS_BACKEND'] = 'direct' if checkpoint == 'permission': os.environ['LIBGUESTFS_BACKEND'] = '' process.run('echo $LIBGUESTFS_BACKEND', shell=True) v2v_result = utils_v2v.v2v_cmd(v2v_params) if 'new_name' in v2v_params: vm_name = params['main_vm'] = v2v_params['new_name'] check_result(v2v_result, status_error) finally: if params.get('vmchecker'): params['vmchecker'].cleanup() if output_mode == 'rhev' and v2v_sasl: v2v_sasl.cleanup() if output_mode == 'libvirt': pvt.cleanup_pool(pool_name, pool_type, pool_target, '')
def run(test, params, env): """ Test virtual network """ vm_name = params.get('main_vm') vm = env.get_vm(vm_name) net = params.get('net', DEFAULT_NET) expect_str = params.get('expect_str') bridge_name = 'br_' + utils_misc.generate_random_string(3) test_group = params.get('test_group', 'default') case = params.get('case', '') def setup_test_default(case): """ Default setup for test cases :param case: test case """ logging.info('No specific setup step for %s', case) def cleanup_test_default(case): """ Default cleanup for test cases :param case: test case """ logging.info('No specific cleanup step for %s', case) def setup_test_zone(case): """ Test setup for network zone test cases :param case: test case """ if not libvirt_version.version_compare(6, 0, 0): test.cancel('Version of libvirt is too low for this test.') # Make sure firewalld version supports current test rpmb = rpm.RpmBackend() if rpmb.check_installed('firewalld', '0.6.0'): logging.info('Version of firewalld meets expectation') else: test.cancel('Version of firewalld is too low to finish this test.') setup_firewalld() # Setup zone for bridge netxml = NetworkXML.new_from_net_dumpxml(net) if case == 'public': netxml.bridge = {'name': bridge_name, 'zone': 'public'} elif case == 'info': netxml.bridge = {'name': bridge_name} else: test.error('Test "%s" is not supported.' % case) netxml.forward = {'mode': 'nat'} netxml.sync() logging.debug('Updated net:\n%s', virsh.net_dumpxml(net).stdout_text) def run_test_zone(case): """ Test steps for network zone test cases :param case: test case """ def run_test_zone_public(): """ Check zone of interface with firewalld-cmd """ check_cmd = 'firewall-cmd --get-zone-of-interface=%s' % bridge_name output = process.run(check_cmd, verbose=True).stdout_text.strip() if output == 'public': logging.info('Zone check of interface PASSED') else: test.fail('Zone check of interface FAILED, should be public, but got %s' % output) def run_test_zone_info(): """ Check zone info with firewalld-cmd """ check_cmd = 'firewall-cmd --info-zone=libvirt' output = process.run(check_cmd, verbose=True).stdout_text.strip() br = bridge_name for item in eval(expect_str): if item in output or re.search(item, output): logging.debug('Found "%s" in firewalld-cmd output' % item) else: test.fail('Not found "%s" in firewalld-cmd output' % item) test_zone = eval('run_test_zone_%s' % case) test_zone() bk_netxml = NetworkXML.new_from_net_dumpxml(net) bk_xml = vm_xml.VMXML.new_from_dumpxml(vm_name) try: # Get setup function setup_test = eval('setup_test_%s' % test_group) \ if 'setup_test_%s' % test_group in locals() else setup_test_default # Get runtest function run_test = eval('run_test_%s' % test_group) # Get cleanup function cleanup_test = eval('cleanup_test_%s' % test_group) \ if 'cleanup_test_%s' % test_group in locals() else cleanup_test_default # Execute test setup_test(case) run_test(case) cleanup_test(case) finally: bk_netxml.sync() bk_xml.sync()
def run(test, params, env): """ Test virsh reset command """ if not virsh.has_help_command('reset'): raise error.TestNAError("This version of libvirt does not support " "the reset test") vm_name = params.get("main_vm", "avocado-vt-vm1") vm_ref = params.get("reset_vm_ref") readonly = params.get("readonly", False) status_error = ("yes" == params.get("status_error", "no")) start_vm = ("yes" == params.get("start_vm")) vm = env.get_vm(vm_name) domid = vm.get_id() domuuid = vm.get_uuid() bef_pid = commands.getoutput("pidof -s qemu-kvm") if vm_ref == 'id': vm_ref = domid elif vm_ref == 'uuid': vm_ref = domuuid else: vm_ref = vm_name 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.") # change the disk cache to default vmxml_backup = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) def change_cache(vmxml, mode): """ Change the cache mode :param vmxml: instance of VMXML :param mode: cache mode you want to change """ devices = vmxml.devices disk_index = devices.index(devices.by_device_tag('disk')[0]) disk = devices[disk_index] disk_driver = disk.driver disk_driver['cache'] = mode disk.driver = disk_driver vmxml.devices = devices vmxml.define() try: change_cache(vmxml_backup.copy(), "default") tmpfile = "/home/%s" % utils_misc.generate_random_string(6) logging.debug("tmpfile is %s", tmpfile) if start_vm: session = vm.wait_for_login() session.cmd("rm -rf %s && sync" % tmpfile) status = session.get_command_status("touch %s && ls %s" % (tmpfile, tmpfile)) if status == 0: logging.info("Succeed generate file %s", tmpfile) else: raise error.TestFail("Touch command failed!") # record the pid before reset for compare output = virsh.reset(vm_ref, readonly=readonly, unprivileged_user=unprivileged_user, uri=uri, ignore_status=True, debug=True) if output.exit_status != 0: if status_error: logging.info("Failed to reset guest as expected, Error:%s.", output.stderr) return else: raise error.TestFail("Failed to reset guest, Error:%s." % output.stderr) elif status_error: raise error.TestFail("Expect fail, but succeed indeed.") session.close() session = vm.wait_for_login() status = session.get_command_status("ls %s" % tmpfile) if status == 0: raise error.TestFail("Fail to reset guest, tmpfile still exist!") else: aft_pid = commands.getoutput("pidof -s qemu-kvm") if bef_pid == aft_pid: logging.info("Succeed to check reset, tmpfile is removed.") else: raise error.TestFail("Domain pid changed after reset!") session.close() finally: vmxml_backup.sync()
def run_smartcard_setup(test, params, env): """ Simple setup test to create certs on the client to be passed to VM's smartcard. @param test: QEMU test object. @param params: Dictionary with the test parameters. @param env: Dictionary with test environment. """ # Get necessary params cert_list = params.get("gencerts").split(",") cert_db = params.get("certdb") self_sign = params.get("self_sign") cert_trustargs = params.get("trustargs") logging.debug("Cert List:") for cert in cert_list: logging.debug(cert) logging.debug(cert_trustargs) logging.debug("CN=" + cert) logging.debug(cert_db) client_vm = env.get_vm(params["client_vm"]) client_vm.verify_alive() client_session = client_vm.wait_for_login(timeout=int( params.get("login_timeout", 360)), username="******", password="******") for vm in params.get("vms").split(): utils_spice.clear_interface(env.get_vm(vm), int(params.get("login_timeout", "360"))) # generate a random string, used to create a random key for the certs randomstring = utils_misc.generate_random_string(2048) cmd = "echo '" + randomstring + "' > /tmp/randomtext.txt" output = client_session.cmd(cmd) #output2 = client_session.cmd("cat /tmp/randomtext.txt") utils_spice.wait_timeout(5) # for each cert listed by the test, create it on the client for cert in cert_list: cmd = "certutil " if self_sign: cmd += " -x " cmd += "-t '" + cert_trustargs + "' -S -s " + "'CN=" + cert cmd += "' -n '" + cert + "' -d " + cert_db cmd += " -z " + "/tmp/randomtext.txt" logging.debug(cmd) output = client_session.cmd(cmd) logging.debug("Cert Created: " + output) cmd = "certutil -L -d " + cert_db output = client_session.cmd(cmd) logging.info("Listing all certs on the client: " + output) # Verify that all the certs have been generated on the client for cert in cert_list: if not (cert in output): raise error.TestFail("Certificate %s not found" % cert) client_session.close()
def run(test, params, env): """ Test Step 1. boot up two virtual machine 2. Transfer data: host <--> guest1 <--> guest2 <-->host via ipv6 3. after data transfer, check data have no change Params: :param test: QEMU test object :param params: Dictionary with the test parameters :param env: Dictionary with test environment. """ timeout = int(params.get("login_timeout", '360')) client = params.get("file_transfer_client") port = params.get("file_transfer_port") password = params.get("password") username = params.get("username") tmp_dir = params.get("tmp_dir", "/tmp/") filesize = int(params.get("filesize", '4096')) dd_cmd = params.get("dd_cmd") file_trans_timeout = int(params.get("file_trans_timeout", '1200')) file_md5_check_timeout = int(params.get("file_md5_check_timeout", '600')) def get_linux_ipv6_linklocal_address(ifname, session=None): """ Get host/guest ipv6 linklocal address via ifname """ if session is not None: o = session.cmd_output("ifconfig %s" % ifname) else: o = utils.system_output("ifconfig %s" % ifname) ipv6_address_reg = re.compile(r"(fe80::[^\s|/]*)") if o: ipv6_linklocal_address = ipv6_address_reg.findall(o) if not ipv6_linklocal_address: raise error.TestError("Can't get %s linklocal address" % ifname) return ipv6_linklocal_address[0] else: return None def get_file_md5sum(file_name, session, timeout): """ Get file md5sum from guest. """ logging.info("Get md5sum of the file:'%s'" % file_name) try: o = session.cmd_output("md5sum %s" % file_name, timeout=timeout) file_md5sum = re.findall("\w+", o)[0] except IndexError: raise error.TestError("Could not get file md5sum in guest") return file_md5sum sessions = {} addresses = {} inet_name = {} vms = [] error.context("Boot vms for test", logging.info) for vm_name in params.get("vms", "vm1 vm2").split(): vms.append(env.get_vm(vm_name)) # config ipv6 address host and guest. host_ifname = params.get("netdst") for vm in vms: vm.verify_alive() sessions[vm] = vm.wait_for_login(timeout=timeout) inet_name[vm] = utils_net.get_linux_ifname(sessions[vm], vm.get_mac_address()) addresses[vm] = get_linux_ipv6_linklocal_address(inet_name[vm], sessions[vm]) # prepare test data guest_path = (tmp_dir + "src-%s" % utils_misc.generate_random_string(8)) dest_path = (tmp_dir + "dst-%s" % utils_misc.generate_random_string(8)) host_path = os.path.join(test.tmpdir, "tmp-%s" % utils_misc.generate_random_string(8)) logging.info("Test setup: Creating %dMB file on host", filesize) utils.run(dd_cmd % (host_path, filesize)) try: src_md5 = (utils.hash_file(host_path, method="md5")) # transfer data for vm in vms: error.context("Transfer data from host to %s" % vm.name, logging.info) remote.copy_files_to(addresses[vm], client, username, password, port, host_path, guest_path, timeout=file_trans_timeout, interface=host_ifname) dst_md5 = get_file_md5sum(guest_path, sessions[vm], timeout=file_md5_check_timeout) if dst_md5 != src_md5: raise error.TestFail("File changed after transfer host -> %s" % vm.name) for vm_src in addresses: for vm_dst in addresses: if vm_src != vm_dst: error.context("Transferring data from %s to %s" % (vm_src.name, vm_dst.name), logging.info) remote.scp_between_remotes(addresses[vm_src], addresses[vm_dst], port, password, password, username, username, guest_path, dest_path, timeout=file_trans_timeout, src_inter=host_ifname, dst_inter=inet_name[vm_src]) dst_md5 = get_file_md5sum(dest_path, sessions[vm_dst], timeout=file_md5_check_timeout) if dst_md5 != src_md5: raise error.TestFail("File changed transfer %s -> %s" % (vm_src.name, vm_dst.name)) for vm in vms: error.context("Transfer data from %s to host" % vm.name, logging.info) remote.copy_files_from(addresses[vm], client, username, password, port, dest_path, host_path, timeout=file_trans_timeout, interface=host_ifname) error.context("Check whether the file changed after trans", logging.info) dst_md5 = (utils.hash_file(host_path, method="md5")) if dst_md5 != src_md5: raise error.TestFail("File changed after transfer (md5sum mismatch)") utils.system_output("rm -rf %s" % host_path, timeout=timeout) finally: utils.system("rm -rf %s" % host_path, timeout=timeout, ignore_status=True) for vm in vms: sessions[vm].cmd("rm -rf %s %s || true" % (guest_path, dest_path), timeout=timeout, ignore_all_errors=True) sessions[vm].close()
def run(test, params, env): """ Check physical resources assigned to KVM virtual machines: 1) Log into the guest 2) Verify whether cpu counts ,memory size, nics' model, count and drives' format & count, drive_serial, UUID reported by the guest OS matches what has been assigned to the VM (qemu command line) 3) Verify all MAC addresses for guest NICs :param test: QEMU test object. :param params: Dictionary with the test parameters. :param env: Dictionary with test environment. """ # Define a function for checking number of hard drivers & NICs def check_num(devices, info_cmd, check_str): f_fail = [] expected_num = params.objects(devices).__len__() o = "" try: o = vm.monitor.human_monitor_cmd("info %s " % info_cmd) except qemu_monitor.MonitorError as e: fail_log = str(e) + "\n" fail_log += "info/query monitor command failed (%s)" % info_cmd f_fail.append(fail_log) logging.error(fail_log) ovmf_fd_num = o.count('%s.fd' % check_str) # Exclude ovmf fd drive actual_num = o.count(check_str) - ovmf_fd_num if expected_num != actual_num: fail_log = "%s number mismatch:\n" % str(devices) fail_log += " Assigned to VM: %d\n" % expected_num fail_log += " Reported by OS: %d" % actual_num f_fail.append(fail_log) logging.error(fail_log) return f_fail # Define a function for checking hard drives & NICs' model def chk_fmt_model(device, fmt_model, info_cmd, regexp): f_fail = [] devices = params.objects(device) for chk_device in devices: expected = params.object_params(chk_device).get(fmt_model) if not expected: expected = "rtl8139" o = "" try: o = vm.monitor.human_monitor_cmd("info %s" % info_cmd) except qemu_monitor.MonitorError as e: fail_log = str(e) + "\n" fail_log += "info/query monitor command failed (%s)" % info_cmd f_fail.append(fail_log) logging.error(fail_log) device_found = re.findall(regexp, o) logging.debug("Found devices: %s", device_found) found = False for fm in device_found: if expected in fm: found = True if not found: fail_log = "%s model mismatch:\n" % str(device) fail_log += " Assigned to VM: %s\n" % expected fail_log += " Reported by OS: %s" % device_found f_fail.append(fail_log) logging.error(fail_log) return f_fail # Define a function to verify UUID & Serial number def verify_device(expect, name, verify_cmd): f_fail = [] if verify_cmd: actual = session.cmd_output(verify_cmd) if not re.findall(expect, actual, re.I): fail_log = "%s mismatch:\n" % name fail_log += " Assigned to VM: %s\n" % expect.upper() fail_log += " Reported by OS: %s" % actual f_fail.append(fail_log) logging.error(fail_log) return f_fail def get_cpu_number(chk_type, chk_timeout): """ Get cpu sockets/cores/threads number. :param chk_type: Should be one of 'sockets', 'cores', 'threads'. :param chk_timeout: timeout of running chk_cmd. :return: Actual number of guest cpu number. """ chk_str = params["mem_chk_re_str"] chk_cmd = params.get("cpu_%s_chk_cmd" % chk_type) if chk_cmd is None: fail_log = "Unknown cpu number checking type: '%s'" % chk_type logging.error(fail_log) return -1 s, output = session.cmd_status_output(chk_cmd, timeout=chk_timeout) num = re.findall(chk_str, output) if s != 0 or not num: fail_log = "Failed to get guest %s number, " % chk_type fail_log += "guest output: '%s'" % output logging.error(fail_log) return -2 logging.info("CPU %s number: %d", chk_type.capitalize(), int(num[-1])) return int(num[-1]) def check_cpu_number(chk_type, actual_n, expected_n): """ Checking cpu sockets/cores/threads number. :param chk_type: Should be one of 'sockets', 'cores', 'threads'. :param actual_n: Actual number of guest cpu number. :param expected_n: Expected number of guest cpu number. :return: a list that contains fail report. """ f_fail = [] if actual_n == -1: fail_log = "Unknown cpu number checking type: '%s'" % chk_type logging.error(fail_log) f_fail.append(fail_log) return f_fail if actual_n == -2: fail_log = "Failed to get guest %s number." % chk_type logging.error(fail_log) f_fail.append(fail_log) return f_fail logging.info("CPU %s number check", chk_type.capitalize()) if actual_n != expected_n: fail_log = "%s output mismatch:\n" % chk_type.capitalize() fail_log += " Assigned to VM: '%s'\n" % expected_n fail_log += " Reported by OS: '%s'" % actual_n f_fail.append(fail_log) logging.error(fail_log) return f_fail logging.debug("%s check pass. Expected: '%s', Actual: '%s'", chk_type.capitalize(), expected_n, actual_n) return f_fail def verify_machine_type(): f_fail = [] cmd = params.get("check_machine_type_cmd") fail_log = "" if cmd is None: return f_fail status, actual_mtype = session.cmd_status_output(cmd) if status != 0: test.error("Failed to get machine type from vm") machine_type_cmd = "%s -M ?" % utils_misc.get_qemu_binary(params) machine_types = process.system_output(machine_type_cmd, ignore_status=True).decode() machine_types = machine_types.split(':')[-1] machine_type_map = {} for machine_type in machine_types.splitlines(): if not machine_type: continue type_pair = re.findall(r"([\w\.-]+)\s+([^(]+).*", machine_type) if len(type_pair) == 1 and len(type_pair[0]) == 2: machine_type_map[type_pair[0][0]] = type_pair[0][1] else: logging.warn("Unexpect output from qemu-kvm -M " "?: '%s'" % machine_type) try: expect_mtype = machine_type_map[params['machine_type']].strip() except KeyError: logging.warn("Can not find machine type '%s' from qemu-kvm -M ?" " output. Skip this test." % params['machine_type']) return f_fail if expect_mtype not in actual_mtype: fail_log += " Assigned to VM: '%s' \n" % expect_mtype fail_log += " Reported by OS: '%s'" % actual_mtype f_fail.append(fail_log) logging.error(fail_log) else: logging.info("MachineType check pass. Expected: %s, Actual: %s" % (expect_mtype, actual_mtype)) return f_fail if params.get("catch_serial_cmd") is not None: length = int(params.get("length", "20")) id_leng = random.randint(0, length) drive_serial = "" convert_str = "!\"#$%&\'()*+./:;<=>?@[\\]^`{|}~" drive_serial = utils_misc.generate_random_string( id_leng, ignore_str=",", convert_str=convert_str) params["drive_serial"] = drive_serial params["start_vm"] = "yes" vm = params["main_vm"] vm_params = params.object_params(vm) env_process.preprocess_vm(test, vm_params, env, vm) vm = env.get_vm(vm) else: vm = env.get_vm(params["main_vm"]) vm.verify_alive() timeout = int(params.get("login_timeout", 360)) chk_timeout = int(params.get("chk_timeout", 240)) error_context.context("Login to the guest", logging.info) session = vm.wait_for_login(timeout=timeout) qtree = qemu_qtree.QtreeContainer() try: qtree.parse_info_qtree(vm.monitor.info('qtree')) except AttributeError: # monitor doesn't support info qtree qtree = None logging.info("Starting physical resources check test") logging.info("Values assigned to VM are the values we expect " "to see reported by the Operating System") # Define a failure counter, as we want to check all physical # resources to know which checks passed and which ones failed n_fail = [] # We will check HDs with the image name image_name = storage.get_image_filename(params, data_dir.get_data_dir()) # Check cpu count error_context.context("CPU count check", logging.info) actual_cpu_nr = vm.get_cpu_count() cpu_cores_num = get_cpu_number("cores", chk_timeout) cpu_lp_num = get_cpu_number("logical_processors", chk_timeout) cpu_threads_num = get_cpu_number("threads", chk_timeout) cpu_sockets_num = get_cpu_number("sockets", chk_timeout) if ((params.get("os_type") == 'windows') and cpu_cores_num > 0 and cpu_lp_num > 0 and cpu_sockets_num > 0): actual_cpu_nr = cpu_lp_num * cpu_sockets_num cpu_threads_num = cpu_lp_num / cpu_cores_num if vm.cpuinfo.smp != actual_cpu_nr: fail_log = "CPU count mismatch:\n" fail_log += " Assigned to VM: %s \n" % vm.cpuinfo.smp fail_log += " Reported by OS: %s" % actual_cpu_nr n_fail.append(fail_log) logging.error(fail_log) n_fail.extend(check_cpu_number("cores", cpu_cores_num, vm.cpuinfo.cores)) n_fail.extend( check_cpu_number("threads", cpu_threads_num, vm.cpuinfo.threads)) n_fail.extend( check_cpu_number("sockets", cpu_sockets_num, vm.cpuinfo.sockets)) # Check the cpu vendor_id expected_vendor_id = params.get("cpu_model_vendor") cpu_vendor_id_chk_cmd = params.get("cpu_vendor_id_chk_cmd") if expected_vendor_id and cpu_vendor_id_chk_cmd: output = session.cmd_output(cpu_vendor_id_chk_cmd) if expected_vendor_id not in output: fail_log = "CPU vendor id check failed.\n" fail_log += " Assigned to VM: '%s'\n" % expected_vendor_id fail_log += " Reported by OS: '%s'" % output n_fail.append(fail_log) logging.error(fail_log) # Check memory size error_context.context("Memory size check", logging.info) expected_mem = int(params["mem"]) actual_mem = vm.get_memory_size() if actual_mem != expected_mem: fail_log = "Memory size mismatch:\n" fail_log += " Assigned to VM: %s\n" % expected_mem fail_log += " Reported by OS: %s\n" % actual_mem n_fail.append(fail_log) logging.error(fail_log) error_context.context("Hard drive count check", logging.info) f_fail = check_num("images", "block", image_name) n_fail.extend(f_fail) error_context.context("NIC count check", logging.info) f_fail = check_num("nics", "network", "model=") n_fail.extend(f_fail) error_context.context("NICs model check", logging.info) f_fail = chk_fmt_model("nics", "nic_model", "network", "model=(.*),") n_fail.extend(f_fail) if qtree is not None: error_context.context("Images params check", logging.info) logging.debug("Found devices: %s", params.objects('images')) qdisks = qemu_qtree.QtreeDisksContainer(qtree.get_nodes()) disk_errors = sum(qdisks.parse_info_block(vm.monitor.info_block())) disk_errors += qdisks.generate_params() disk_errors += qdisks.check_disk_params(params) if disk_errors: disk_errors = ("Images check failed with %s errors, " "check the log for details" % disk_errors) logging.error(disk_errors) n_fail.append("\n".join(qdisks.errors)) else: logging.info("Images check param skipped (qemu monitor doesn't " "support 'info qtree')") error_context.context("Network card MAC check", logging.info) o = "" try: o = vm.monitor.human_monitor_cmd("info network") except qemu_monitor.MonitorError as e: fail_log = str(e) + "\n" fail_log += "info/query monitor command failed (network)" n_fail.append(fail_log) logging.error(fail_log) found_mac_addresses = re.findall(r"macaddr=(\S+)", o) logging.debug("Found MAC adresses: %s", found_mac_addresses) num_nics = len(params.objects("nics")) for nic_index in range(num_nics): mac = vm.get_mac_address(nic_index) if mac.lower() not in found_mac_addresses: fail_log = "MAC address mismatch:\n" fail_log += " Assigned to VM (not found): %s" % mac n_fail.append(fail_log) logging.error(fail_log) error_context.context("UUID check", logging.info) if vm.get_uuid(): f_fail = verify_device(vm.get_uuid(), "UUID", params.get("catch_uuid_cmd")) n_fail.extend(f_fail) error_context.context("Hard Disk serial number check", logging.info) catch_serial_cmd = params.get("catch_serial_cmd") f_fail = verify_device(params.get("drive_serial"), "Serial", catch_serial_cmd) n_fail.extend(f_fail) error_context.context("Machine Type Check", logging.info) f_fail = verify_machine_type() n_fail.extend(f_fail) if n_fail: session.close() test.fail("Physical resources check test " "reported %s failures:\n%s" % (len(n_fail), "\n".join(n_fail))) session.close()
def run(test, params, env): """ KVM migration test: 1) Get a live VM and clone it. 2) Verify that the source VM supports migration. If it does, proceed with the test. 3) Transfer file from host to guest. 4) Repeatedly migrate VM and wait until transfer's finished. 5) Transfer file from guest back to host. 6) Repeatedly migrate VM and wait until transfer's finished. :param test: QEMU test object. :param params: Dictionary with test parameters. :param env: Dictionary with the test environment. """ vm = env.get_vm(params["main_vm"]) vm.verify_alive() login_timeout = int(params.get("login_timeout", 360)) session = vm.wait_for_login(timeout=login_timeout) mig_timeout = float(params.get("mig_timeout", "3600")) mig_protocol = params.get("migration_protocol", "tcp") mig_cancel_delay = int(params.get("mig_cancel") == "yes") * 2 host_path = "/tmp/file-%s" % utils_misc.generate_random_string(6) host_path_returned = "%s-returned" % host_path guest_path = params.get("guest_path", "/tmp/file") file_size = params.get("file_size", "500") transfer_timeout = int(params.get("transfer_timeout", "240")) migrate_between_vhost_novhost = params.get("migrate_between_vhost_novhost") try: utils.run("dd if=/dev/urandom of=%s bs=1M count=%s" % (host_path, file_size)) def run_and_migrate(bg): bg.start() try: while bg.isAlive(): logging.info("File transfer not ended, starting a round of " "migration...") if migrate_between_vhost_novhost == "yes": vhost_status = vm.params.get("vhost") if vhost_status == "vhost=on": vm.params["vhost"] = "vhost=off" elif vhost_status == "vhost=off": vm.params["vhost"] = "vhost=on" vm.migrate(mig_timeout, mig_protocol, mig_cancel_delay) except Exception: # If something bad happened in the main thread, ignore # exceptions raised in the background thread bg.join(suppress_exception=True) raise else: bg.join() error.context("transferring file to guest while migrating", logging.info) bg = utils.InterruptedThread(vm.copy_files_to, (host_path, guest_path), dict(verbose=True, timeout=transfer_timeout)) run_and_migrate(bg) error.context("transferring file back to host while migrating", logging.info) bg = utils.InterruptedThread(vm.copy_files_from, (guest_path, host_path_returned), dict(verbose=True, timeout=transfer_timeout)) run_and_migrate(bg) # Make sure the returned file is identical to the original one error.context("comparing hashes", logging.info) orig_hash = client_utils.hash_file(host_path) returned_hash = client_utils.hash_file(host_path_returned) if orig_hash != returned_hash: raise error.TestFail("Returned file hash (%s) differs from " "original one (%s)" % (returned_hash, orig_hash)) error.context() finally: session.close() if os.path.isfile(host_path): os.remove(host_path) if os.path.isfile(host_path_returned): os.remove(host_path_returned)
if checkpoint in ['ntpd_on', 'sync_ntp']: check_time_keep(vmchecker.checker) # Merge 2 error lists error_list.extend(vmchecker.errors) log_check = utils_v2v.check_log(params, output) if log_check: log_fail(log_check) if len(error_list): test.fail('%d checkpoints failed: %s' % (len(error_list), error_list)) try: v2v_params = { 'hostname': remote_host, 'hypervisor': 'kvm', 'v2v_opts': '-v -x', 'storage': output_storage, 'network': network, 'bridge': bridge, 'target': target, 'main_vm': vm_name, 'input_mode': 'libvirt', 'new_name': vm_name + '_' + utils_misc.generate_random_string(3) } if output_format: v2v_params.update({'output_format': output_format}) # Build rhev related options if output_mode == 'rhev': # Create SASL user on the ovirt host user_pwd = "[['%s', '%s']]" % (params.get("sasl_user"), params.get("sasl_pwd")) v2v_sasl = utils_sasl.SASL(sasl_user_pwd=user_pwd) v2v_sasl.server_ip = params.get("remote_ip") v2v_sasl.server_user = params.get('remote_user') v2v_sasl.server_pwd = params.get('remote_pwd') v2v_sasl.setup(remote=True) if output_mode == 'local': v2v_params['storage'] = data_dir.get_tmp_dir()