def recover(self, params=None): """ Recover test environment """ if self.selinux_enforcing: utils_selinux.set_status("enforcing") if virsh.domain_exists(self.vm_name): virsh.remove_domain(self.vm_name) image_file = params.get("image_name") if os.path.exists(image_file): os.remove(image_file) if os.path.isdir(self.image_path): os.rmdir(self.image_path) self.env.unregister_vm(self.vm_name)
def recover(self, params): """ Recover test environment """ abnormal_type = params.get("abnormal_type") cpu_enable = True if self.cpu_status else False utils_misc.set_cpu_status(self.cpu_num, cpu_enable) if virsh.domain_exists(self.vm_new_name): virsh.remove_domain(self.vm_new_name) if os.path.exists(self.new_image_file): os.remove(self.new_image_file) if self.twice_execute: if virsh.domain_exists(self.vm_new_name1): virsh.remove_domain(self.vm_new_name1) if os.path.exists(self.new_image_file1): os.remove(self.new_image_file1) if abnormal_type == "memory_lack": if params.has_key('memory_pid'): pid = params.get('memory_pid') if isinstance(pid,str): pid = int(pid) utils_misc.safe_kill(pid, signal.SIGKILL) utils.run("swapon -a") tmp_c_file = params.get("tmp_c_file", "/tmp/test.c") tmp_exe_file = params.get("tmp_exe_file", "/tmp/test") if os.path.exists(tmp_c_file): os.remove(tmp_c_file) if os.path.exists(tmp_exe_file): os.remove(tmp_exe_file) elif abnormal_type in ["disk_lack", ""]: if self.selinux_enforcing: utils_selinux.set_status("enforcing") tmp_file = os.path.join(self.mount_dir, "tmp") if os.path.exists(tmp_file): os.remove(tmp_file) # Sometimes one umount action is not enough utils_misc.wait_for(lambda: utils_misc.umount(self.partition, self.mount_dir, self.fs_type), 120) if self.iscsi_dev: self.iscsi_dev.cleanup() os.rmdir(self.mount_dir) elif abnormal_type == "cpu_lack": os.system("cat /sys/fs/cgroup/cpuset/cpuset.cpus > /sys/fs/cgroup/cpuset/machine.slice/cpuset.cpus") remove_machine_cgroup()
def recover(self, params): """ Recover test environment """ abnormal_type = params.get("abnormal_type") if self.cpu_status: cpu.offline(self.cpu_num) else: cpu.online(self.cpu_num) if virsh.domain_exists(self.vm_new_name): virsh.remove_domain(self.vm_new_name) if os.path.exists(self.new_image_file): os.remove(self.new_image_file) if self.twice_execute: if virsh.domain_exists(self.vm_new_name1): virsh.remove_domain(self.vm_new_name1) if os.path.exists(self.new_image_file1): os.remove(self.new_image_file1) if abnormal_type == "memory_lack": if 'memory_pid' in params: pid = params.get('memory_pid') utils_misc.safe_kill(pid, signal.SIGKILL) process.run("swapon -a", shell=True) tmp_c_file = params.get("tmp_c_file", "/tmp/test.c") tmp_exe_file = params.get("tmp_exe_file", "/tmp/test") if os.path.exists(tmp_c_file): os.remove(tmp_c_file) if os.path.exists(tmp_exe_file): os.remove(tmp_exe_file) elif abnormal_type in ["disk_lack", ""]: if self.selinux_enforcing: utils_selinux.set_status("enforcing") tmp_file = os.path.join(self.mount_dir, "tmp") if os.path.exists(tmp_file): os.remove(tmp_file) # Sometimes one umount action is not enough utils_misc.wait_for( lambda: utils_misc.umount(self.partition, self.mount_dir, self. fs_type), 120) if self.iscsi_dev: self.iscsi_dev.cleanup() os.rmdir(self.mount_dir) remove_machine_cgroup()
def run(test, params, env): """ Test svirt in virt-install. (1). Init variables. (2). Set selinux on host. (3). Set label of image. (4). run unattended install. (5). clean up. """ # Get general variables. status_error = ('yes' == params.get("status_error", 'no')) host_sestatus = params.get("host_selinux", "enforcing") # Set selinux status on host. backup_sestatus = utils_selinux.get_status() utils_selinux.set_status(host_sestatus) # Set the image label. disk_label = params.get("disk_label", None) vm_name = params.get("main_vm", None) vm_params = params.object_params(vm_name) base_dir = params.get("images_base_dir", data_dir.get_data_dir()) image_filename = storage.get_image_filename(vm_params, base_dir) utils_selinux.set_context_of_file(image_filename, disk_label) try: try: unattended_install.run(test, params, env) # Install completed. if status_error: raise error.TestFail('Test successed in negative case.') except error.CmdError, e: # Install failed. if not status_error: raise error.TestFail("Test failed in positive case." "error: %s" % e) finally: # cleanup utils_selinux.set_status(backup_sestatus) if virsh.domain_exists(vm_name): virsh.remove_domain(vm_name)
def result_confirm(self, params): """ Confirm if VM installation is succeed """ if self.twice_execute and self.kill_first: get_pid_cmd = "ps -ef | grep '%s' | grep qemu-kvm | grep -v grep"\ % self.vm_name result = process.run(get_pid_cmd, ignore_status=True, shell=True) if result.exit_status: self.test.fail("First install failed!") install_pid = result.stdout.strip().split()[1] utils_misc.safe_kill(int(install_pid), signal.SIGKILL) self.td.join() if self.read_only: if virsh.domain_exists(self.vm_name): self.test.fail("Domain '%s' should not exist" % self.vm_name) os.chmod(self.image_path, stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO) else: if not virsh.domain_exists(self.vm_name): self.test.fail("Domain '%s' should exists, no matter its" " installation is succeed or failed!" % self.vm_name) else: if not self.kill_first: if self.vm.is_dead(): self.vm.start() try: self.vm.wait_for_login() except remote.LoginTimeoutError as detail: self.test.fail(str(detail)) else: virsh.remove_domain(self.vm_name) if self.twice_execute or self.read_only: self.td1 = threading.Thread(target=unattended_install.run, args=(self.test, params, self.env)) self.td1.start() self.td1.join() if not virsh.domain_exists(self.vm_name): self.test.fail("Domain '%s' installation failed!" % self.vm_name)
def result_confirm(self, params): """ Confirm if VM installation is succeed """ if self.twice_execute and self.kill_first: get_pid_cmd = "ps -ef | grep '%s' | grep qemu-kvm | grep -v grep"\ % self.vm_name result = process.run(get_pid_cmd, ignore_status=True, shell=True) if result.exit_status: self.test.fail("First install failed!") install_pid = result.stdout_text.strip().split()[1] utils_misc.safe_kill(int(install_pid), signal.SIGKILL) self.td.join() if self.read_only: if virsh.domain_exists(self.vm_name): self.test.fail("Domain '%s' should not exist" % self.vm_name) os.chmod(self.image_path, stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO) else: if not virsh.domain_exists(self.vm_name): self.test.fail("Domain '%s' should exists, no matter its" " installation is succeed or failed!" % self.vm_name) else: if not self.kill_first: if self.vm.is_dead(): self.vm.start() try: self.vm.wait_for_login() except remote.LoginTimeoutError as detail: self.test.fail(str(detail)) else: virsh.remove_domain(self.vm_name) if self.twice_execute or self.read_only: self.td1 = threading.Thread(target=unattended_install.run, args=(self.test, params, self.env)) self.td1.start() self.td1.join() if not virsh.domain_exists(self.vm_name): self.test.fail("Domain '%s' installation failed!" % self.vm_name)
def recover(self, params): """ Recover test environment """ abnormal_type = params.get("abnormal_type") cpu_enable = True if self.cpu_status else False utils_misc.set_cpu_status(self.cpu_num, cpu_enable) if virsh.domain_exists(self.vm_new_name): virsh.remove_domain(self.vm_new_name) if os.path.exists(self.new_image_file): os.remove(self.new_image_file) if self.twice_execute: if virsh.domain_exists(self.vm_new_name1): virsh.remove_domain(self.vm_new_name1) if os.path.exists(self.new_image_file1): os.remove(self.new_image_file1) if abnormal_type == "memory_lack": if 'memory_pid' in params: pid = params.get('memory_pid') utils_misc.safe_kill(pid, signal.SIGKILL) process.run("swapon -a", shell=True) tmp_c_file = params.get("tmp_c_file", "/tmp/test.c") tmp_exe_file = params.get("tmp_exe_file", "/tmp/test") if os.path.exists(tmp_c_file): os.remove(tmp_c_file) if os.path.exists(tmp_exe_file): os.remove(tmp_exe_file) elif abnormal_type in ["disk_lack", ""]: if self.selinux_enforcing: utils_selinux.set_status("enforcing") tmp_file = os.path.join(self.mount_dir, "tmp") if os.path.exists(tmp_file): os.remove(tmp_file) # Sometimes one umount action is not enough utils_misc.wait_for(lambda: utils_misc.umount(self.partition, self.mount_dir, self.fs_type), 120) if self.iscsi_dev: self.iscsi_dev.cleanup() os.rmdir(self.mount_dir) remove_machine_cgroup()
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) vm_name = params.get("main_vm", "EXAMPLE") new_vm_name = params.get("new_vm_name") input_mode = params.get("input_mode") 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' 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 %s'" % target_path process.system(cmd, verbose=True) cmd = su_cmd + "'virsh pool-create-as %s dir" % pool_name cmd += " --target %s'" % target_path process.system(cmd, verbose=True) else: pvt.pre_pool(pool_name, pool_type, pool_target, emulated_img) 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: cmd = su_cmd + "'virsh pool-destroy %s'" % pool_name process.system(cmd, verbose=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 setup_esx_ssh_key(hostname, user, password, port=22): """ Setup up remote login in esx server by using public key """ logging.debug('Performing SSH key setup on %s:%d as %s.' % (hostname, port, user)) try: session = remote.remote_login(client='ssh', host=hostname, username=user, port=port, password=password, prompt=r'[ $#%]') public_key = ssh_key.get_public_key() session.cmd("echo '%s' >> /etc/ssh/keys-root/authorized_keys; " % public_key) logging.debug('SSH key setup complete.') session.close() except Exception as err: logging.debug('SSH key setup has failed. %s', err) 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, 'debug': True } v2v_virsh = virsh.VirshPersistent(**virsh_dargs) 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: 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().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 = "%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') # For esx, '(raw)' is fixed? Let's see if others will be met. disks_info_pattern = '|'.join([ "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_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 if v2v_start and len(line) > 72: test.fail('Error log longer than 72 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': 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: 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 == ['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) 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 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) if checkpoint == 'with_ic': ic_uri = 'qemu:///session' input_option = "-i %s -ic %s %s" % (input_mode, ic_uri, vm_name) if checkpoint == 'without_ic': input_option = '-i %s %s' % (input_mode, vm_name) # 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 -os %s" % (output_mode, output_storage) if checkpoint == 'rhv': output_option = output_option.replace('rhev', 'rhv') 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) # 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 ") ssh_key.setup_ssh_key(remote_host, user=user, port=22, password=passwd) 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 += " --password-file %s" % vpx_passwd_file # 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": create_pool() # 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 create_pool(user_pool=True, pool_name='src_pool', pool_target='v2v_src_pool') create_pool(user_pool=True) logging.debug(virsh.pool_list(uri='qemu:///session')) sh_install_vm = params.get('sh_install_vm') if not sh_install_vm: test.error('Source vm installing script missing') with open(sh_install_vm) as fh: cmd_install_vm = fh.read().strip() process.run('su - %s -c "%s"' % (v2v_user, cmd_install_vm), timeout=10, shell=True) params['cmd_clean_vm'] = "%s 'virsh undefine %s'" % (su_cmd, vm_name) 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", "123qweP") vmx = params.get('vmx') setup_esx_ssh_key(esx_ip, esx_user, esx_pwd) try: utils_misc.add_identities_into_ssh_agent() except Exception: process.run("ssh-agent -k") raise exceptions.TestError("Fail to setup 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/') # 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 == "xen": process.run("ssh-agent -k") if hypervisor == "esx": process.run("rm -rf %s" % vpx_passwd_file) 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') cleanup_pool(user_pool=True) 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: vmcheck = utils_v2v.VMCheck(test, params, env) vmcheck.cleanup() if checkpoint in ['with_ic', 'without_ic']: process.run(params['cmd_clean_vm']) if new_v2v_user: process.system("userdel -f %s" % v2v_user) if backup_xml: backup_xml.sync() if checkpoint == 'vmx': utils_misc.umount(params['nfs_vmx'], params['mount_point'], 'nfs') os.rmdir(params['mount_point']) if checkpoint == 'simulate_nfs': process.run('rm -rf /tmp/rhv/')
def run(test, params, env): """ LXC container life cycle testing by virsh command """ uri = params.get("connect_uri", "lxc:///") vm_name = params.get("main_vm") dom_type = params.get("lxc_domtype", "lxc") vcpu = int(params.get("lxc_vcpu", 1)) max_mem = int(params.get("lxc_max_mem", 500000)) current_mem = int(params.get("lxc_current_mem", 500000)) os_type = params.get("lxc_ostype", "exe") os_arch = params.get("lxc_osarch", "x86_64") os_init = params.get("lxc_osinit", "/bin/sh") emulator_path = params.get("lxc_emulator", "/usr/libexec/libvirt_lxc") interface_type = params.get("lxc_interface_type", "network") net_name = params.get("lxc_net_name", "default") full_os = ("yes" == params.get("lxc_full_os", "no")) install_root = params.get("lxc_install_root", "/") fs_target = params.get("lxc_fs_target", "/") fs_accessmode = params.get("lxc_fs_accessmode", "passthrough") passwd = params.get("lxc_fs_passwd", "redhat") def generate_container_xml(): """ Generate container xml """ vmxml = vm_xml.VMXML(dom_type) vmxml.vm_name = vm_name vmxml.max_mem = max_mem vmxml.current_mem = current_mem vmxml.vcpu = vcpu # Generate os vm_os = vm_xml.VMOSXML() vm_os.type = os_type vm_os.arch = os_arch vm_os.init = os_init vmxml.os = vm_os # Generate emulator emulator = Emulator() emulator.path = emulator_path # Generate console console = Console() filesystem = Filesystem() filesystem.accessmode = fs_accessmode filesystem.source = {'dir': install_root} filesystem.target = {'dir': fs_target} # Add emulator and console in devices devices = vm_xml.VMXMLDevices() devices.append(emulator) devices.append(console) devices.append(filesystem) # Add network device network = Interface(type_name=interface_type) network.mac_address = utils_net.generate_mac_address_simple() network.source = {interface_type: net_name} devices.append(network) vmxml.set_devices(devices) return vmxml def check_state(expected_state): result = virsh.domstate(vm_name, uri=uri) utlv.check_exit_status(result) vm_state = result.stdout.strip() if vm_state == expected_state: logging.info("Get expected state: %s", vm_state) else: raise TestFail("Get unexpected state: %s", vm_state) virsh_args = {'uri': uri, 'debug': True} try: vmxml = generate_container_xml() with open(vmxml.xml, 'r') as f: logging.info("Container XML:\n%s", f.read()) if full_os: if not os.path.exists(install_root): os.mkdir(install_root) # Install core os under installroot cmd = "yum --releasever=/ --installroot=%s" % install_root cmd += " --nogpgcheck -y groupinstall core" process.run(cmd, shell=True) # Fix root login on console process.run("echo 'pts/0' >> %s/etc/securetty" % install_root, shell=True) for i in [ "session required pam_selinux.so close", "session required pam_selinux.so open", "session required pam_loginuid.so" ]: process.run('sed -i s/"%s\"/"#%s"/g %s/etc/pam.d/login' % (i, i, install_root), shell=True) # Fix root login for sshd process.run('sed -i s/"%s\"/"#%s"/g %s/etc/pam.d/sshd' % (i, i, install_root), shell=True) # Config basic network net_file = install_root + '/etc/sysconfig/network' with open(net_file, 'w') as f: f.write('NETWORKING=yes\nHOSTNAME=%s\n' % vm_name) net_script = install_root + '/etc/sysconfig/network-scripts/ifcfg-eth0' with open(net_script, 'w') as f: f.write('DEVICE=eth0\nBOOTPROTO=dhcp\nONBOOT=yes\n') # Set root password and enable sshd session = aexpect.ShellSession("chroot %s" % install_root) session.sendline('echo %s|passwd root --stdin' % passwd) session.sendline('chkconfig sshd on') session.close() # Create result = virsh.create(vmxml.xml, **virsh_args) utlv.check_exit_status(result) check_state('running') # Destroy result = virsh.destroy(vm_name, **virsh_args) utlv.check_exit_status(result) if not virsh.domain_exists(vm_name, **virsh_args): logging.info("Destroy transient LXC domain successfully") else: raise TestFail("Transient LXC domain still exist after destroy") # Define result = virsh.define(vmxml.xml, **virsh_args) utlv.check_exit_status(result) check_state('shut off') # List result = virsh.dom_list('--inactive', **virsh_args) utlv.check_exit_status(result) if re.findall("(%s)\s+shut off" % vm_name, result.stdout): logging.info("Find %s in virsh list output", vm_name) else: raise TestFail("Not find %s in virsh list output") # Dumpxml result = virsh.dumpxml(vm_name, uri=uri, debug=False) utlv.check_exit_status(result) # Edit edit_vcpu = '2' logging.info("Change vcpu of LXC container to %s", edit_vcpu) edit_cmd = [r":%s /[0-9]*<\/vcpu>/" + edit_vcpu + r"<\/vcpu>"] if not utlv.exec_virsh_edit(vm_name, edit_cmd, connect_uri=uri): raise TestFail("Run edit command fail") else: result = virsh.dumpxml(vm_name, **virsh_args) new_vcpu = re.search(r'(\d*)</vcpu>', result.stdout).group(1) if new_vcpu == edit_vcpu: logging.info("vcpu number is expected after do edit") else: raise TestFail("vcpu number is unexpected after do edit") # Start result = virsh.start(vm_name, **virsh_args) utlv.check_exit_status(result) check_state('running') # Suspend result = virsh.suspend(vm_name, **virsh_args) utlv.check_exit_status(result) check_state('paused') # Resume result = virsh.resume(vm_name, **virsh_args) utlv.check_exit_status(result) check_state('running') # Reboot(not supported on RHEL6) result = virsh.reboot(vm_name, **virsh_args) supported_err = 'not supported by the connection driver: virDomainReboot' if supported_err in result.stderr.strip(): logging.info("Reboot is not supported") else: utlv.check_exit_status(result) # Destroy result = virsh.destroy(vm_name, **virsh_args) utlv.check_exit_status(result) check_state('shut off') # Undefine result = virsh.undefine(vm_name, **virsh_args) utlv.check_exit_status(result) if not virsh.domain_exists(vm_name, **virsh_args): logging.info("Undefine LXC domain successfully") else: raise TestFail("LXC domain still exist after undefine") finally: virsh.remove_domain(vm_name, **virsh_args) if full_os and os.path.exists(install_root): shutil.rmtree(install_root)
def run(test, params, env): """ Test command: virsh managedsave. This command can save and destroy a running domain, so it can be restarted from the same state at a later time. """ vm_name = params.get("main_vm") vm = env.get_vm(vm_name) managed_save_file = "/var/lib/libvirt/qemu/save/%s.save" % vm_name shutdown_timeout = int(params.get('shutdown_timeout', 60)) # define function def vm_recover_check(option, libvirtd, check_shutdown=False): """ Check if the vm can be recovered correctly. :param guest_name : Checked vm's name. :param option : managedsave command option. """ # This time vm not be shut down if vm.is_alive(): test.fail("Guest should be inactive") # Check vm managed save state. ret = virsh.dom_list("--managed-save --inactive", debug=True) vm_state1 = re.findall(r".*%s.*" % vm_name, ret.stdout.strip())[0].split()[2] ret = virsh.dom_list("--managed-save --all", debug=True) vm_state2 = re.findall(r".*%s.*" % vm_name, ret.stdout.strip())[0].split()[2] if vm_state1 != "saved" or vm_state2 != "saved": test.fail("Guest state should be saved") virsh.start(vm_name, debug=True) # This time vm should be in the list if vm.is_dead(): test.fail("Guest should be active") # Restart libvirtd and check vm status again. libvirtd.restart() if vm.is_dead(): test.fail("Guest should be active after" " restarting libvirtd") # Check managed save file: if os.path.exists(managed_save_file): test.fail("Managed save image exist " "after starting the domain") if option: if option.count("running"): if vm.is_dead() or vm.is_paused(): test.fail("Guest state should be" " running after started" " because of '--running' option") elif option.count("paused"): if not vm.is_paused(): test.fail("Guest state should be" " paused after started" " because of '--paused' option") else: if params.get("paused_after_start_vm") == "yes": if not vm.is_paused(): test.fail("Guest state should be" " paused after started" " because of initia guest state") if check_shutdown: # Resume the domain. if vm.is_paused(): vm.resume() vm.wait_for_login() # Shutdown and start the domain, # it should be in runing state and can be login. vm.shutdown() if not vm.wait_for_shutdown(shutdown_timeout): test.fail('VM failed to shutdown') vm.start() vm.wait_for_login() def vm_undefine_check(vm_name): """ Check if vm can be undefined with manage-save option """ #backup xml file xml_backup = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) if not os.path.exists(managed_save_file): test.fail("Can't find managed save image") #undefine domain with no options. if not virsh.undefine(vm_name, options=None, ignore_status=True).exit_status: test.fail("Guest shouldn't be undefined" "while domain managed save image exists") #undefine domain with managed-save option. if virsh.undefine(vm_name, options="--managed-save", ignore_status=True).exit_status: test.fail("Guest can't be undefine with " "managed-save option") if os.path.exists(managed_save_file): test.fail("Managed save image exists" " after undefining vm") #restore and start the vm. xml_backup.define() vm.start() def check_flags_parallel(virsh_cmd, bash_cmd, flags): """ Run the commands parallel and check the output. """ cmd = ("%s & %s" % (virsh_cmd, bash_cmd)) ret = process.run(cmd, ignore_status=True, shell=True, ignore_bg_processes=True) output = ret.stdout_text.strip() logging.debug("check flags output: %s" % output) lines = re.findall(r"flags:.(\d+)", output, re.M) logging.debug("Find all fdinfo flags: %s" % lines) lines = [int(i, 8) & flags for i in lines] if flags not in lines: test.fail("Checking flags %s failed" % flags) return ret def check_multi_guests(guests, start_delay, libvirt_guests): """ Check start_delay option for multiple guests. """ # Destroy vm first if vm.is_alive(): vm.destroy(gracefully=False) # Clone given number of guests timeout = params.get("clone_timeout", 360) for i in range(int(guests)): dst_vm = "%s_%s" % (vm_name, i) utils_libguestfs.virt_clone_cmd(vm_name, dst_vm, True, timeout=timeout) virsh.start(dst_vm, debug=True) # Wait 10 seconds for vm to start time.sleep(10) is_systemd = process.run("cat /proc/1/comm", shell=True).stdout_text.count("systemd") if is_systemd: libvirt_guests.restart() pattern = r'(.+ \d\d:\d\d:\d\d).+: Resuming guest.+done' else: ret = process.run("service libvirt-guests restart | \ awk '{ print strftime(\"%b %y %H:%M:%S\"), \ $0; fflush(); }'", shell=True) pattern = r'(.+ \d\d:\d\d:\d\d)+ Resuming guest.+done' # libvirt-guests status command read messages from systemd # journal, in cases of messages are not ready in time, # add a time wait here. def wait_func(): return libvirt_guests.raw_status().stdout.count("Resuming guest") utils_misc.wait_for(wait_func, 5) if is_systemd: ret = libvirt_guests.raw_status() logging.info("status output: %s", ret.stdout_text) resume_time = re.findall(pattern, ret.stdout_text, re.M) if not resume_time: test.fail("Can't see messages of resuming guest") # Convert time string to int resume_seconds = [ time.mktime(time.strptime(tm, "%b %y %H:%M:%S")) for tm in resume_time ] logging.info("Resume time in seconds: %s", resume_seconds) # Check if start_delay take effect for i in range(len(resume_seconds) - 1): if resume_seconds[i + 1] - resume_seconds[i] < int(start_delay): test.fail("Checking start_delay failed") def wait_for_state(vm_state): """ Wait for vm state is ready. """ utils_misc.wait_for(lambda: vm.state() == vm_state, 10) def check_guest_flags(bash_cmd, flags): """ Check bypass_cache option for single guest. """ # Drop caches. drop_caches() # form proper parallel command based on if systemd is used or not is_systemd = process.run("cat /proc/1/comm", shell=True).stdout_text.count("systemd") if is_systemd: virsh_cmd_stop = "systemctl stop libvirt-guests" virsh_cmd_start = "systemctl start libvirt-guests" else: virsh_cmd_stop = "service libvirt-guests stop" virsh_cmd_start = "service libvirt-guests start" ret = check_flags_parallel( virsh_cmd_stop, bash_cmd % (managed_save_file, managed_save_file, "1"), flags) if is_systemd: ret = libvirt_guests.raw_status() logging.info("status output: %s", ret.stdout_text) if all([ "Suspending %s" % vm_name not in ret.stdout_text, "stopped, with saved guests" not in ret.stdout_text ]): test.fail("Can't see messages of suspending vm") # status command should return 3. if not is_systemd: ret = libvirt_guests.raw_status() if ret.exit_status != 3: test.fail("The exit code %s for libvirt-guests" " status is not correct" % ret) # Wait for VM in shut off state wait_for_state("shut off") check_flags_parallel( virsh_cmd_start, bash_cmd % (managed_save_file, managed_save_file, "0"), flags) # Wait for VM in running state wait_for_state("running") def vm_msave_remove_check(vm_name): """ Check managed save remove command. """ if not os.path.exists(managed_save_file): test.fail("Can't find managed save image") virsh.managedsave_remove(vm_name, debug=True) if os.path.exists(managed_save_file): test.fail("Managed save image still exists") virsh.start(vm_name, debug=True) # The domain state should be running if vm.state() != "running": test.fail("Guest state should be" " running after started") def vm_managedsave_loop(vm_name, loop_range, libvirtd): """ Run a loop of managedsave command and check its result. """ if vm.is_dead(): virsh.start(vm_name, debug=True) for i in range(int(loop_range)): logging.debug("Test loop: %s" % i) virsh.managedsave(vm_name, debug=True) virsh.start(vm_name, debug=True) # Check libvirtd status. if not libvirtd.is_running(): test.fail("libvirtd is stopped after cmd") # Check vm status. if vm.state() != "running": test.fail("Guest isn't in running state") def build_vm_xml(vm_name, **dargs): """ Build the new domain xml and define it. """ try: # stop vm before doing any change to xml if vm.is_alive(): vm.destroy(gracefully=False) vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) if dargs.get("cpu_mode"): if "cpu" in vmxml: del vmxml.cpu cpuxml = vm_xml.VMCPUXML() cpuxml.mode = params.get("cpu_mode", "host-model") cpuxml.match = params.get("cpu_match", "exact") cpuxml.fallback = params.get("cpu_fallback", "forbid") cpu_topology = {} cpu_topology_sockets = params.get("cpu_topology_sockets") if cpu_topology_sockets: cpu_topology["sockets"] = cpu_topology_sockets cpu_topology_cores = params.get("cpu_topology_cores") if cpu_topology_cores: cpu_topology["cores"] = cpu_topology_cores cpu_topology_threads = params.get("cpu_topology_threads") if cpu_topology_threads: cpu_topology["threads"] = cpu_topology_threads if cpu_topology: cpuxml.topology = cpu_topology vmxml.cpu = cpuxml vmxml.vcpu = int(params.get("vcpu_nums")) if dargs.get("sec_driver"): seclabel_dict = { "type": "dynamic", "model": "selinux", "relabel": "yes" } vmxml.set_seclabel([seclabel_dict]) vmxml.sync() vm.start() except Exception as e: logging.error(str(e)) test.cancel("Build domain xml failed") status_error = ("yes" == params.get("status_error", "no")) vm_ref = params.get("managedsave_vm_ref", "name") libvirtd_state = params.get("libvirtd", "on") extra_param = params.get("managedsave_extra_param", "") progress = ("yes" == params.get("managedsave_progress", "no")) cpu_mode = "yes" == params.get("managedsave_cpumode", "no") test_undefine = "yes" == params.get("managedsave_undefine", "no") test_bypass_cache = "yes" == params.get("test_bypass_cache", "no") autostart_bypass_cache = params.get("autostart_bypass_cache", "") multi_guests = params.get("multi_guests", "") test_libvirt_guests = params.get("test_libvirt_guests", "") check_flags = "yes" == params.get("check_flags", "no") security_driver = params.get("security_driver", "") remove_after_cmd = "yes" == params.get("remove_after_cmd", "no") option = params.get("managedsave_option", "") check_shutdown = "yes" == params.get("shutdown_after_cmd", "no") pre_vm_state = params.get("pre_vm_state", "") move_saved_file = "yes" == params.get("move_saved_file", "no") test_loop_cmd = "yes" == params.get("test_loop_cmd", "no") if option: if not virsh.has_command_help_match('managedsave', option): # Older libvirt does not have this option test.cancel("Older libvirt does not" " handle arguments consistently") # Backup xml file. vmxml_backup = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) # Get the libvirtd service libvirtd = utils_libvirtd.Libvirtd() # Get config files. qemu_config = utils_config.LibvirtQemuConfig() libvirt_guests_config = utils_config.LibvirtGuestsConfig() # Get libvirt-guests service libvirt_guests = Factory.create_service("libvirt-guests") try: # Destroy vm first for setting configuration file if vm.state() == "running": vm.destroy(gracefully=False) # Prepare test environment. if libvirtd_state == "off": libvirtd.stop() if autostart_bypass_cache: ret = virsh.autostart(vm_name, "", ignore_status=True, debug=True) libvirt.check_exit_status(ret) qemu_config.auto_start_bypass_cache = autostart_bypass_cache libvirtd.restart() if security_driver: qemu_config.security_driver = [security_driver] if test_libvirt_guests: if multi_guests: start_delay = params.get("start_delay", "20") libvirt_guests_config.START_DELAY = start_delay if check_flags: libvirt_guests_config.BYPASS_CACHE = "1" # The config file format should be "x=y" instead of "x = y" process.run( "sed -i -e 's/ = /=/g' " "/etc/sysconfig/libvirt-guests", shell=True) libvirt_guests.restart() # Change domain xml. if cpu_mode: build_vm_xml(vm_name, cpu_mode=True) if security_driver: build_vm_xml(vm_name, sec_driver=True) # Turn VM into certain state. if pre_vm_state == "transient": logging.info("Creating %s..." % vm_name) vmxml_for_test = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) if vm.is_alive(): vm.destroy(gracefully=False) # Wait for VM to be in shut off state utils_misc.wait_for(lambda: vm.state() == "shut off", 10) vm.undefine() if virsh.create(vmxml_for_test.xml, ignore_status=True, debug=True).exit_status: vmxml_backup.define() test.cancel("Cann't create the domain") # Wait for vm in stable state if params.get("start_vm") == "yes": if vm.state() == "shut off": vm.start() vm.wait_for_login() # run test case domid = vm.get_id() domuuid = vm.get_uuid() if vm_ref == "id": vm_ref = domid elif vm_ref == "uuid": vm_ref = domuuid elif vm_ref == "hex_id": vm_ref = hex(int(domid)) elif vm_ref.count("invalid"): vm_ref = params.get(vm_ref) elif vm_ref == "name": vm_ref = vm_name # Ignore exception with "ignore_status=True" if progress: option += " --verbose" option += extra_param # For bypass_cache test. Run a shell command to check fd flags while # excuting managedsave command software_mgr = software_manager.SoftwareManager() if not software_mgr.check_installed('lsof'): logging.info('Installing lsof package:') software_mgr.install('lsof') bash_cmd = ( "let i=1; while((i++<400)); do if [ -e %s ]; then (cat /proc" "/$(lsof -w %s|awk '/libvirt_i/{print $2}')/fdinfo/%s |" "grep 'flags:.*') && break; else sleep 0.05; fi; done;") # Flags to check bypass cache take effect flags = os.O_DIRECT if test_bypass_cache: # Drop caches. drop_caches() virsh_cmd = "virsh managedsave %s %s" % (option, vm_name) check_flags_parallel( virsh_cmd, bash_cmd % (managed_save_file, managed_save_file, "1"), flags) # Wait for VM in shut off state wait_for_state("shut off") virsh_cmd = "virsh start %s %s" % (option, vm_name) check_flags_parallel( virsh_cmd, bash_cmd % (managed_save_file, managed_save_file, "0"), flags) # Wait for VM in running state wait_for_state("running") elif test_libvirt_guests: logging.debug("libvirt-guests status: %s", libvirt_guests.status()) if multi_guests: check_multi_guests(multi_guests, start_delay, libvirt_guests) if check_flags: check_guest_flags(bash_cmd, flags) else: # Ensure VM is running utils_misc.wait_for(lambda: vm.state() == "running", 10) ret = virsh.managedsave(vm_ref, options=option, ignore_status=True, debug=True) status = ret.exit_status # The progress information outputed in error message error_msg = ret.stderr.strip() if move_saved_file: cmd = "echo > %s" % managed_save_file process.run(cmd, shell=True) # recover libvirtd service start if libvirtd_state == "off": libvirtd.start() if status_error: if not status: if libvirtd_state == "off" and libvirt_version.version_compare( 5, 6, 0): logging.info( "From libvirt version 5.6.0 libvirtd is restarted " "and command should succeed") else: test.fail("Run successfully with wrong command!") else: if status: test.fail("Run failed with right command") if progress: if not error_msg.count("Managedsave:"): test.fail("Got invalid progress output") if remove_after_cmd: vm_msave_remove_check(vm_name) elif test_undefine: vm_undefine_check(vm_name) elif autostart_bypass_cache: # rhbz#1755303 if libvirt_version.version_compare(5, 6, 0): os.remove("/run/libvirt/qemu/autostarted") libvirtd.stop() virsh_cmd = ("(service libvirtd start)") check_flags_parallel( virsh_cmd, bash_cmd % (managed_save_file, managed_save_file, "0"), flags) elif test_loop_cmd: loop_range = params.get("loop_range", "20") vm_managedsave_loop(vm_name, loop_range, libvirtd) else: vm_recover_check(option, libvirtd, check_shutdown) finally: # Restore test environment. # Restart libvirtd.service qemu_config.restore() libvirt_guests_config.restore() libvirtd.restart() if autostart_bypass_cache: virsh.autostart(vm_name, "--disable", ignore_status=True, debug=True) vm.destroy(gracefully=False) virsh.managedsave_remove(vm_name, debug=True) vmxml_backup.sync() if multi_guests: for i in range(int(multi_guests)): virsh.remove_domain("%s_%s" % (vm_name, i), "--remove-all-storage", debug=True)
else: vm_recover_check(option, libvirtd, check_shutdown) finally: # Restore test environment. # Ensure libvirtd is started if not libvirtd.is_running(): libvirtd.start() if vm.is_paused(): virsh.resume(vm_name) elif vm.is_dead(): vm.start() # Wait for VM in running state wait_for_state("running") if autostart_bypass_cache: virsh.autostart(vm_name, "--disable", ignore_status=True) if vm.is_alive(): vm.destroy(gracefully=False) # Wait for VM to be in shut off state utils_misc.wait_for(lambda: vm.state() == "shut off", 10) virsh.managedsave_remove(vm_name) vmxml_backup.sync() if multi_guests: for i in range(int(multi_guests)): virsh.remove_domain("%s_%s" % (vm_name, i), "--remove-all-storage") qemu_config.restore() libvirt_guests_config.restore() libvirtd.restart()
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: check_ver = backend_version if backend_version != 'none' else '2.0' pattern = '"emulator" version="%s"' % check_ver 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." % check_ver) # 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 command: virsh rename. The command can rename a domain. 1.Prepare test environment. 2.Perform virsh rename operation. 3.Recover test environment. 4.Confirm the test result. """ # Get specific parameter value vm_name = params.get("main_vm") vm = env.get_vm(vm_name) domuuid = vm.get_uuid() vm_ref = params.get("domrename_vm_ref", "name") status_error = "yes" == params.get("status_error", "no") new_name = params.get("vm_new_name", "new") pre_vm_state = params.get("domrename_vm_state", "shutoff") domain_option = params.get("dom_opt", "") new_name_option = params.get("newname_opt", "") add_vm = "yes" == params.get("add_vm", "no") # Replace the varaiables if vm_ref == "name": vm_ref = vm_name elif vm_ref == "uuid": vm_ref = domuuid if new_name == "vm2_name": vm2_name = ("%s" % vm_name[:-1])+"2" new_name = vm2_name # Build input params dom_param = ' '.join([domain_option, vm_ref]) new_name_param = ' '.join([new_name_option, new_name]) # Backup for recovery. vmxml_backup = libvirt_xml.vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) logging.debug("vm xml is %s", vmxml_backup) # Clone additional vms if needed if add_vm: 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") ret_clone = utils_libguestfs.virt_clone_cmd(vm_name, vm2_name, True, timeout=360) if ret_clone.exit_status: test.fail("Error occured when clone a second vm!") vm2 = libvirt_vm.VM(vm2_name, vm.params, vm.root_dir, vm.address_cache) virsh.dom_list("--name --all", debug=True) # Create object instance for renamed domain new_vm = libvirt_vm.VM(new_name, vm.params, vm.root_dir, vm.address_cache) # Prepare vm state if pre_vm_state != "shutoff": vm.start() if pre_vm_state == "paused": vm.pause() logging.debug("Domain state is now: %s", vm.state()) elif pre_vm_state == "managed_saved": vm.managedsave() elif pre_vm_state == "with_snapshot": virsh.snapshot_create_as(vm_name, "snap1 --disk-only", debug=True) vm.destroy(gracefully=False) try: result = virsh.domrename(dom_param, new_name_param, ignore_status=True, debug=True) # Raise unexpected pass or fail libvirt.check_exit_status(result, status_error) # Return expected failure for negative tests if status_error: logging.debug("Expected failure: %s", result.stderr) return # Checkpoints after domrename succeed else: list_ret = virsh.dom_list("--name --all", debug=True).stdout domname_ret = virsh.domname(domuuid, debug=True).stdout.strip() if new_name not in list_ret or vm_name in list_ret: test.fail("New name does not affect in virsh list") if domname_ret != new_name: test.fail("New domain name does not affect in virsh domname uuid") # Try to start vm with the new name new_vm.start() finally: # Remove additional vms if add_vm and vm2.exists() and result.exit_status: virsh.remove_domain(vm2_name, "--remove-all-storage") # Undefine newly renamed domain if new_vm.exists(): if new_vm.is_alive(): new_vm.destroy(gracefully=False) new_vm.undefine() # Recover domain state if pre_vm_state != "shutoff": if pre_vm_state == "with_snapshot": libvirt.clean_up_snapshots(vm_name) else: if pre_vm_state == "managed_saved": vm.start() vm.destroy(gracefully=False) # Restore VM vmxml_backup.sync()
def run(test, params, env): """ Convert a remote vm to local libvirt(KVM). """ for v in params.itervalues(): if "V2V_EXAMPLE" in v: raise exceptions.TestSkipError("Please set real value for %s" % v) vm_name = params.get("main_vm") source_user = params.get("username", "root") xen_ip = params.get("xen_ip") xen_pwd = params.get("xen_pwd") vpx_ip = params.get("vpx_ip") vpx_pwd = params.get("vpx_pwd") vpx_pwd_file = params.get("vpx_passwd_file") vpx_dc = params.get("vpx_dc") esx_ip = params.get("esx_ip") hypervisor = params.get("hypervisor") input_mode = params.get("input_mode") target = params.get("target") v2v_opts = params.get("v2v_opts") # 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_pwd_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") raise exceptions.TestError("Fail to setup ssh-agent") else: raise exceptions.TestSkipError("Unspported hypervisor: %s" % hypervisor) # Create libvirt URI for the source node v2v_uri = utils_v2v.Uri(hypervisor) remote_uri = v2v_uri.get_uri(source_ip, vpx_dc, esx_ip) logging.debug("Remote host uri for converting: %s", remote_uri) # Make sure the VM exist before convert virsh_dargs = {'uri': remote_uri, 'remote_ip': source_ip, 'remote_user': source_user, 'remote_pwd': source_pwd, 'debug': True} remote_virsh = virsh.VirshPersistent(**virsh_dargs) try: if not remote_virsh.domain_exists(vm_name): raise exceptions.TestError("VM '%s' not exist" % vm_name) finally: remote_virsh.close_session() # Prepare libvirt storage pool pool_type = params.get("pool_type") pool_name = params.get("pool_name") target_path = params.get("target_path") libvirt_pool = utlv.PoolVolumeTest(test, params) libvirt_pool.pre_pool(pool_name, pool_type, target_path, '') # Preapre libvirt virtual network network = params.get("network") net_kwargs = {'net_name': network, 'address': params.get('network_addr'), 'dhcp_start': params.get('network_dhcp_start'), 'dhcp_end': params.get('network_dhcp_end')} libvirt_net = utlv.LibvirtNetwork('vnet', **net_kwargs) net_info = virsh.net_info(network).stdout.strip() bridge = re.search(r'Bridge:\s+(\S+)', net_info).group(1) # 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': pool_name, 'hostname': source_ip} 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}) # Set libguestfs environment os.environ['LIBGUESTFS_BACKEND'] = 'direct' try: # Execute virt-v2v command ret = utils_v2v.v2v_cmd(v2v_params) logging.debug("virt-v2v verbose messages:\n%s", ret) if ret.exit_status != 0: raise exceptions.TestFail("Convert VM failed") logging.debug("XML info:\n%s", virsh.dumpxml(vm_name)) vm = env.create_vm("libvirt", "libvirt", vm_name, params, test.bindir) vm.start() # Check all checkpoints after convert vmchecker = VMChecker(test, params, env) ret = vmchecker.run() vmchecker.cleanup() if ret == 0: logging.info("All checkpoints passed") else: raise exceptions.TestFail("%s checkpoints failed" % ret) finally: if hypervisor == "esx": os.remove(vpx_pwd_file) if hypervisor == "xen": process.run("ssh-agent -k") # Clean libvirt VM virsh.remove_domain(vm_name) # Clean libvirt pool if libvirt_pool: libvirt_pool.cleanup_pool(pool_name, pool_type, target_path, '') # Clean libvirt network if libvirt_net: libvirt_net.cleanup()
libvirtd.stop() virsh_cmd = ("(service libvirtd start)") check_flags_parallel( virsh_cmd, bash_cmd % (managed_save_file, managed_save_file, "0"), flags) elif test_loop_cmd: loop_range = params.get("loop_range", "20") vm_managedsave_loop(vm_name, loop_range, libvirtd) else: vm_recover_check(option, libvirtd, check_shutdown) finally: # Restore test environment. # Restart libvirtd.service qemu_config.restore() libvirt_guests_config.restore() libvirtd.restart() if autostart_bypass_cache: virsh.autostart(vm_name, "--disable", ignore_status=True, debug=True) vm.destroy(gracefully=False) virsh.managedsave_remove(vm_name, debug=True) vmxml_backup.sync() if multi_guests: for i in range(int(multi_guests)): virsh.remove_domain("%s_%s" % (vm_name, i), "--remove-all-storage", debug=True)
def run(test, params, env): """ Test command: virsh managedsave. This command can save and destroy a running domain, so it can be restarted from the same state at a later time. """ vm_name = params.get("main_vm") vm = env.get_vm(vm_name) managed_save_file = "/var/lib/libvirt/qemu/save/%s.save" % vm_name # define function def vm_recover_check(option, libvirtd, check_shutdown=False): """ Check if the vm can be recovered correctly. :param guest_name : Checked vm's name. :param option : managedsave command option. """ # This time vm not be shut down if vm.is_alive(): test.fail("Guest should be inactive") # Check vm managed save state. ret = virsh.dom_list("--managed-save --inactive", debug=True) vm_state1 = re.findall(r".*%s.*" % vm_name, ret.stdout.strip())[0].split()[2] ret = virsh.dom_list("--managed-save --all", debug=True) vm_state2 = re.findall(r".*%s.*" % vm_name, ret.stdout.strip())[0].split()[2] if vm_state1 != "saved" or vm_state2 != "saved": test.fail("Guest state should be saved") virsh.start(vm_name, debug=True) # This time vm should be in the list if vm.is_dead(): test.fail("Guest should be active") # Restart libvirtd and check vm status again. libvirtd.restart() if vm.is_dead(): test.fail("Guest should be active after" " restarting libvirtd") # Check managed save file: if os.path.exists(managed_save_file): test.fail("Managed save image exist " "after starting the domain") if option: if option.count("running"): if vm.is_dead() or vm.is_paused(): test.fail("Guest state should be" " running after started" " because of '--running' option") elif option.count("paused"): if not vm.is_paused(): test.fail("Guest state should be" " paused after started" " because of '--paused' option") else: if params.get("paused_after_start_vm") == "yes": if not vm.is_paused(): test.fail("Guest state should be" " paused after started" " because of initia guest state") if check_shutdown: # Resume the domain. if vm.is_paused(): vm.resume() vm.wait_for_login() # Shutdown and start the domain, # it should be in runing state and can be login. vm.shutdown() vm.wait_for_shutdown() vm.start() vm.wait_for_login() def vm_undefine_check(vm_name): """ Check if vm can be undefined with manage-save option """ #backup xml file xml_backup = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) if not os.path.exists(managed_save_file): test.fail("Can't find managed save image") #undefine domain with no options. if not virsh.undefine(vm_name, options=None, ignore_status=True).exit_status: test.fail("Guest shouldn't be undefined" "while domain managed save image exists") #undefine domain with managed-save option. if virsh.undefine(vm_name, options="--managed-save", ignore_status=True).exit_status: test.fail("Guest can't be undefine with " "managed-save option") if os.path.exists(managed_save_file): test.fail("Managed save image exists" " after undefining vm") #restore and start the vm. xml_backup.define() vm.start() def check_flags_parallel(virsh_cmd, bash_cmd, flags): """ Run the commands parallel and check the output. """ cmd = ("%s & %s" % (virsh_cmd, bash_cmd)) ret = process.run(cmd, ignore_status=True, shell=True, ignore_bg_processes=True) output = ret.stdout_text.strip() logging.debug("check flags output: %s" % output) lines = re.findall(r"flags:.(\d+)", output, re.M) logging.debug("Find all fdinfo flags: %s" % lines) lines = [int(i, 8) & flags for i in lines] if flags not in lines: test.fail("Checking flags %s failed" % flags) return ret def check_multi_guests(guests, start_delay, libvirt_guests): """ Check start_delay option for multiple guests. """ # Destroy vm first if vm.is_alive(): vm.destroy(gracefully=False) # Clone given number of guests timeout = params.get("clone_timeout", 360) for i in range(int(guests)): dst_vm = "%s_%s" % (vm_name, i) utils_libguestfs.virt_clone_cmd(vm_name, dst_vm, True, timeout=timeout) virsh.start(dst_vm, debug=True) # Wait 10 seconds for vm to start time.sleep(10) is_systemd = process.run("cat /proc/1/comm", shell=True).stdout_text.count("systemd") if is_systemd: libvirt_guests.restart() pattern = r'(.+ \d\d:\d\d:\d\d).+: Resuming guest.+done' else: ret = process.run("service libvirt-guests restart | \ awk '{ print strftime(\"%b %y %H:%M:%S\"), \ $0; fflush(); }'", shell=True) pattern = r'(.+ \d\d:\d\d:\d\d)+ Resuming guest.+done' # libvirt-guests status command read messages from systemd # journal, in cases of messages are not ready in time, # add a time wait here. def wait_func(): return libvirt_guests.raw_status().stdout.count("Resuming guest") utils_misc.wait_for(wait_func, 5) if is_systemd: ret = libvirt_guests.raw_status() logging.info("status output: %s", ret.stdout_text) resume_time = re.findall(pattern, ret.stdout_text, re.M) if not resume_time: test.fail("Can't see messages of resuming guest") # Convert time string to int resume_seconds = [time.mktime(time.strptime( tm, "%b %y %H:%M:%S")) for tm in resume_time] logging.info("Resume time in seconds: %s", resume_seconds) # Check if start_delay take effect for i in range(len(resume_seconds)-1): if resume_seconds[i+1] - resume_seconds[i] < int(start_delay): test.fail("Checking start_delay failed") def wait_for_state(vm_state): """ Wait for vm state is ready. """ utils_misc.wait_for(lambda: vm.state() == vm_state, 10) def check_guest_flags(bash_cmd, flags): """ Check bypass_cache option for single guest. """ # Drop caches. drop_caches() # form proper parallel command based on if systemd is used or not is_systemd = process.run("cat /proc/1/comm", shell=True).stdout_text.count("systemd") if is_systemd: virsh_cmd_stop = "systemctl stop libvirt-guests" virsh_cmd_start = "systemctl start libvirt-guests" else: virsh_cmd_stop = "service libvirt-guests stop" virsh_cmd_start = "service libvirt-guests start" ret = check_flags_parallel(virsh_cmd_stop, bash_cmd % (managed_save_file, managed_save_file, "1"), flags) if is_systemd: ret = libvirt_guests.raw_status() logging.info("status output: %s", ret.stdout_text) if all(["Suspending %s" % vm_name not in ret.stdout_text, "stopped, with saved guests" not in ret.stdout_text]): test.fail("Can't see messages of suspending vm") # status command should return 3. if not is_systemd: ret = libvirt_guests.raw_status() if ret.exit_status != 3: test.fail("The exit code %s for libvirt-guests" " status is not correct" % ret) # Wait for VM in shut off state wait_for_state("shut off") check_flags_parallel(virsh_cmd_start, bash_cmd % (managed_save_file, managed_save_file, "0"), flags) # Wait for VM in running state wait_for_state("running") def vm_msave_remove_check(vm_name): """ Check managed save remove command. """ if not os.path.exists(managed_save_file): test.fail("Can't find managed save image") virsh.managedsave_remove(vm_name, debug=True) if os.path.exists(managed_save_file): test.fail("Managed save image still exists") virsh.start(vm_name, debug=True) # The domain state should be running if vm.state() != "running": test.fail("Guest state should be" " running after started") def vm_managedsave_loop(vm_name, loop_range, libvirtd): """ Run a loop of managedsave command and check its result. """ if vm.is_dead(): virsh.start(vm_name, debug=True) for i in range(int(loop_range)): logging.debug("Test loop: %s" % i) virsh.managedsave(vm_name, debug=True) virsh.start(vm_name, debug=True) # Check libvirtd status. if not libvirtd.is_running(): test.fail("libvirtd is stopped after cmd") # Check vm status. if vm.state() != "running": test.fail("Guest isn't in running state") def build_vm_xml(vm_name, **dargs): """ Build the new domain xml and define it. """ try: # stop vm before doing any change to xml if vm.is_alive(): vm.destroy(gracefully=False) vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) if dargs.get("cpu_mode"): if "cpu" in vmxml: del vmxml.cpu cpuxml = vm_xml.VMCPUXML() cpuxml.mode = params.get("cpu_mode", "host-model") cpuxml.match = params.get("cpu_match", "exact") cpuxml.fallback = params.get("cpu_fallback", "forbid") cpu_topology = {} cpu_topology_sockets = params.get("cpu_topology_sockets") if cpu_topology_sockets: cpu_topology["sockets"] = cpu_topology_sockets cpu_topology_cores = params.get("cpu_topology_cores") if cpu_topology_cores: cpu_topology["cores"] = cpu_topology_cores cpu_topology_threads = params.get("cpu_topology_threads") if cpu_topology_threads: cpu_topology["threads"] = cpu_topology_threads if cpu_topology: cpuxml.topology = cpu_topology vmxml.cpu = cpuxml vmxml.vcpu = int(params.get("vcpu_nums")) if dargs.get("sec_driver"): seclabel_dict = {"type": "dynamic", "model": "selinux", "relabel": "yes"} vmxml.set_seclabel([seclabel_dict]) vmxml.sync() vm.start() except Exception as e: logging.error(str(e)) test.cancel("Build domain xml failed") status_error = ("yes" == params.get("status_error", "no")) vm_ref = params.get("managedsave_vm_ref", "name") libvirtd_state = params.get("libvirtd", "on") extra_param = params.get("managedsave_extra_param", "") progress = ("yes" == params.get("managedsave_progress", "no")) cpu_mode = "yes" == params.get("managedsave_cpumode", "no") test_undefine = "yes" == params.get("managedsave_undefine", "no") test_bypass_cache = "yes" == params.get("test_bypass_cache", "no") autostart_bypass_cache = params.get("autostart_bypass_cache", "") multi_guests = params.get("multi_guests", "") test_libvirt_guests = params.get("test_libvirt_guests", "") check_flags = "yes" == params.get("check_flags", "no") security_driver = params.get("security_driver", "") remove_after_cmd = "yes" == params.get("remove_after_cmd", "no") option = params.get("managedsave_option", "") check_shutdown = "yes" == params.get("shutdown_after_cmd", "no") pre_vm_state = params.get("pre_vm_state", "") move_saved_file = "yes" == params.get("move_saved_file", "no") test_loop_cmd = "yes" == params.get("test_loop_cmd", "no") if option: if not virsh.has_command_help_match('managedsave', option): # Older libvirt does not have this option test.cancel("Older libvirt does not" " handle arguments consistently") # Backup xml file. vmxml_backup = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) # Get the libvirtd service libvirtd = utils_libvirtd.Libvirtd() # Get config files. qemu_config = utils_config.LibvirtQemuConfig() libvirt_guests_config = utils_config.LibvirtGuestsConfig() # Get libvirt-guests service libvirt_guests = Factory.create_service("libvirt-guests") try: # Destroy vm first for setting configuration file if vm.state() == "running": vm.destroy(gracefully=False) # Prepare test environment. if libvirtd_state == "off": libvirtd.stop() if autostart_bypass_cache: ret = virsh.autostart(vm_name, "", ignore_status=True, debug=True) libvirt.check_exit_status(ret) qemu_config.auto_start_bypass_cache = autostart_bypass_cache libvirtd.restart() if security_driver: qemu_config.security_driver = [security_driver] if test_libvirt_guests: if multi_guests: start_delay = params.get("start_delay", "20") libvirt_guests_config.START_DELAY = start_delay if check_flags: libvirt_guests_config.BYPASS_CACHE = "1" # The config file format should be "x=y" instead of "x = y" process.run("sed -i -e 's/ = /=/g' " "/etc/sysconfig/libvirt-guests", shell=True) libvirt_guests.restart() # Change domain xml. if cpu_mode: build_vm_xml(vm_name, cpu_mode=True) if security_driver: build_vm_xml(vm_name, sec_driver=True) # Turn VM into certain state. if pre_vm_state == "transient": logging.info("Creating %s..." % vm_name) vmxml_for_test = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) if vm.is_alive(): vm.destroy(gracefully=False) # Wait for VM to be in shut off state utils_misc.wait_for(lambda: vm.state() == "shut off", 10) vm.undefine() if virsh.create(vmxml_for_test.xml, ignore_status=True, debug=True).exit_status: vmxml_backup.define() test.cancel("Cann't create the domain") # Wait for vm in stable state if params.get("start_vm") == "yes": if vm.state() == "shut off": vm.start() vm.wait_for_login() # run test case domid = vm.get_id() domuuid = vm.get_uuid() if vm_ref == "id": vm_ref = domid elif vm_ref == "uuid": vm_ref = domuuid elif vm_ref == "hex_id": vm_ref = hex(int(domid)) elif vm_ref.count("invalid"): vm_ref = params.get(vm_ref) elif vm_ref == "name": vm_ref = vm_name # Ignore exception with "ignore_status=True" if progress: option += " --verbose" option += extra_param # For bypass_cache test. Run a shell command to check fd flags while # excuting managedsave command software_mgr = software_manager.SoftwareManager() if not software_mgr.check_installed('lsof'): logging.info('Installing lsof package:') software_mgr.install('lsof') bash_cmd = ("let i=1; while((i++<400)); do if [ -e %s ]; then (cat /proc" "/$(lsof -w %s|awk '/libvirt_i/{print $2}')/fdinfo/*%s* |" "grep 'flags:.*') && break; else sleep 0.05; fi; done;") # Flags to check bypass cache take effect flags = os.O_DIRECT if test_bypass_cache: # Drop caches. drop_caches() virsh_cmd = "virsh managedsave %s %s" % (option, vm_name) check_flags_parallel(virsh_cmd, bash_cmd % (managed_save_file, managed_save_file, "1"), flags) # Wait for VM in shut off state wait_for_state("shut off") virsh_cmd = "virsh start %s %s" % (option, vm_name) check_flags_parallel(virsh_cmd, bash_cmd % (managed_save_file, managed_save_file, "0"), flags) # Wait for VM in running state wait_for_state("running") elif test_libvirt_guests: logging.debug("libvirt-guests status: %s", libvirt_guests.status()) if multi_guests: check_multi_guests(multi_guests, start_delay, libvirt_guests) if check_flags: check_guest_flags(bash_cmd, flags) else: # Ensure VM is running utils_misc.wait_for(lambda: vm.state() == "running", 10) ret = virsh.managedsave(vm_ref, options=option, ignore_status=True, debug=True) status = ret.exit_status # The progress information outputed in error message error_msg = ret.stderr.strip() if move_saved_file: cmd = "echo > %s" % managed_save_file process.run(cmd, shell=True) # recover libvirtd service start if libvirtd_state == "off": libvirtd.start() if status_error: if not status: test.fail("Run successfully with wrong command!") else: if status: test.fail("Run failed with right command") if progress: if not error_msg.count("Managedsave:"): test.fail("Got invalid progress output") if remove_after_cmd: vm_msave_remove_check(vm_name) elif test_undefine: vm_undefine_check(vm_name) elif autostart_bypass_cache: libvirtd.stop() virsh_cmd = ("(service libvirtd start)") check_flags_parallel(virsh_cmd, bash_cmd % (managed_save_file, managed_save_file, "0"), flags) elif test_loop_cmd: loop_range = params.get("loop_range", "20") vm_managedsave_loop(vm_name, loop_range, libvirtd) else: vm_recover_check(option, libvirtd, check_shutdown) finally: # Restore test environment. # Restart libvirtd.service qemu_config.restore() libvirt_guests_config.restore() libvirtd.restart() if autostart_bypass_cache: virsh.autostart(vm_name, "--disable", ignore_status=True, debug=True) vm.destroy(gracefully=False) virsh.managedsave_remove(vm_name, debug=True) vmxml_backup.sync() if multi_guests: for i in range(int(multi_guests)): virsh.remove_domain("%s_%s" % (vm_name, i), "--remove-all-storage", debug=True)
def run(test, params, env): """ LXC container life cycle testing by virsh command """ uri = params.get("connect_uri", "lxc:///") vm_name = params.get("main_vm") dom_type = params.get("lxc_domtype", "lxc") vcpu = int(params.get("lxc_vcpu", 1)) max_mem = int(params.get("lxc_max_mem", 500000)) current_mem = int(params.get("lxc_current_mem", 500000)) os_type = params.get("lxc_ostype", "exe") os_arch = params.get("lxc_osarch", "x86_64") os_init = params.get("lxc_osinit", "/bin/sh") emulator_path = params.get("lxc_emulator", "/usr/libexec/libvirt_lxc") interface_type = params.get("lxc_interface_type", "network") net_name = params.get("lxc_net_name", "default") full_os = ("yes" == params.get("lxc_full_os", "no")) install_root = params.get("lxc_install_root", "/") fs_target = params.get("lxc_fs_target", "/") fs_accessmode = params.get("lxc_fs_accessmode", "passthrough") passwd = params.get("lxc_fs_passwd", "redhat") def generate_container_xml(): """ Generate container xml """ vmxml = vm_xml.VMXML(dom_type) vmxml.vm_name = vm_name vmxml.max_mem = max_mem vmxml.current_mem = current_mem vmxml.vcpu = vcpu # Generate os vm_os = vm_xml.VMOSXML() vm_os.type = os_type vm_os.arch = os_arch vm_os.init = os_init vmxml.os = vm_os # Generate emulator emulator = Emulator() emulator.path = emulator_path # Generate console console = Console() filesystem = Filesystem() filesystem.accessmode = fs_accessmode filesystem.source = {'dir': install_root} filesystem.target = {'dir': fs_target} # Add emulator and console in devices devices = vm_xml.VMXMLDevices() devices.append(emulator) devices.append(console) devices.append(filesystem) # Add network device network = Interface(type_name=interface_type) network.mac_address = utils_net.generate_mac_address_simple() network.source = {interface_type: net_name} devices.append(network) vmxml.set_devices(devices) return vmxml def check_state(expected_state): result = virsh.domstate(vm_name, uri=uri) utlv.check_exit_status(result) vm_state = result.stdout.strip() if vm_state == expected_state: logging.info("Get expected state: %s", vm_state) else: raise TestFail("Get unexpected state: %s", vm_state) virsh_args = {'uri': uri, 'debug': True} try: vmxml = generate_container_xml() with open(vmxml.xml, 'r') as f: logging.info("Container XML:\n%s", f.read()) if full_os: if not os.path.exists(install_root): os.mkdir(install_root) # Install core os under installroot cmd = "yum --releasever=/ --installroot=%s" % install_root cmd += " --nogpgcheck -y groupinstall core" process.run(cmd, shell=True) # Fix root login on console process.run("echo 'pts/0' >> %s/etc/securetty" % install_root, shell=True) for i in ["session required pam_selinux.so close", "session required pam_selinux.so open", "session required pam_loginuid.so"]: process.run('sed -i s/"%s\"/"#%s"/g %s/etc/pam.d/login' % (i, i, install_root), shell=True) # Fix root login for sshd process.run('sed -i s/"%s\"/"#%s"/g %s/etc/pam.d/sshd' % (i, i, install_root), shell=True) # Config basic network net_file = install_root + '/etc/sysconfig/network' with open(net_file, 'w') as f: f.write('NETWORKING=yes\nHOSTNAME=%s\n' % vm_name) net_script = install_root + '/etc/sysconfig/network-scripts/ifcfg-eth0' with open(net_script, 'w') as f: f.write('DEVICE=eth0\nBOOTPROTO=dhcp\nONBOOT=yes\n') # Set root password and enable sshd session = aexpect.ShellSession("chroot %s" % install_root) session.sendline('echo %s|passwd root --stdin' % passwd) session.sendline('chkconfig sshd on') session.close() # Create result = virsh.create(vmxml.xml, **virsh_args) utlv.check_exit_status(result) check_state('running') # Destroy result = virsh.destroy(vm_name, **virsh_args) utlv.check_exit_status(result) if not virsh.domain_exists(vm_name, **virsh_args): logging.info("Destroy transient LXC domain successfully") else: raise TestFail("Transient LXC domain still exist after destroy") # Define result = virsh.define(vmxml.xml, **virsh_args) utlv.check_exit_status(result) check_state('shut off') # List result = virsh.dom_list('--inactive', **virsh_args) utlv.check_exit_status(result) if re.findall("(%s)\s+shut off" % vm_name, result.stdout): logging.info("Find %s in virsh list output", vm_name) else: raise TestFail("Not find %s in virsh list output") # Dumpxml result = virsh.dumpxml(vm_name, uri=uri, debug=False) utlv.check_exit_status(result) # Edit edit_vcpu = '2' logging.info("Change vcpu of LXC container to %s", edit_vcpu) edit_cmd = [r":%s /[0-9]*<\/vcpu>/" + edit_vcpu + r"<\/vcpu>"] if not utlv.exec_virsh_edit(vm_name, edit_cmd, connect_uri=uri): raise TestFail("Run edit command fail") else: result = virsh.dumpxml(vm_name, **virsh_args) new_vcpu = re.search(r'(\d*)</vcpu>', result.stdout).group(1) if new_vcpu == edit_vcpu: logging.info("vcpu number is expected after do edit") else: raise TestFail("vcpu number is unexpected after do edit") # Start result = virsh.start(vm_name, **virsh_args) utlv.check_exit_status(result) check_state('running') # Suspend result = virsh.suspend(vm_name, **virsh_args) utlv.check_exit_status(result) check_state('paused') # Resume result = virsh.resume(vm_name, **virsh_args) utlv.check_exit_status(result) check_state('running') # Reboot(not supported on RHEL6) result = virsh.reboot(vm_name, **virsh_args) supported_err = 'not supported by the connection driver: virDomainReboot' if supported_err in result.stderr.strip(): logging.info("Reboot is not supported") else: utlv.check_exit_status(result) # Destroy result = virsh.destroy(vm_name, **virsh_args) utlv.check_exit_status(result) check_state('shut off') # Undefine result = virsh.undefine(vm_name, **virsh_args) utlv.check_exit_status(result) if not virsh.domain_exists(vm_name, **virsh_args): logging.info("Undefine LXC domain successfully") else: raise TestFail("LXC domain still exist after undefine") finally: virsh.remove_domain(vm_name, **virsh_args) if full_os and os.path.exists(install_root): shutil.rmtree(install_root)
def run(test, params, env): """ Test rbd disk device. 1.Prepare test environment,destroy or suspend a VM. 2.Prepare disk image. 3.Edit disks xml and start the domain. 4.Perform test operation. 5.Recover test environment. """ vm_name = params.get("main_vm") vm = env.get_vm(vm_name) virsh_dargs = {'debug': True, 'ignore_status': True} additional_xml_file = os.path.join(data_dir.get_tmp_dir(), "additional_disk.xml") def config_ceph(): """ Write the configs to the file. """ src_host = disk_src_host.split() src_port = disk_src_port.split() conf_str = "mon_host = " hosts = [] for host, port in zip(src_host, src_port): hosts.append("%s:%s" % (host, port)) with open(disk_src_config, 'w') as f: f.write(conf_str + ','.join(hosts) + '\n') def create_pool(): """ Define and start a pool. """ sp = libvirt_storage.StoragePool() if create_by_xml: p_xml = pool_xml.PoolXML(pool_type=pool_type) p_xml.name = pool_name s_xml = pool_xml.SourceXML() s_xml.vg_name = disk_src_pool source_host = [] for (host_name, host_port) in zip( disk_src_host.split(), disk_src_port.split()): source_host.append({'name': host_name, 'port': host_port}) s_xml.hosts = source_host if auth_type: s_xml.auth_type = auth_type if auth_user: s_xml.auth_username = auth_user if auth_usage: s_xml.secret_usage = auth_usage p_xml.source = s_xml logging.debug("Pool xml: %s", p_xml) p_xml.xmltreefile.write() ret = virsh.pool_define(p_xml.xml, **virsh_dargs) libvirt.check_exit_status(ret) ret = virsh.pool_build(pool_name, **virsh_dargs) libvirt.check_exit_status(ret) ret = virsh.pool_start(pool_name, **virsh_dargs) libvirt.check_exit_status(ret) else: auth_opt = "" if client_name and client_key: auth_opt = ("--auth-type %s --auth-username %s --secret-usage '%s'" % (auth_type, auth_user, auth_usage)) if not sp.define_rbd_pool(pool_name, mon_host, disk_src_pool, extra=auth_opt): test.fail("Failed to define storage pool") if not sp.build_pool(pool_name): test.fail("Failed to build storage pool") if not sp.start_pool(pool_name): test.fail("Failed to start storage pool") # Check pool operation ret = virsh.pool_refresh(pool_name, **virsh_dargs) libvirt.check_exit_status(ret) ret = virsh.pool_uuid(pool_name, **virsh_dargs) libvirt.check_exit_status(ret) # pool-info pool_info = sp.pool_info(pool_name) if pool_info["Autostart"] != 'no': test.fail("Failed to check pool information") # pool-autostart if not sp.set_pool_autostart(pool_name): test.fail("Failed to set pool autostart") pool_info = sp.pool_info(pool_name) if pool_info["Autostart"] != 'yes': test.fail("Failed to check pool information") # pool-autostart --disable if not sp.set_pool_autostart(pool_name, "--disable"): test.fail("Failed to set pool autostart") # If port is not pre-configured, port value should not be hardcoded in pool information. if "yes" == params.get("rbd_port", "no"): if 'port' in virsh.pool_dumpxml(pool_name): test.fail("port attribute should not be in pool information") # find-storage-pool-sources-as if "yes" == params.get("find_storage_pool_sources_as", "no"): ret = virsh.find_storage_pool_sources_as("rbd", mon_host) libvirt.check_result(ret, skip_if=unsupported_err) def create_vol(vol_params): """ Create volume. :param p_name. Pool name. :param vol_params. Volume parameters dict. :return: True if create successfully. """ pvt = libvirt.PoolVolumeTest(test, params) if create_by_xml: pvt.pre_vol_by_xml(pool_name, **vol_params) else: pvt.pre_vol(vol_name, None, '2G', None, pool_name) def check_vol(vol_params): """ Check volume information. """ pv = libvirt_storage.PoolVolume(pool_name) # Supported operation if vol_name not in pv.list_volumes(): test.fail("Volume %s doesn't exist" % vol_name) ret = virsh.vol_dumpxml(vol_name, pool_name) libvirt.check_exit_status(ret) # vol-info if not pv.volume_info(vol_name): test.fail("Can't see volume info") # vol-key ret = virsh.vol_key(vol_name, pool_name) libvirt.check_exit_status(ret) if "%s/%s" % (disk_src_pool, vol_name) not in ret.stdout.strip(): test.fail("Volume key isn't correct") # vol-path ret = virsh.vol_path(vol_name, pool_name) libvirt.check_exit_status(ret) if "%s/%s" % (disk_src_pool, vol_name) not in ret.stdout.strip(): test.fail("Volume path isn't correct") # vol-pool ret = virsh.vol_pool("%s/%s" % (disk_src_pool, vol_name)) libvirt.check_exit_status(ret) if pool_name not in ret.stdout.strip(): test.fail("Volume pool isn't correct") # vol-name ret = virsh.vol_name("%s/%s" % (disk_src_pool, vol_name)) libvirt.check_exit_status(ret) if vol_name not in ret.stdout.strip(): test.fail("Volume name isn't correct") # vol-resize ret = virsh.vol_resize(vol_name, "2G", pool_name) libvirt.check_exit_status(ret) # Not supported operation # vol-clone ret = virsh.vol_clone(vol_name, cloned_vol_name, pool_name) libvirt.check_result(ret, skip_if=unsupported_err) # vol-create-from volxml = vol_xml.VolXML() vol_params.update({"name": "%s" % create_from_cloned_volume}) v_xml = volxml.new_vol(**vol_params) v_xml.xmltreefile.write() ret = virsh.vol_create_from(pool_name, v_xml.xml, vol_name, pool_name) libvirt.check_result(ret, skip_if=unsupported_err) # vol-wipe ret = virsh.vol_wipe(vol_name, pool_name) libvirt.check_result(ret, skip_if=unsupported_err) # vol-upload ret = virsh.vol_upload(vol_name, vm.get_first_disk_devices()['source'], "--pool %s" % pool_name) libvirt.check_result(ret, skip_if=unsupported_err) # vol-download ret = virsh.vol_download(vol_name, cloned_vol_name, "--pool %s" % pool_name) libvirt.check_result(ret, skip_if=unsupported_err) def check_qemu_cmd(): """ Check qemu command line options. """ cmd = ("ps -ef | grep %s | grep -v grep " % vm_name) process.run(cmd, shell=True) if disk_src_name: cmd += " | grep file=rbd:%s:" % disk_src_name if auth_user and auth_key: cmd += ('id=%s:auth_supported=cephx' % auth_user) if disk_src_config: cmd += " | grep 'conf=%s'" % disk_src_config elif mon_host: hosts = '\:6789\;'.join(mon_host.split()) cmd += " | grep 'mon_host=%s'" % hosts if driver_iothread: cmd += " | grep iothread%s" % driver_iothread # Run the command process.run(cmd, shell=True) def check_save_restore(): """ Test save and restore operation """ save_file = os.path.join(data_dir.get_tmp_dir(), "%s.save" % vm_name) ret = virsh.save(vm_name, save_file, **virsh_dargs) libvirt.check_exit_status(ret) ret = virsh.restore(save_file, **virsh_dargs) libvirt.check_exit_status(ret) if os.path.exists(save_file): os.remove(save_file) # Login to check vm status vm.wait_for_login().close() def check_snapshot(snap_option, target_dev='vda'): """ Test snapshot operation. """ snap_name = "s1" snap_mem = os.path.join(data_dir.get_tmp_dir(), "rbd.mem") snap_disk = os.path.join(data_dir.get_tmp_dir(), "rbd.disk") xml_snap_exp = ["disk name='%s' snapshot='external' type='file'" % target_dev] xml_dom_exp = ["source file='%s'" % snap_disk, "backingStore type='network' index='1'", "source protocol='rbd' name='%s'" % disk_src_name] if snap_option.count("disk-only"): options = ("%s --diskspec %s,file=%s --disk-only" % (snap_name, target_dev, snap_disk)) elif snap_option.count("disk-mem"): options = ("%s --memspec file=%s --diskspec %s,file=" "%s" % (snap_name, snap_mem, target_dev, snap_disk)) xml_snap_exp.append("memory snapshot='external' file='%s'" % snap_mem) else: options = snap_name ret = virsh.snapshot_create_as(vm_name, options) if test_disk_internal_snapshot or test_disk_readonly: libvirt.check_result(ret, expected_fails=unsupported_err) else: libvirt.check_result(ret, skip_if=unsupported_err) # check xml file. if not ret.exit_status: snap_xml = virsh.snapshot_dumpxml(vm_name, snap_name, debug=True).stdout.strip() dom_xml = virsh.dumpxml(vm_name, debug=True).stdout.strip() # Delete snapshots. libvirt.clean_up_snapshots(vm_name) if os.path.exists(snap_mem): os.remove(snap_mem) if os.path.exists(snap_disk): os.remove(snap_disk) if not all([x in snap_xml for x in xml_snap_exp]): test.fail("Failed to check snapshot xml") if not all([x in dom_xml for x in xml_dom_exp]): test.fail("Failed to check domain xml") def check_blockcopy(target): """ Block copy operation test. """ blk_file = os.path.join(data_dir.get_tmp_dir(), "blk.rbd") if os.path.exists(blk_file): os.remove(blk_file) blk_mirror = ("mirror type='file' file='%s' " "format='raw' job='copy'" % blk_file) # Do blockcopy ret = virsh.blockcopy(vm_name, target, blk_file) libvirt.check_result(ret, skip_if=unsupported_err) dom_xml = virsh.dumpxml(vm_name, debug=True).stdout.strip() if not dom_xml.count(blk_mirror): test.fail("Can't see block job in domain xml") # Abort ret = virsh.blockjob(vm_name, target, "--abort") libvirt.check_exit_status(ret) dom_xml = virsh.dumpxml(vm_name, debug=True).stdout.strip() if dom_xml.count(blk_mirror): test.fail("Failed to abort block job") if os.path.exists(blk_file): os.remove(blk_file) # Sleep for a while after abort operation. time.sleep(5) # Do blockcopy again ret = virsh.blockcopy(vm_name, target, blk_file) libvirt.check_exit_status(ret) # Wait for complete def wait_func(): ret = virsh.blockjob(vm_name, target, "--info") return ret.stderr.count("Block Copy: [100 %]") timeout = params.get("blockjob_timeout", 600) utils_misc.wait_for(wait_func, int(timeout)) # Pivot ret = virsh.blockjob(vm_name, target, "--pivot") libvirt.check_exit_status(ret) dom_xml = virsh.dumpxml(vm_name, debug=True).stdout.strip() if not dom_xml.count("source file='%s'" % blk_file): test.fail("Failed to pivot block job") # Remove the disk file. if os.path.exists(blk_file): os.remove(blk_file) def check_in_vm(vm_obj, target, old_parts, read_only=False): """ Check mount/read/write disk in VM. :param vm. VM guest. :param target. Disk dev in VM. :return: True if check successfully. """ try: session = vm_obj.wait_for_login() new_parts = libvirt.get_parts_list(session) added_parts = list(set(new_parts).difference(set(old_parts))) logging.info("Added parts:%s", added_parts) if len(added_parts) != 1: logging.error("The number of new partitions is invalid in VM") return False added_part = None if target.startswith("vd"): if added_parts[0].startswith("vd"): added_part = added_parts[0] elif target.startswith("hd"): if added_parts[0].startswith("sd"): added_part = added_parts[0] if not added_part: logging.error("Can't see added partition in VM") return False cmd = ("mount /dev/{0} /mnt && ls /mnt && (sleep 15;" " touch /mnt/testfile; umount /mnt)" .format(added_part)) s, o = session.cmd_status_output(cmd, timeout=60) session.close() logging.info("Check disk operation in VM:\n, %s, %s", s, o) # Readonly fs, check the error messages. # The command may return True, read-only # messges can be found from the command output if read_only: if "Read-only file system" not in o: return False else: return True # Other errors if s != 0: return False return True except (remote.LoginError, virt_vm.VMError, aexpect.ShellError) as e: logging.error(str(e)) return False def clean_up_volume_snapshots(): """ Get all snapshots for rbd_vol.img volume,unprotect and then clean up them. """ cmd = ("rbd -m {0} {1} info {2}" "".format(mon_host, key_opt, os.path.join(disk_src_pool, vol_name))) if process.run(cmd, ignore_status=True, shell=True).exit_status: return # Get snapshot list. cmd = ("rbd -m {0} {1} snap" " list {2}" "".format(mon_host, key_opt, os.path.join(disk_src_pool, vol_name))) snaps_out = process.run(cmd, ignore_status=True, shell=True).stdout_text snap_names = [] if snaps_out: for line in snaps_out.rsplit("\n"): if line.startswith("SNAPID") or line == "": continue snap_line = line.rsplit() if len(snap_line) == 4: snap_names.append(snap_line[1]) logging.debug("Find snapshots: %s", snap_names) # Unprotect snapshot first,otherwise it will fail to purge volume for snap_name in snap_names: cmd = ("rbd -m {0} {1} snap" " unprotect {2}@{3}" "".format(mon_host, key_opt, os.path.join(disk_src_pool, vol_name), snap_name)) process.run(cmd, ignore_status=True, shell=True) # Purge volume,and then delete volume. cmd = ("rbd -m {0} {1} info {2} && rbd -m {0} {1} snap" " purge {2} && rbd -m {0} {1} rm {2}" "".format(mon_host, key_opt, os.path.join(disk_src_pool, vol_name))) process.run(cmd, ignore_status=True, shell=True) def make_snapshot(): """ make external snapshots. :return external snapshot path list """ logging.info("Making snapshot...") first_disk_source = vm.get_first_disk_devices()['source'] snapshot_path_list = [] snapshot2_file = os.path.join(data_dir.get_tmp_dir(), "mem.s2") snapshot3_file = os.path.join(data_dir.get_tmp_dir(), "mem.s3") snapshot4_file = os.path.join(data_dir.get_tmp_dir(), "mem.s4") snapshot4_disk_file = os.path.join(data_dir.get_tmp_dir(), "disk.s4") snapshot5_file = os.path.join(data_dir.get_tmp_dir(), "mem.s5") snapshot5_disk_file = os.path.join(data_dir.get_tmp_dir(), "disk.s5") # Attempt to take different types of snapshots. snapshots_param_dict = {"s1": "s1 --disk-only --no-metadata", "s2": "s2 --memspec %s --no-metadata" % snapshot2_file, "s3": "s3 --memspec %s --no-metadata --live" % snapshot3_file, "s4": "s4 --memspec %s --diskspec vda,file=%s --no-metadata" % (snapshot4_file, snapshot4_disk_file), "s5": "s5 --memspec %s --diskspec vda,file=%s --live --no-metadata" % (snapshot5_file, snapshot5_disk_file)} for snapshot_name in sorted(snapshots_param_dict.keys()): ret = virsh.snapshot_create_as(vm_name, snapshots_param_dict[snapshot_name], **virsh_dargs) libvirt.check_exit_status(ret) if snapshot_name != 's4' and snapshot_name != 's5': snapshot_path_list.append(first_disk_source.replace('qcow2', snapshot_name)) return snapshot_path_list def get_secret_list(): """ Get secret list. :return secret list """ logging.info("Get secret list ...") secret_list_result = virsh.secret_list() secret_list = results_stdout_52lts(secret_list_result).strip().splitlines() # First two lines contain table header followed by entries # for each secret, such as: # # UUID Usage # -------------------------------------------------------------------------------- # b4e8f6d3-100c-4e71-9f91-069f89742273 ceph client.libvirt secret secret_list = secret_list[2:] result = [] # If secret list is empty. if secret_list: for line in secret_list: # Split on whitespace, assume 1 column linesplit = line.split(None, 1) result.append(linesplit[0]) return result mon_host = params.get("mon_host") disk_src_name = params.get("disk_source_name") disk_src_config = params.get("disk_source_config") disk_src_host = params.get("disk_source_host") disk_src_port = params.get("disk_source_port") disk_src_pool = params.get("disk_source_pool") disk_format = params.get("disk_format", "raw") driver_iothread = params.get("driver_iothread") snap_name = params.get("disk_snap_name") attach_device = "yes" == params.get("attach_device", "no") attach_disk = "yes" == params.get("attach_disk", "no") test_save_restore = "yes" == params.get("test_save_restore", "no") test_snapshot = "yes" == params.get("test_snapshot", "no") test_blockcopy = "yes" == params.get("test_blockcopy", "no") test_qemu_cmd = "yes" == params.get("test_qemu_cmd", "no") test_vm_parts = "yes" == params.get("test_vm_parts", "no") additional_guest = "yes" == params.get("additional_guest", "no") create_snapshot = "yes" == params.get("create_snapshot", "no") convert_image = "yes" == params.get("convert_image", "no") create_volume = "yes" == params.get("create_volume", "no") create_by_xml = "yes" == params.get("create_by_xml", "no") client_key = params.get("client_key") client_name = params.get("client_name") auth_key = params.get("auth_key") auth_user = params.get("auth_user") auth_type = params.get("auth_type") auth_usage = params.get("secret_usage") pool_name = params.get("pool_name") pool_type = params.get("pool_type") vol_name = params.get("vol_name") cloned_vol_name = params.get("cloned_volume", "cloned_test_volume") create_from_cloned_volume = params.get("create_from_cloned_volume", "create_from_cloned_test_volume") vol_cap = params.get("vol_cap") vol_cap_unit = params.get("vol_cap_unit") start_vm = "yes" == params.get("start_vm", "no") test_disk_readonly = "yes" == params.get("test_disk_readonly", "no") test_disk_internal_snapshot = "yes" == params.get("test_disk_internal_snapshot", "no") test_json_pseudo_protocol = "yes" == params.get("json_pseudo_protocol", "no") disk_snapshot_with_sanlock = "yes" == params.get("disk_internal_with_sanlock", "no") # Create /etc/ceph/ceph.conf file to suppress false warning error message. process.run("mkdir -p /etc/ceph", ignore_status=True, shell=True) cmd = ("echo 'mon_host = {0}' >/etc/ceph/ceph.conf" .format(mon_host)) process.run(cmd, ignore_status=True, shell=True) # Start vm and get all partions in vm. if vm.is_dead(): vm.start() session = vm.wait_for_login() old_parts = libvirt.get_parts_list(session) session.close() vm.destroy(gracefully=False) if additional_guest: guest_name = "%s_%s" % (vm_name, '1') timeout = params.get("clone_timeout", 360) utils_libguestfs.virt_clone_cmd(vm_name, guest_name, True, timeout=timeout, ignore_status=False) additional_vm = vm.clone(guest_name) if start_vm: virsh.start(guest_name) # Back up xml file. vmxml_backup = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) key_opt = "" secret_uuid = None snapshot_path = None key_file = os.path.join(data_dir.get_tmp_dir(), "ceph.key") img_file = os.path.join(data_dir.get_tmp_dir(), "%s_test.img" % vm_name) front_end_img_file = os.path.join(data_dir.get_tmp_dir(), "%s_frontend_test.img" % vm_name) # Construct a unsupported error message list to skip these kind of tests unsupported_err = [] if driver_iothread: unsupported_err.append('IOThreads not supported') if test_snapshot: unsupported_err.append('live disk snapshot not supported') if test_disk_readonly: if not libvirt_version.version_compare(5, 0, 0): unsupported_err.append('Could not create file: Permission denied') unsupported_err.append('Permission denied') else: unsupported_err.append('unsupported configuration: external snapshot ' + 'for readonly disk vdb is not supported') if test_disk_internal_snapshot: unsupported_err.append('unsupported configuration: internal snapshot for disk ' + 'vdb unsupported for storage type raw') if test_blockcopy: unsupported_err.append('block copy is not supported') if attach_disk: unsupported_err.append('No such file or directory') if create_volume: unsupported_err.append("backing 'volume' disks isn't yet supported") unsupported_err.append('this function is not supported') try: # Clean up dirty secrets in test environments if there have. dirty_secret_list = get_secret_list() if dirty_secret_list: for dirty_secret_uuid in dirty_secret_list: virsh.secret_undefine(dirty_secret_uuid) # Prepare test environment. qemu_config = LibvirtQemuConfig() if disk_snapshot_with_sanlock: # Install necessary package:sanlock,libvirt-lock-sanlock if not utils_package.package_install(["sanlock"]): test.error("fail to install sanlock") if not utils_package.package_install(["libvirt-lock-sanlock"]): test.error("fail to install libvirt-lock-sanlock") # Set virt_use_sanlock result = process.run("setsebool -P virt_use_sanlock 1", shell=True) if result.exit_status: test.error("Failed to set virt_use_sanlock value") # Update lock_manager in qemu.conf qemu_config.lock_manager = 'sanlock' # Update qemu-sanlock.conf. san_lock_config = LibvirtSanLockConfig() san_lock_config.user = '******' san_lock_config.group = 'sanlock' san_lock_config.host_id = 1 san_lock_config.auto_disk_leases = True process.run("mkdir -p /var/lib/libvirt/sanlock", shell=True) san_lock_config.disk_lease_dir = "/var/lib/libvirt/sanlock" san_lock_config.require_lease_for_disks = False # Start sanlock service and restart libvirtd to enforce changes. result = process.run("systemctl start wdmd", shell=True) if result.exit_status: test.error("Failed to start wdmd service") result = process.run("systemctl start sanlock", shell=True) if result.exit_status: test.error("Failed to start sanlock service") utils_libvirtd.Libvirtd().restart() # Prepare lockspace and lease file for sanlock in order. sanlock_cmd_dict = OrderedDict() sanlock_cmd_dict["truncate -s 1M /var/lib/libvirt/sanlock/TEST_LS"] = "Failed to truncate TEST_LS" sanlock_cmd_dict["sanlock direct init -s TEST_LS:0:/var/lib/libvirt/sanlock/TEST_LS:0"] = "Failed to sanlock direct init TEST_LS:0" sanlock_cmd_dict["chown sanlock:sanlock /var/lib/libvirt/sanlock/TEST_LS"] = "Failed to chown sanlock TEST_LS" sanlock_cmd_dict["restorecon -R -v /var/lib/libvirt/sanlock"] = "Failed to restorecon sanlock" sanlock_cmd_dict["truncate -s 1M /var/lib/libvirt/sanlock/test-disk-resource-lock"] = "Failed to truncate test-disk-resource-lock" sanlock_cmd_dict["sanlock direct init -r TEST_LS:test-disk-resource-lock:" + "/var/lib/libvirt/sanlock/test-disk-resource-lock:0"] = "Failed to sanlock direct init test-disk-resource-lock" sanlock_cmd_dict["chown sanlock:sanlock " + "/var/lib/libvirt/sanlock/test-disk-resource-lock"] = "Failed to chown test-disk-resource-loc" sanlock_cmd_dict["sanlock client add_lockspace -s TEST_LS:1:" + "/var/lib/libvirt/sanlock/TEST_LS:0"] = "Failed to client add_lockspace -s TEST_LS:0" for sanlock_cmd in sanlock_cmd_dict.keys(): result = process.run(sanlock_cmd, shell=True) if result.exit_status: test.error(sanlock_cmd_dict[sanlock_cmd]) # Create one lease device and add it to VM. san_lock_vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) lease_device = Lease() lease_device.lockspace = 'TEST_LS' lease_device.key = 'test-disk-resource-lock' lease_device.target = {'path': '/var/lib/libvirt/sanlock/test-disk-resource-lock'} san_lock_vmxml.add_device(lease_device) san_lock_vmxml.sync() # Install ceph-common package which include rbd command if utils_package.package_install(["ceph-common"]): if client_name and client_key: with open(key_file, 'w') as f: f.write("[%s]\n\tkey = %s\n" % (client_name, client_key)) key_opt = "--keyring %s" % key_file # Create secret xml sec_xml = secret_xml.SecretXML("no", "no") sec_xml.usage = auth_type sec_xml.usage_name = auth_usage sec_xml.xmltreefile.write() logging.debug("Secret xml: %s", sec_xml) ret = virsh.secret_define(sec_xml.xml) libvirt.check_exit_status(ret) secret_uuid = re.findall(r".+\S+(\ +\S+)\ +.+\S+", ret.stdout.strip())[0].lstrip() logging.debug("Secret uuid %s", secret_uuid) if secret_uuid is None: test.error("Failed to get secret uuid") # Set secret value auth_key = params.get("auth_key") ret = virsh.secret_set_value(secret_uuid, auth_key, **virsh_dargs) libvirt.check_exit_status(ret) # Delete the disk if it exists cmd = ("rbd -m {0} {1} info {2} && rbd -m {0} {1} rm " "{2}".format(mon_host, key_opt, disk_src_name)) process.run(cmd, ignore_status=True, shell=True) else: test.error("Failed to install ceph-common") if disk_src_config: config_ceph() disk_path = ("rbd:%s:mon_host=%s" % (disk_src_name, mon_host)) if auth_user and auth_key: disk_path += (":id=%s:key=%s" % (auth_user, auth_key)) targetdev = params.get("disk_target", "vdb") # To be compatible with create_disk_xml function, # some parameters need to be updated. params.update({ "type_name": params.get("disk_type", "network"), "target_bus": params.get("disk_target_bus"), "target_dev": targetdev, "secret_uuid": secret_uuid, "source_protocol": params.get("disk_source_protocol"), "source_name": disk_src_name, "source_host_name": disk_src_host, "source_host_port": disk_src_port}) # Prepare disk image if convert_image: first_disk = vm.get_first_disk_devices() blk_source = first_disk['source'] # Convert the image to remote storage disk_cmd = ("rbd -m %s %s info %s 2> /dev/null|| qemu-img convert" " -O %s %s %s" % (mon_host, key_opt, disk_src_name, disk_format, blk_source, disk_path)) process.run(disk_cmd, ignore_status=False, shell=True) elif create_volume: vol_params = {"name": vol_name, "capacity": int(vol_cap), "capacity_unit": vol_cap_unit, "format": disk_format} create_pool() create_vol(vol_params) check_vol(vol_params) else: # Create an local image and make FS on it. disk_cmd = ("qemu-img create -f %s %s 10M && mkfs.ext4 -F %s" % (disk_format, img_file, img_file)) process.run(disk_cmd, ignore_status=False, shell=True) # Convert the image to remote storage disk_cmd = ("rbd -m %s %s info %s 2> /dev/null|| qemu-img convert -O" " %s %s %s" % (mon_host, key_opt, disk_src_name, disk_format, img_file, disk_path)) process.run(disk_cmd, ignore_status=False, shell=True) # Create disk snapshot if needed. if create_snapshot: snap_cmd = ("rbd -m %s %s snap create %s@%s" % (mon_host, key_opt, disk_src_name, snap_name)) process.run(snap_cmd, ignore_status=False, shell=True) if test_json_pseudo_protocol: # Create one frontend image with the rbd backing file. json_str = ('json:{"file.driver":"rbd",' '"file.filename":"rbd:%s:mon_host=%s"}' % (disk_src_name, mon_host)) # pass different json string according to the auth config if auth_user and auth_key: json_str = ('%s:id=%s:key=%s"}' % (json_str[:-2], auth_user, auth_key)) disk_cmd = ("qemu-img create -f qcow2 -b '%s' %s" % (json_str, front_end_img_file)) disk_path = front_end_img_file process.run(disk_cmd, ignore_status=False, shell=True) # If hot plug, start VM first, and then wait the OS boot. # Otherwise stop VM if running. if start_vm: if vm.is_dead(): vm.start() vm.wait_for_login().close() else: if not vm.is_dead(): vm.destroy() if attach_device: if create_volume: params.update({"source_pool": pool_name}) params.update({"type_name": "volume"}) # No need auth options for volume if "auth_user" in params: params.pop("auth_user") if "auth_type" in params: params.pop("auth_type") if "secret_type" in params: params.pop("secret_type") if "secret_uuid" in params: params.pop("secret_uuid") if "secret_usage" in params: params.pop("secret_usage") xml_file = libvirt.create_disk_xml(params) if additional_guest: # Copy xml_file for additional guest VM. shutil.copyfile(xml_file, additional_xml_file) opts = params.get("attach_option", "") ret = virsh.attach_device(vm_name, xml_file, flagstr=opts, debug=True) libvirt.check_result(ret, skip_if=unsupported_err) if additional_guest: # Make sure the additional VM is running if additional_vm.is_dead(): additional_vm.start() additional_vm.wait_for_login().close() ret = virsh.attach_device(guest_name, additional_xml_file, "", debug=True) libvirt.check_result(ret, skip_if=unsupported_err) elif attach_disk: opts = params.get("attach_option", "") ret = virsh.attach_disk(vm_name, disk_path, targetdev, opts) libvirt.check_result(ret, skip_if=unsupported_err) elif test_disk_readonly: params.update({'readonly': "yes"}) xml_file = libvirt.create_disk_xml(params) opts = params.get("attach_option", "") ret = virsh.attach_device(vm_name, xml_file, flagstr=opts, debug=True) libvirt.check_result(ret, skip_if=unsupported_err) elif test_disk_internal_snapshot: xml_file = libvirt.create_disk_xml(params) opts = params.get("attach_option", "") ret = virsh.attach_device(vm_name, xml_file, flagstr=opts, debug=True) libvirt.check_result(ret, skip_if=unsupported_err) elif disk_snapshot_with_sanlock: if vm.is_dead(): vm.start() snapshot_path = make_snapshot() if vm.is_alive(): vm.destroy() elif not create_volume: libvirt.set_vm_disk(vm, params) if test_blockcopy: logging.info("Creating %s...", vm_name) vmxml_for_test = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) if vm.is_alive(): vm.destroy(gracefully=False) vm.undefine() if virsh.create(vmxml_for_test.xml, **virsh_dargs).exit_status: vmxml_backup.define() test.fail("Can't create the domain") elif vm.is_dead(): vm.start() # Wait for vm is running vm.wait_for_login(timeout=600).close() if additional_guest: if additional_vm.is_dead(): additional_vm.start() # Check qemu command line if test_qemu_cmd: check_qemu_cmd() # Check partitions in vm if test_vm_parts: if not check_in_vm(vm, targetdev, old_parts, read_only=create_snapshot): test.fail("Failed to check vm partitions") if additional_guest: if not check_in_vm(additional_vm, targetdev, old_parts): test.fail("Failed to check vm partitions") # Save and restore operation if test_save_restore: check_save_restore() if test_snapshot: snap_option = params.get("snapshot_option", "") check_snapshot(snap_option) if test_blockcopy: check_blockcopy(targetdev) if test_disk_readonly: snap_option = params.get("snapshot_option", "") check_snapshot(snap_option, 'vdb') if test_disk_internal_snapshot: snap_option = params.get("snapshot_option", "") check_snapshot(snap_option, targetdev) # Detach the device. if attach_device: xml_file = libvirt.create_disk_xml(params) ret = virsh.detach_device(vm_name, xml_file) libvirt.check_exit_status(ret) if additional_guest: ret = virsh.detach_device(guest_name, xml_file) libvirt.check_exit_status(ret) elif attach_disk: ret = virsh.detach_disk(vm_name, targetdev) libvirt.check_exit_status(ret) # Check disk in vm after detachment. if attach_device or attach_disk: session = vm.wait_for_login() new_parts = libvirt.get_parts_list(session) if len(new_parts) != len(old_parts): test.fail("Disk still exists in vm" " after detachment") session.close() except virt_vm.VMStartError as details: for msg in unsupported_err: if msg in str(details): test.cancel(str(details)) else: test.fail("VM failed to start." "Error: %s" % str(details)) finally: # Remove /etc/ceph/ceph.conf file if exists. if os.path.exists('/etc/ceph/ceph.conf'): os.remove('/etc/ceph/ceph.conf') # Delete snapshots. 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") # Recover VM. if vm.is_alive(): vm.destroy(gracefully=False) if additional_guest: virsh.remove_domain(guest_name, "--remove-all-storage", ignore_stauts=True) # Remove the snapshot. if create_snapshot: cmd = ("rbd -m {0} {1} info {2} && rbd -m {0} {1} snap" " purge {2} && rbd -m {0} {1} rm {2}" "".format(mon_host, key_opt, disk_src_name)) process.run(cmd, ignore_status=True, shell=True) elif create_volume: cmd = ("rbd -m {0} {1} info {2} && rbd -m {0} {1} rm {2}" "".format(mon_host, key_opt, os.path.join(disk_src_pool, cloned_vol_name))) process.run(cmd, ignore_status=True, shell=True) cmd = ("rbd -m {0} {1} info {2} && rbd -m {0} {1} rm {2}" "".format(mon_host, key_opt, os.path.join(disk_src_pool, create_from_cloned_volume))) process.run(cmd, ignore_status=True, shell=True) clean_up_volume_snapshots() else: cmd = ("rbd -m {0} {1} info {2} && rbd -m {0} {1} rm {2}" "".format(mon_host, key_opt, disk_src_name)) process.run(cmd, ignore_status=True, shell=True) # Delete tmp files. if os.path.exists(key_file): os.remove(key_file) if os.path.exists(img_file): os.remove(img_file) # Clean up volume, pool if vol_name and vol_name in str(virsh.vol_list(pool_name).stdout): virsh.vol_delete(vol_name, pool_name) if pool_name and pool_name in virsh.pool_state_dict(): virsh.pool_destroy(pool_name, **virsh_dargs) virsh.pool_undefine(pool_name, **virsh_dargs) # Clean up secret secret_list = get_secret_list() if secret_list: for secret_uuid in secret_list: virsh.secret_undefine(secret_uuid) logging.info("Restoring vm...") vmxml_backup.sync() if disk_snapshot_with_sanlock: # Restore virt_use_sanlock setting. process.run("setsebool -P virt_use_sanlock 0", shell=True) # Restore qemu config qemu_config.restore() utils_libvirtd.Libvirtd().restart() # Force shutdown sanlock service. process.run("sanlock client shutdown -f 1", shell=True) # Clean up lockspace folder process.run("rm -rf /var/lib/libvirt/sanlock/*", shell=True) if snapshot_path is not None: for snapshot in snapshot_path: if os.path.exists(snapshot): os.remove(snapshot)
test.fail("VM failed to start." "Error: %s" % str(details)) finally: # Delete snapshots. 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") # Recover VM. if vm.is_alive(): vm.destroy(gracefully=False) if additional_guest: virsh.remove_domain(guest_name, "--remove-all-storage", ignore_stauts=True) # Remove the snapshot. if create_snapshot: cmd = ("rbd -m {0} {1} info {2} && rbd -m {0} {1} snap" " purge {2} && rbd -m {0} {1} rm {2}" "".format(mon_host, key_opt, disk_src_name)) process.run(cmd, ignore_status=True, shell=True) elif create_volume: cmd = ("rbd -m {0} {1} info {2} && rbd -m {0} {1} rm {2}" "".format(mon_host, key_opt, os.path.join(disk_src_pool, cloned_vol_name))) process.run(cmd, ignore_status=True, shell=True) cmd = ("rbd -m {0} {1} info {2} && rbd -m {0} {1} rm {2}" "".format(mon_host, key_opt, os.path.join(disk_src_pool, create_from_cloned_volume))) process.run(cmd, ignore_status=True, shell=True) clean_up_volume_snapshots()
params['inactivity_treshold'] = 1800 params['image_verify_bootable'] = "no" params['unattended_delivery_method'] = "cdrom" params['drive_index_unattended'] = 1 params['drive_index_cd1'] = 2 params['boot_once'] = "d" params['medium'] = "cdrom" params['wait_no_ack'] = "yes" params['image_raw_device'] = "yes" params['backup_image_before_testing'] = "no" params['kernel_params'] = ("ks=cdrom nicdelay=60 " "console=ttyS0,115200 console=tty0") params['cdroms'] = "unattended cd1" params['redirs'] += " unattended_install" try: unattended_install.run(test, params, env) except error.CmdError, detail: raise error.TestFail("Guest install failed:%s" % detail) finally: env.unregister_vm(vm_name) finally: try: if application == "install": if virsh.domain_exists(vm_name): virsh.remove_domain(vm_name) elif application == "attach": virsh.detach_disk(vm_name, disk_target) finally: pvtest.cleanup_pool(pool_name, pool_type, pool_target, emulated_img)
def run(test, params, env): """ Configuring /etc/sysconfig/libvirt-guests, then check the domains status after restarting the libvirt-guests.server, 1. Set the values in /etc/sysconfig/libvirt-guests 2. Restart libvirt-guests service 3. Check the domains states, and the guests' save files """ def get_log(): """ Tail output appended data as the file /var/log/messages grows :returns: the appended data tailed from /var/log/messages """ tailed_log_file = os.path.join(data_dir.get_tmp_dir(), 'tail_log') tailed_messages = aexpect.Tail(command='tail -f /var/log/messages', output_func=utils_misc.log_line, output_params=(tailed_log_file)) return tailed_messages def chk_on_shutdown(status_error, on_shutdown, parallel_shutdown, output): """ check domains' state when host shutdown, and if parallel_shutdown is set to non-zero, check whether the guests have been shutdown corretly. :param status_error: positive test if status_error is "no", otherwise negative test :param on_shutdown: action taking on host shutdown :param parallel_shutdown: the number of parallel_shutdown guests would be shutdown concurrently on shutdown :param output: apppended message from /var/log/messages """ if on_shutdown == "shutdown" and on_boot == "start": second_boot_time = boot_time() logging.debug("The second boot time is %s", second_boot_time) if any([i >= j for i, j in zip(first_boot_time, second_boot_time)]): test.fail("The second boot time for should be larger" "than its first boot time.") expect_msg = expect_shutdown_msg(status_error, on_shutdown) logging.debug("The expected messages when host shutdown is: %s ", expect_msg) for dom in vms: if not re.search(expect_msg[dom.name], output): logging.debug("expect_mesg is: %s", expect_msg[dom.name]) if status_error == "no": test.fail("guest should be %s on shutdown" % on_shutdown) else: test.fail("Shutdown of guest should be failed to " "complete in time") if (on_shutdown == "shutdown") and int(parallel_shutdown) > 0: chk_parallel_shutdown(output, parallel_shutdown) def chk_on_boot(status_error, on_boot): """ check domains' state when host booted :param status_error: positive test if status_error is "no", otherwise negative test :param on_boot: action taking on host booting """ if status_error == "no": if on_boot == "start": for dom in vms: if not dom.is_alive(): test.fail("Since on_boot is setting to 'start', " "guest should be running after " "restarting libvirt-guests.") else: for dom in vms: if dom.is_alive(): test.fail("Since on_boot is setting to 'ignore', " "unless guests are autostart, " "guest should be shut off after " "restarting libvirt-guests, ") def check_on_shutdown_vm_status(): for dom in vms: result = virsh.domstate(dom.name, "--reason") try: dom.wait_for_shutdown() except Exception as e: test.fail('As on_boot is set to "ignore", but guest %s is ' 'not shutdown. reason: %s ' % (dom.name, e)) def chk_parallel_shutdown(output, parallel_shutdown): """ check whether the guests has been shut down concurrently on host shutdown. """ pattern = r".+ libvirt-guests.sh.*: Starting shutdown on guest: .+" shut_start_line_nums = [] for line_num, line in enumerate(output.splitlines()): if re.search(pattern, line): shut_start_line_nums.append(line_num) logging.debug("the line_numbers contains shutdown messages is: %s ", shut_start_line_nums) pattern = r".+ libvirt-guests.sh.*: Shutdown of guest.+complete" for line_num, line in enumerate(output.splitlines()): if re.search(pattern, line): shut_complete_first_line = line_num break logging.debug("the first line contains shutdown complete messages is: %s ", shut_complete_first_line) para_shut = int(parallel_shutdown) if shut_start_line_nums[para_shut-1] > shut_complete_first_line: test.fail("Since parallel_shutdown is setting to non_zero, " "%s guests should be shutdown concurrently." % parallel_shutdown) if shut_start_line_nums[para_shut] < shut_complete_first_line: test.fail("The number of guests shutdown concurrently " "should not be exceeded than %s." % parallel_shutdown) def expect_shutdown_msg(status_error, on_shutdown): """ the expected messages of each guests when host shutdown logged into /var/log/messages """ expect_msg = {} for dom in vms: if status_error == "no": if on_shutdown == "shutdown": expect_msg[dom.name] = ("libvirt-guests.sh.*: " "Shutdown of guest %s " "complete" % dom.name) else: expect_msg[dom.name] = ("libvirt-guests.sh.*: " "Suspending %s: done" % dom.name) else: # Now the negative tests are only about ON_SHUTDOWN=shutdown. if on_shutdown == "shutdown": expect_msg[dom.name] = ("libvirt-guests.sh.*: " "Shutdown of guest %s " "failed to complete in " "time" % dom.name) return expect_msg def chk_save_files(status_error, on_shutdown, on_boot): """ save files should exist when on_shutdown is set to shutdown, and on_boot is set to ignore. In other conditions, there should be no save files. """ save_files = dict() for dom in vms: save_files[dom] = ("/var/lib/libvirt/qemu/save/%s.save" % dom.name) if status_error == "no": if on_shutdown == "shutdown": for dom in vms: if os.path.exists(save_files[dom]): test.fail("There should be no save files since " "guests are shutdown on host shutdown.") else: if on_boot == "start": for dom in vms: if os.path.exists(save_files[dom]): test.fail("There should be no save files since " "guests are restored on host shutdown.") else: for dom in vms: if not os.path.exists(save_files[dom]): test.fail("Guests are suspended on host shutdown, " "and been ignored on host boot, there " "should be save files for the guests.") def boot_time(): booting_time = [] for vm in vms: session = vm.wait_for_login() time = session.cmd_output("uptime --since") booting_time.append(time) session.close() return booting_time main_vm_name = params.get("main_vm") main_vm = env.get_vm(main_vm_name) on_boot = params.get("on_boot") on_shutdown = params.get("on_shutdown") parallel_shutdown = params.get("parallel_shutdown") additional_vms = int(params.get("additional_vms", "0")) status_error = params.get("status_error") shutdown_timeout = params.get("shutdown_timeout", "300") config = utils_config.LibvirtGuestsConfig() libvirt_guests_service = service.Factory.create_service("libvirt-guests") if not libvirt_guests_service.status(): libvirt_guests_service.start() vms = [main_vm] if main_vm.is_alive: main_vm.destroy(gracefully=False) if not utils_misc.start_rsyslogd(): test.error("Rsyslogd service start fail") try: utils_path.find_command("virt-clone") except utils_path.CmdNotFoundError: test.cancel("No virt-clone command found.") # Clone additional vms: avocado-vt-vm2, avocado-vt-vm3..... for i in range(additional_vms): guest_name = ("%s" % main_vm_name[:-1])+("%s" % str(i+2)) logging.debug("guest_name : %s", guest_name) utils_libguestfs.virt_clone_cmd(main_vm_name, guest_name, True, timeout=360) vms.append(main_vm.clone(guest_name)) logging.debug("Now the vms is: %s", [dom.name for dom in vms]) for dom in vms: if not dom.is_alive(): dom.start() for dom in vms: dom.wait_for_login() first_boot_time = [] if on_shutdown == "shutdown" and on_boot == "start": first_boot_time = boot_time() logging.debug("The first boot time is %s", first_boot_time) try: # Config the libvirt-guests file config.ON_BOOT = on_boot config.ON_SHUTDOWN = on_shutdown config.PARALLEL_SHUTDOWN = parallel_shutdown config.SHUTDOWN_TIMEOUT = shutdown_timeout process.run("sed -i -e 's/ = /=/g' " "/etc/sysconfig/libvirt-guests", shell=True) tail_messages = get_log() # Even though libvirt-guests was designed to operate guests when # host shutdown. The purpose can also be fullfilled by restart the # libvirt-guests service. libvirt_guests_service.restart() time.sleep(10) output = tail_messages.get_output() logging.debug("Get messages in /var/log/messages: %s" % output) # check the guests state when host shutdown chk_on_shutdown(status_error, on_shutdown, parallel_shutdown, output) # check the guests state when host rebooted chk_on_boot(status_error, on_boot) # check the guests save files chk_save_files(status_error, on_shutdown, on_boot) if on_boot == "ignore" and on_shutdown == "shutdown": check_on_shutdown_vm_status() finally: config.restore() # Undefine additional vms for dom in vms[1:]: if dom.is_alive(): dom.destroy(gracefully=False) virsh.remove_domain(dom.name, "--remove-all-storage") if not libvirt_guests_service.status(): libvirt_guests_service.start()
def run(test, params, env): """ Test qemu-monitor-command blockjobs by migrating with option --copy-storage-all or --copy-storage-inc. """ if not libvirt_version.version_compare(1, 0, 1): raise error.TestNAError("Blockjob functions - " "complete,pause,resume are" "not supported in current libvirt version.") vm = env.get_vm(params.get("main_vm")) cpu_size = int(params.get("cpu_size", "1")) memory_size = int(params.get("memory_size", "1048576")) primary_target = vm.get_first_disk_devices()["target"] file_path, file_size = vm.get_device_size(primary_target) # Convert to Gib file_size = int(file_size) / 1073741824 image_format = utils_test.get_image_info(file_path)["format"] remote_host = params.get("migrate_dest_host", "REMOTE.EXAMPLE") remote_user = params.get("remote_user", "root") remote_passwd = params.get("migrate_dest_pwd", "PASSWORD.EXAMPLE") if remote_host.count("EXAMPLE"): raise error.TestNAError("Config remote or local host first.") # Config ssh autologin for it ssh_key.setup_ssh_key(remote_host, remote_user, remote_passwd, port=22) # Define a new vm with modified cpu/memory new_vm_name = "%s_blockjob" % vm.name if vm.is_alive(): vm.destroy() utlv.define_new_vm(vm.name, new_vm_name) try: set_cpu_memory(new_vm_name, cpu_size, memory_size) vm = libvirt_vm.VM(new_vm_name, vm.params, vm.root_dir, vm.address_cache) except: # Make sure created vm is cleaned up virsh.remove_domain(new_vm_name) raise rdm_params = { "remote_ip": remote_host, "remote_user": remote_user, "remote_pwd": remote_passwd } rdm = utils_test.RemoteDiskManager(rdm_params) try: vm = libvirt_vm.VM(new_vm_name, vm.params, vm.root_dir, vm.address_cache) vm.start() rdm.create_image("file", file_path, file_size, None, None, img_frmt=image_format) logging.debug("Start migration...") copied_migration(vm, params, params.get("qmp_blockjob_type"), primary_target) finally: # Recover created vm if vm.is_alive(): vm.destroy() if vm.name == new_vm_name: vm.undefine() rdm.remove_path("file", file_path) rdm.runner.session.close()
def run(test, params, env): """ Convert a remote vm to local libvirt(KVM). """ for v in list(params.values()): if "V2V_EXAMPLE" in v: raise exceptions.TestSkipError("Please set real value for %s" % v) enable_legacy_policy = params_get(params, "enable_legacy_policy") == 'yes' vm_name = params.get("main_vm") 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_pwd_file = params.get("vpx_passwd_file") vpx_dc = params.get("vpx_dc") esx_ip = params.get("esx_hostname") hypervisor = params.get("hypervisor") input_mode = params.get("input_mode") target = params.get("target") v2v_opts = '-v -x' if params.get('v2v_debug', 'on') == 'on' else '' if params.get('v2v_opts'): # Add a blank by force v2v_opts += ' ' + params.get("v2v_opts") # 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') source_pwd = None # Prepare step for different hypervisor if enable_legacy_policy: update_crypto_policy("LEGACY") if hypervisor == "esx": source_ip = vpx_ip source_pwd = vpx_pwd # Create password file to access ESX hypervisor with open(vpx_pwd_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 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: process.run("ssh-agent -k") raise exceptions.TestError("Fail to setup ssh-agent") else: raise exceptions.TestSkipError("Unsupported hypervisor: %s" % hypervisor) # Create libvirt URI for the source node v2v_uri = utils_v2v.Uri(hypervisor) remote_uri = v2v_uri.get_uri(source_ip, vpx_dc, esx_ip) LOG.debug("Remote host uri for converting: %s", remote_uri) # Make sure the VM exist before convert virsh_dargs = { 'uri': remote_uri, 'remote_ip': source_ip, 'remote_user': source_user, 'remote_pwd': source_pwd, 'auto_close': True, 'debug': True } remote_virsh = virsh.VirshPersistent(**virsh_dargs) try: if not remote_virsh.domain_exists(vm_name): raise exceptions.TestError("VM '%s' not exist" % vm_name) finally: remote_virsh.close_session() # Prepare libvirt storage pool pool_type = params.get("pool_type") pool_name = params.get("pool_name") pool_target = params.get("pool_target") libvirt_pool = utlv.PoolVolumeTest(test, params) libvirt_pool.pre_pool(pool_name, pool_type, pool_target, '') # Prepare libvirt virtual network network = params.get("network") net_kwargs = { 'net_name': network, 'address': params.get('network_addr'), 'dhcp_start': params.get('network_dhcp_start'), 'dhcp_end': params.get('network_dhcp_end') } libvirt_net = utlv.LibvirtNetwork('vnet', **net_kwargs) net_info = virsh.net_info(network).stdout.strip() bridge = re.search(r'Bridge:\s+(\S+)', net_info).group(1) params['netdst'] = bridge # 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, 'os_pool': pool_name, 'hostname': source_ip, 'password': source_pwd, 'input_transport': input_transport, 'vcenter_host': vpx_ip, 'vcenter_password': vpx_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}) if v2v_opts: v2v_params.update({"v2v_opts": v2v_opts}) # Set libguestfs environment if hypervisor == 'xen': os.environ['LIBGUESTFS_BACKEND'] = 'direct' try: # Execute virt-v2v command ret = utils_v2v.v2v_cmd(v2v_params) if ret.exit_status != 0: raise exceptions.TestFail("Convert VM failed") LOG.debug("XML info:\n%s", virsh.dumpxml(vm_name)) vm = env.create_vm("libvirt", "libvirt", vm_name, params, test.bindir) # Win10 is not supported by some cpu model, # need to modify to 'host-model' unsupport_list = ['win10', 'win2016', 'win2019'] if params.get('os_version') in unsupport_list: LOG.info('Set cpu mode to "host-model" for %s.', unsupport_list) vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) cpu_xml = vm_xml.VMCPUXML() cpu_xml.mode = 'host-model' cpu_xml.fallback = 'allow' vmxml['cpu'] = cpu_xml vmxml.sync() vm.start() # Check all checkpoints after convert vmchecker = VMChecker(test, params, env) # Cannot do "params['vmchecker'] = vmchecker" if vm was to_libvirt, # or exception 'Fatal Python error: Cannot recover from stack overflow' # will happen. Not sure how it happens now, if somebody knows about it, # Please help to fix it. # # The exception happens at: # avocado/utils/stacktrace.py, line 98 in analyze_unpickable_item # <FIXIT> in future. try: ret = vmchecker.run() finally: vmchecker.cleanup() if len(ret) == 0: LOG.info("All checkpoints passed") else: raise exceptions.TestFail("%d checkpoints failed: %s" % (len(ret), ret)) finally: utils_v2v.cleanup_constant_files(params) 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") # Clean libvirt VM virsh.remove_domain(vm_name) # Clean libvirt pool if libvirt_pool: libvirt_pool.cleanup_pool(pool_name, pool_type, pool_target, '') # Clean libvirt network if libvirt_net: libvirt_net.cleanup()
def run(test, params, env): """ Test svirt in virt-install. (1). Init variables. (2). Set selinux on host. (3). Set label of image. (4). run a virt-install command. (5). clean up. As this test only care whether the qemu-kvm process can access the image. It is not necessary to install a full os in a vm. Just verify the vm is alive after virt-install command is enough. Then we can save a lot of time and make this test independent from unattended_install. """ # Get general variables. status_error = "yes" == params.get("status_error", "no") host_sestatus = params.get("host_selinux", "enforcing") # Get variables about seclabel for VM. sec_type = params.get("svirt_install_vm_sec_type", "dynamic") sec_model = params.get("svirt_install_vm_sec_model", "selinux") sec_label = params.get("svirt_install_vm_sec_label", None) sec_relabel = params.get("svirt_install_vm_sec_relabel", "yes") # Set selinux status on host. backup_sestatus = utils_selinux.get_status() utils_selinux.set_status(host_sestatus) # Set the image label. disk_label = params.get("svirt_install_disk_label", None) vm_name = params.get("main_vm", None) # svirt will prevent accessing via a symble link. data_path = data_dir.get_data_dir() real_data_path = os.path.realpath(data_path) image_path = os.path.join(real_data_path, "svirt_image") if virsh.domain_exists(vm_name): virsh.remove_domain(vm_name) if not os.path.exists(image_path): utils_test.libvirt.create_local_disk("file", path=image_path) try: utils_selinux.set_context_of_file(image_path, disk_label) cmd = "virt-install --name %s --import --disk path=%s --ram '1024' " % (vm_name, image_path) cmd += " --security" if sec_type == "static": if sec_label is None: raise ValueError("Seclabel is not setted for static.") cmd += " type=static,label=%s" % (sec_label) elif sec_type == "dynamic": cmd += " type=dynamic" else: raise ValueError("Security type %s is not supported." % sec_type) if sec_relabel is not None: cmd += ",relabel=%s" % sec_relabel cmd += "&" utils.run(cmd, ignore_status=True) def _vm_alive(): return virsh.is_alive(vm_name) if utils_misc.wait_for(_vm_alive, timeout=5): if status_error: raise error.TestFail("Test succeeded in negative case.") else: if not status_error: raise error.TestFail("Test failed in positive case.") finally: # cleanup utils_selinux.set_status(backup_sestatus) if virsh.domain_exists(vm_name): virsh.remove_domain(vm_name) if not os.path.exists(image_path): utils_test.libvirt.delete_local_disk("file", path=image_path)
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 params.itervalues(): if "V2V_EXAMPLE" in v: raise exceptions.TestSkipError("Please set real value for %s" % v) vm_name = params.get("main_vm", "EXAMPLE") new_vm_name = params.get("new_vm_name") input_mode = params.get("input_mode") 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") output_mode = params.get("output_mode") output_storage = params.get("output_storage", "default") disk_img = params.get("input_disk_image", "") nfs_storage = params.get("nfs_storage") no_root = 'yes' == params.get('no_root', 'no') mnt_point = params.get("mount_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_path", "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', '') 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 %s'" % target_path process.system(cmd, verbose=True) cmd = su_cmd + "'virsh pool-create-as %s dir" % pool_name cmd += " --target %s'" % target_path process.system(cmd, verbose=True) else: pvt.pre_pool(pool_name, pool_type, pool_target, emulated_img) 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: cmd = su_cmd + "'virsh pool-destroy %s'" % pool_name process.system(cmd, verbose=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: raise exceptions.TestError("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 = 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: raise exceptions.TestFail("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): raise exceptions.TestError("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: raise exceptions.TestFail("%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: raise exceptions.TestFail( "%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: raise exceptions.TestFail("%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: raise exceptions.TestFail("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: raise exceptions.TestFail("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: raise exceptions.TestFail("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: raise exceptions.TestFail('vm_snapshot_id consists with "0"') else: raise exceptions.TestFail('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', 'display', 'CPU features', 'disks', 'NICs' ] for key in checklist: if key not in source_info: raise exceptions.TestFail('%s info missing' % key) # Check single values fail = [] xml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) 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)' 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 source_info[key] != str(check_map[key]): fail.append(key) # Check disk info disk = xml.get_disk_all().values()[0] bus, type = disk.find('target').get('bus'), disk.find('driver').get( 'type') path = disk.find('source').get('file') disks_info = "%s (%s) [%s]" % (path, type, bus) logging.info('disks:%s<->%s', source_info['disks'], disks_info) if source_info['disks'] != disks_info: fail.append('disks') # Check nic info nic = 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 source_info['NICs'].lower() != nic_info.lower(): fail.append('NICs') # Check cpu features 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: raise exceptions.TestFail('Source info not correct for: %s' % fail) def check_result(cmd, result, status_error): """ Check virt-v2v command result """ utlv.check_exit_status(result, status_error) output = result.stdout + result.stderr 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 if v2v_start and len(line) > 72: raise exceptions.TestFail( 'Error log longer than 72 ' '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: raise exceptions.TestFail('Disk exists for vm %s' % vm_name) else: error_map = { 'conflict_options': ['option used more than once'], 'xen_no_output_format': ['The input metadata did not define' ' the disk format'], 'in_place': ['virt-v2v: error: --in-place cannot be used in RHEL 7'] } if error_map.has_key(checkpoint) and not utils_v2v.check_log( output, error_map[checkpoint]): raise exceptions.TestFail('Not found error message %s' % error_map[checkpoint]) 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): raise exceptions.TestFail('Allocation check failed.') if '-of' in cmd and '--no-copy' not in cmd and checkpoint != 'quiet': 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): raise exceptions.TestFail("Import VM failed") else: 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 == 'quiet': if len(output.strip()) != 0: raise exceptions.TestFail( 'Output is not empty in quiet mode') if checkpoint == 'dependency': if 'libguestfs-winsupport' not in output: raise exceptions.TestFail( 'libguestfs-winsupport not in dependency') if 'qemu-kvm-rhev' in output: raise exceptions.TestFail('qemu-kvm-rhev 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: raise exceptions.TestFail('Command "%s" success' % command % win_img) if checkpoint == 'no_dcpath': if not utils_v2v.check_log(output, ['--dcpath'], expect=False): raise exceptions.TestFail('"--dcpath" is not removed') if checkpoint == 'debug_overlays': search = re.search('Overlay saved as(.*)', output) if not search: raise exceptions.TestFail( '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: raise exceptions.TestFail('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 result.stdout.lower(): raise exceptions.TestFail('Expect log not found: %s' % target_str) if checkpoint == 'print_source': check_source(result.stdout) if checkpoint == 'machine_readable': if os.path.exists(params.get('example_file', '')): expect_output = open(params['example_file']).read().strip() logging.debug(expect_output) logging.debug(expect_output == result.stdout.strip()) else: raise exceptions.TestError('No content to compare with') if checkpoint == 'compress': img_path = get_img_path(output) logging.info('Image path: %s', img_path) disk_check = process.run('qemu-img check %s' % img_path).stdout 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: raise exceptions.TestFail('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 not utils_v2v.check_log(messages, [msg_content], expect=False): raise exceptions.TestFail( 'Found "%s" in /var/log/messages' % msg_content) backup_xml = None vdsm_domain_dir, vdsm_image_dir, vdsm_vm_dir = ("", "", "") try: 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) if checkpoint == 'with_ic': ic_uri = 'qemu:///session' input_option = "-i %s -ic %s %s" % (input_mode, ic_uri, vm_name) if checkpoint == 'without_ic': input_option = '-i %s %s' % (input_mode, vm_name) # 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']: raise exceptions.TestSkipError("Unsupported input mode: %s" % input_mode) else: raise exceptions.TestError("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 -os %s" % (output_mode, output_storage) 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"): raise exceptions.TestError("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) # 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' ]: 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 = string.replace(input_option, disk_img, disk_path) os.chown(disk_path, user_info.pw_uid, user_info.pw_gid) elif not no_root: raise exceptions.TestSkipError( "Only support convert local disk") # Setup ssh-agent access to xen hypervisor if hypervisor == 'xen': user = params.get("xen_host_user", "root") passwd = params.get("xen_host_passwd", "redhat") logging.info("set up ssh-agent access ") ssh_key.setup_ssh_key(remote_host, user=user, port=22, password=passwd) 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': vpx_passwd = params.get("vpx_passwd") vpx_passwd_file = os.path.join(test.tmpdir, "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 += " --password-file %s" % vpx_passwd_file # Create libvirt dir pool if output_mode == "libvirt": create_pool() if hypervisor in ['esx', 'xen' ] or input_mode in ['disk', 'libvirtxml']: os.environ['LIBGUESTFS_BACKEND'] = 'direct' if checkpoint in ['with_ic', 'without_ic']: new_v2v_user = True v2v_options += ' -on %s' % new_vm_name create_pool(user_pool=True, pool_name='src_pool', pool_target='v2v_src_pool') create_pool(user_pool=True) logging.debug(virsh.pool_list(uri='qemu:///session')) sh_install_vm = params.get('sh_install_vm') if not sh_install_vm: raise exceptions.TestError( 'Source vm installing script missing') process.run('su - %s -c %s' % (v2v_user, sh_install_vm)) # Running virt-v2v command cmd = "%s %s %s %s" % (utils_v2v.V2V_EXEC, input_option, output_option, v2v_options) if v2v_user: cmd = su_cmd + "'%s'" % cmd if checkpoint in ['dependency', 'no_dcpath']: cmd = params.get('check_command') # 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 == "xen": process.run("ssh-agent -k") if hypervisor == "esx": process.run("rm -rf %s" % vpx_passwd_file) 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: logging.error('Undefine "%s" failed', vm_name) if no_root: cleanup_pool(user_pool=True, pool_name='src_pool', pool_target='v2v_src_pool') cleanup_pool(user_pool=True) else: virsh.remove_domain(vm_name) cleanup_pool() vmcheck_flag = params.get("vmcheck_flag") if vmcheck_flag: vmcheck = utils_v2v.VMCheck(test, params, env) vmcheck.cleanup() if new_v2v_user: process.system("userdel -f %s" % v2v_user) if backup_xml: backup_xml.sync()
def run(test, params, env): """ Test interafce xml options. 1.Prepare test environment,destroy or suspend a VM. 2.Edit xml and start the domain. 3.Perform test operation. 4.Recover test environment. 5.Confirm the test result. """ vm_name = params.get("main_vm") vm = env.get_vm(vm_name) def prepare_pxe_boot(): """ Prepare tftp server and pxe boot files """ pkg_list = ["syslinux", "tftp-server", "tftp", "ipxe-roms-qemu", "wget"] # Try to install required packages if not utils_package.package_install(pkg_list): test.error("Failed ot install required packages") boot_initrd = params.get("boot_initrd", "EXAMPLE_INITRD") boot_vmlinuz = params.get("boot_vmlinuz", "EXAMPLE_VMLINUZ") if boot_initrd.count("EXAMPLE") or boot_vmlinuz.count("EXAMPLE"): test.cancel("Please provide initrd/vmlinuz URL") # Download pxe boot images process.system("wget %s -O %s/initrd.img" % (boot_initrd, tftp_root)) process.system("wget %s -O %s/vmlinuz" % (boot_vmlinuz, tftp_root)) process.system("cp -f /usr/share/syslinux/pxelinux.0 {0};" " mkdir -m 777 -p {0}/pxelinux.cfg".format(tftp_root), shell=True) pxe_file = "%s/pxelinux.cfg/default" % tftp_root boot_txt = """ DISPLAY boot.txt DEFAULT rhel LABEL rhel kernel vmlinuz append initrd=initrd.img PROMPT 1 TIMEOUT 3""" with open(pxe_file, 'w') as p_file: p_file.write(boot_txt) def modify_iface_xml(): """ Modify interface xml options """ vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) if pxe_boot: # Config boot console for pxe boot osxml = vm_xml.VMOSXML() osxml.type = vmxml.os.type osxml.arch = vmxml.os.arch osxml.machine = vmxml.os.machine osxml.loader = "/usr/share/seabios/bios.bin" osxml.bios_useserial = "yes" osxml.bios_reboot_timeout = "-1" osxml.boots = ['network'] del vmxml.os vmxml.os = osxml xml_devices = vmxml.devices iface_index = xml_devices.index( xml_devices.by_device_tag("interface")[0]) iface = xml_devices[iface_index] iface_bandwidth = {} iface_inbound = ast.literal_eval(iface_bandwidth_inbound) iface_outbound = ast.literal_eval(iface_bandwidth_outbound) if iface_inbound: iface_bandwidth["inbound"] = iface_inbound if iface_outbound: iface_bandwidth["outbound"] = iface_outbound if iface_bandwidth: bandwidth = iface.new_bandwidth(**iface_bandwidth) iface.bandwidth = bandwidth iface_type = params.get("iface_type", "network") iface.type_name = iface_type source = ast.literal_eval(iface_source) if not source: source = {"network": "default"} net_ifs = utils_net.get_net_if(state="UP") # Check source device is valid or not, # if it's not in host interface list, try to set # source device to first active interface of host if (iface.type_name == "direct" and 'dev' in source and source['dev'] not in net_ifs): logging.warn("Source device %s is not a interface" " of host, reset to %s", source['dev'], net_ifs[0]) source['dev'] = net_ifs[0] del iface.source iface.source = source if iface_model: iface.model = iface_model if iface_rom: iface.rom = eval(iface_rom) if iface_boot: vmxml.remove_all_boots() iface.boot = iface_boot logging.debug("New interface xml file: %s", iface) vmxml.devices = xml_devices vmxml.xmltreefile.write() vmxml.sync() def run_dnsmasq_default_test(key, value=None, exists=True, name="default"): """ Test dnsmasq configuration. :param key: key in conf file to check :param value: value in conf file to check :param exists: check the key:value exist or not :param name: The name of conf file """ conf_file = "/var/lib/libvirt/dnsmasq/%s.conf" % name if not os.path.exists(conf_file): test.cancel("Can't find %s.conf file" % name) configs = "" with open(conf_file, 'r') as f: configs = f.read() logging.debug("configs in file %s: %s", conf_file, configs) if value: config = "%s=%s" % (key, value) else: config = key if not configs.count(config): if exists: test.fail("Can't find %s=%s in configuration file" % (key, value)) else: if not exists: test.fail("Found %s=%s in configuration file" % (key, value)) def run_dnsmasq_addnhosts_test(hostip, hostnames): """ Test host ip and names configuration """ conf_file = "/var/lib/libvirt/dnsmasq/default.addnhosts" hosts_re = ".*".join(hostnames) configs = "" with open(conf_file, 'r') as f: configs = f.read() logging.debug("configs in file %s: %s", conf_file, configs) if not re.search(r"%s.*%s" % (hostip, hosts_re), configs, re.M): test.fail("Can't find '%s' in configuration file" % hostip) def run_dnsmasq_host_test(iface_mac, guest_ip, guest_name): """ Test host name and ip configuration for dnsmasq """ conf_file = "/var/lib/libvirt/dnsmasq/default.hostsfile" config = "%s,%s,%s" % (iface_mac, guest_ip, guest_name) configs = "" with open(conf_file, 'r') as f: configs = f.read() logging.debug("configs in file %s: %s", conf_file, configs) if not configs.count(config): test.fail("Can't find host configuration in file %s" % conf_file) def check_class_rules(ifname, rule_id, bandwidth): """ Check bandwidth settings via 'tc class' output """ cmd = "tc class show dev %s" % ifname class_output = to_text(process.system_output(cmd)) logging.debug("Bandwidth class output: %s", class_output) class_pattern = (r"class htb %s.*rate (\d+)(K?M?)bit ceil" " (\d+)(K?M?)bit burst (\d+)(K?M?)b.*" % rule_id) se = re.search(class_pattern, class_output, re.M) if not se: test.fail("Can't find outbound setting for htb %s" % rule_id) logging.debug("bandwidth from tc output:%s" % str(se.groups())) rate = None if "floor" in bandwidth: rate = int(bandwidth["floor"]) * 8 elif "average" in bandwidth: rate = int(bandwidth["average"]) * 8 if rate: if se.group(2) == 'M': rate_check = int(se.group(1)) * 1000 else: rate_check = int(se.group(1)) assert rate_check == rate if "peak" in bandwidth: if se.group(4) == 'M': ceil_check = int(se.group(3)) * 1000 else: ceil_check = int(se.group(3)) assert ceil_check == int(bandwidth["peak"]) * 8 if "burst" in bandwidth: if se.group(6) == 'M': tc_burst = int(se.group(5)) * 1024 else: tc_burst = int(se.group(5)) assert tc_burst == int(bandwidth["burst"]) def check_filter_rules(ifname, bandwidth): """ Check bandwidth settings via 'tc filter' output """ cmd = "tc -d filter show dev %s parent ffff:" % ifname filter_output = to_text(process.system_output(cmd)) logging.debug("Bandwidth filter output: %s", filter_output) if not filter_output.count("filter protocol all pref"): test.fail("Can't find 'protocol all' settings in filter rules") filter_pattern = ".*police.*rate (\d+)(K?M?)bit burst (\d+)(K?M?)b.*" se = re.search(r"%s" % filter_pattern, filter_output, re.M) if not se: test.fail("Can't find any filter policy") logging.debug("bandwidth from tc output:%s" % str(se.groups())) logging.debug("bandwidth from setting:%s" % str(bandwidth)) if "average" in bandwidth: if se.group(2) == 'M': tc_average = int(se.group(1)) * 1000 else: tc_average = int(se.group(1)) assert tc_average == int(bandwidth["average"]) * 8 if "burst" in bandwidth: if se.group(4) == 'M': tc_burst = int(se.group(3)) * 1024 else: tc_burst = int(se.group(3)) assert tc_burst == int(bandwidth["burst"]) def check_host_routes(): """ Check network routes on host """ for rt in routes: try: route = ast.literal_eval(rt) addr = "%s/%s" % (route["address"], route["prefix"]) cmd = "ip route list %s" % addr if "family" in route and route["family"] == "ipv6": cmd = "ip -6 route list %s" % addr output = to_text(process.system_output(cmd)) match_obj = re.search(r"via (\S+).*metric (\d+)", output) if match_obj: via_addr = match_obj.group(1) metric = match_obj.group(2) logging.debug("via address %s for %s, matric is %s" % (via_addr, addr, metric)) assert via_addr == route["gateway"] if "metric" in route: assert metric == route["metric"] except KeyError: pass def run_bandwidth_test(check_net=False, check_iface=False): """ Test bandwidth option for network or interface by tc command. """ iface_inbound = ast.literal_eval(iface_bandwidth_inbound) iface_outbound = ast.literal_eval(iface_bandwidth_outbound) net_inbound = ast.literal_eval(net_bandwidth_inbound) net_outbound = ast.literal_eval(net_bandwidth_outbound) net_bridge_name = ast.literal_eval(net_bridge)["name"] iface_name = libvirt.get_ifname_host(vm_name, iface_mac) try: if check_net and net_inbound: # Check qdisc rules cmd = "tc -d qdisc show dev %s" % net_bridge_name qdisc_output = to_text(process.system_output(cmd)) logging.debug("Bandwidth qdisc output: %s", qdisc_output) if not qdisc_output.count("qdisc ingress ffff:"): test.fail("Can't find ingress setting") check_class_rules(net_bridge_name, "1:1", {"average": net_inbound["average"], "peak": net_inbound["peak"]}) check_class_rules(net_bridge_name, "1:2", net_inbound) # Check filter rules on bridge interface if check_net and net_outbound: check_filter_rules(net_bridge_name, net_outbound) # Check class rules on interface inbound settings if check_iface and iface_inbound: check_class_rules(iface_name, "1:1", {'average': iface_inbound['average'], 'peak': iface_inbound['peak'], 'burst': iface_inbound['burst']}) if "floor" in iface_inbound: if not libvirt_version.version_compare(1, 0, 1): test.cancel("Not supported Qos options 'floor'") check_class_rules(net_bridge_name, "1:3", {'floor': iface_inbound["floor"]}) # Check filter rules on interface outbound settings if check_iface and iface_outbound: check_filter_rules(iface_name, iface_outbound) except AssertionError: stacktrace.log_exc_info(sys.exc_info()) test.fail("Failed to check network bandwidth") def check_name_ip(session): """ Check dns resolving on guest """ # Check if bind-utils is installed if "ubuntu" in vm.get_distro().lower(): pkg = "bind9" else: pkg = "bind-utils" if not utils_package.package_install(pkg, session): test.error("Failed to install bind-utils on guest") # Run host command to check if hostname can be resolved if not guest_ipv4 and not guest_ipv6: test.fail("No ip address found from parameters") guest_ip = guest_ipv4 if guest_ipv4 else guest_ipv6 cmd = "host %s | grep %s" % (guest_name, guest_ip) if session.cmd_status(cmd): test.fail("Can't resolve name %s on guest" % guest_name) def check_ipt_rules(check_ipv4=True, check_ipv6=False): """ Check iptables for network/interface """ br_name = ast.literal_eval(net_bridge)["name"] net_forward = ast.literal_eval(params.get("net_forward", "{}")) net_ipv4 = params.get("net_ipv4") net_ipv6 = params.get("net_ipv6") net_dev_in = "" net_dev_out = "" if "dev" in net_forward: net_dev_in = " -i %s" % net_forward["dev"] net_dev_out = " -o %s" % net_forward["dev"] ipt_rules = ( "INPUT -i %s -p udp -m udp --dport 53 -j ACCEPT" % br_name, "INPUT -i %s -p tcp -m tcp --dport 53 -j ACCEPT" % br_name, "FORWARD -i {0} -o {0} -j ACCEPT".format(br_name), "FORWARD -o %s -j REJECT --reject-with icmp" % br_name, "FORWARD -i %s -j REJECT --reject-with icmp" % br_name) if check_ipv4: ipv4_rules = list(ipt_rules) ipv4_rules.extend( ["INPUT -i %s -p udp -m udp --dport 67 -j ACCEPT" % br_name, "INPUT -i %s -p tcp -m tcp --dport 67 -j ACCEPT" % br_name, "OUTPUT -o %s -p udp -m udp --dport 68 -j ACCEPT" % br_name, "POSTROUTING -o %s -p udp -m udp --dport 68 " "-j CHECKSUM --checksum-fill" % br_name]) ctr_rule = "" nat_rules = [] if "mode" in net_forward and net_forward["mode"] == "nat": nat_port = ast.literal_eval(params.get("nat_port")) p_start = nat_port["start"] p_end = nat_port["end"] ctr_rule = " -m .* RELATED,ESTABLISHED" nat_rules = [("POSTROUTING -s {0} ! -d {0} -p tcp -j MASQUERADE" " --to-ports {1}-{2}".format(net_ipv4, p_start, p_end)), ("POSTROUTING -s {0} ! -d {0} -p udp -j MASQUERADE" " --to-ports {1}-{2}".format(net_ipv4, p_start, p_end)), ("POSTROUTING -s {0} ! -d {0}" " -j MASQUERADE".format(net_ipv4))] if nat_rules: ipv4_rules.extend(nat_rules) if (net_ipv4 and "mode" in net_forward and net_forward["mode"] in ["nat", "route"]): rules = [("FORWARD -d %s%s -o %s%s -j ACCEPT" % (net_ipv4, net_dev_in, br_name, ctr_rule)), ("FORWARD -s %s -i %s%s -j ACCEPT" % (net_ipv4, br_name, net_dev_out))] ipv4_rules.extend(rules) output = to_text(process.system_output('iptables-save')) logging.debug("iptables: %s", output) if "mode" in net_forward and net_forward["mode"] == "open": if re.search(r"%s|%s" % (net_ipv4, br_name), output, re.M): test.fail("Find iptable rule for open mode") utils_libvirtd.libvirtd_restart() output_again = to_text(process.system_output('iptables-save')) if re.search(r"%s|%s" % (net_ipv4, br_name), output_again, re.M): test.fail("Find iptable rule for open mode after restart " "libvirtd") else: logging.info("Can't find iptable rule for open mode as expected") else: for ipt in ipv4_rules: if not re.search(r"%s" % ipt, output, re.M): test.fail("Can't find iptable rule:\n%s" % ipt) return ipv4_rules if check_ipv6: ipv6_rules = list(ipt_rules) ipt6_rules.extend([ ("INPUT -i %s -p udp -m udp --dport 547 -j ACCEPT" % br_name)]) if (net_ipv6 and "mode" in net_forward and net_forward["mode"] in ["nat", "route"]): rules = [("FORWARD -d %s%s -o %s -j ACCEPT" % (net_ipv6, net_dev_in, br_name)), ("FORWARD -s %s -i %s%s -j ACCEPT" % (net_ipv6, br_name, net_dev_out))] ipv6_rules.extend(rules) output = to_text(process.system_output("ip6tables-save")) logging.debug("ip6tables: %s", output) if "mode" in net_forward and net_forward["mode"] == "open": if re.search(r"%s|%s" % (net_ipv6, br_name), output, re.M): test.fail("Find ip6table rule for open mode") utils_libvirtd.libvirtd_restart() output_again = to_text(process.system_output('ip6tables-save')) if re.search(r"%s|%s" % (net_ipv6, br_name), output_again, re.M): test.fail("Find ip6table rule for open mode after restart " "libvirtd") else: for ipt in ipv6_rules: if not re.search(r"%s" % ipt, output, re.M): test.fail("Can't find ip6table rule:\n%s" % ipt) return ipv6_rules def run_ip_test(session, ip_ver): """ Check iptables on host and ipv6 address on guest """ if ip_ver == "ipv6": # Clean up iptables rules for guest to get ipv6 address session.cmd_status("ip6tables -F") # It may take some time to get the ip address def get_ip_func(): return utils_net.get_guest_ip_addr(session, iface_mac, ip_version=ip_ver) utils_misc.wait_for(get_ip_func, 5) if not get_ip_func(): utils_net.restart_guest_network(session, iface_mac, ip_version=ip_ver) utils_misc.wait_for(get_ip_func, 5) vm_ip = get_ip_func() logging.debug("Guest has ip: %s", vm_ip) if not vm_ip: test.fail("Can't find ip address on guest") ip_gateway = net_ip_address if ip_ver == "ipv6": ip_gateway = net_ipv6_address # Cleanup ip6talbes on host for ping6 test process.system("ip6tables -F") if ip_gateway and not routes: ping_s, _ = ping(dest=ip_gateway, count=5, timeout=10, session=session) if ping_s: test.fail("Failed to ping gateway address: %s" % ip_gateway) def run_guest_libvirt(session): """ Check guest libvirt network """ # Try to install required packages if "ubuntu" in vm.get_distro().lower(): pkg = "libvirt-bin" else: pkg = "libvirt" if not utils_package.package_install(pkg, session): test.error("Failed to install libvirt package on guest") # Try to load tun module first session.cmd("lsmod | grep tun || modprobe tun") # Check network state on guest cmd = ("service libvirtd restart; virsh net-info default" " | grep 'Active:.*yes'") if session.cmd_status(cmd): test.fail("'default' network isn't in active state") # Try to destroy&start default network on guest for opt in ['net-destroy', 'net-start']: cmd = "virsh %s default" % opt status, output = session.cmd_status_output(cmd) logging.debug("Run %s on guest exit %s, output %s" % (cmd, status, output)) if status: test.fail(output) if not utils_package.package_remove("libvirt*", session): test.error("Failed to remove libvirt packages on guest") start_error = "yes" == params.get("start_error", "no") define_error = "yes" == params.get("define_error", "no") restart_error = "yes" == params.get("restart_error", "no") # network specific attributes. net_name = params.get("net_name", "default") net_bridge = params.get("net_bridge", "{'name':'virbr0'}") net_domain = params.get("net_domain") net_ip_address = params.get("net_ip_address") net_ipv6_address = params.get("net_ipv6_address") net_dns_forward = params.get("net_dns_forward") net_dns_txt = params.get("net_dns_txt") net_dns_srv = params.get("net_dns_srv") net_dns_hostip = params.get("net_dns_hostip") net_dns_hostnames = params.get("net_dns_hostnames", "").split() dhcp_start_ipv4 = params.get("dhcp_start_ipv4") dhcp_end_ipv4 = params.get("dhcp_end_ipv4") dhcp_start_ipv6 = params.get("dhcp_start_ipv6") dhcp_end_ipv6 = params.get("dhcp_end_ipv6") guest_name = params.get("guest_name") guest_ipv4 = params.get("guest_ipv4") guest_ipv6 = params.get("guest_ipv6") tftp_root = params.get("tftp_root") pxe_boot = "yes" == params.get("pxe_boot", "no") routes = params.get("routes", "").split() net_bandwidth_inbound = params.get("net_bandwidth_inbound", "{}") net_bandwidth_outbound = params.get("net_bandwidth_outbound", "{}") iface_bandwidth_inbound = params.get("iface_bandwidth_inbound", "{}") iface_bandwidth_outbound = params.get("iface_bandwidth_outbound", "{}") iface_num = params.get("iface_num", "1") iface_source = params.get("iface_source", "{}") iface_rom = params.get("iface_rom") iface_boot = params.get("iface_boot") iface_model = params.get("iface_model") multiple_guests = params.get("multiple_guests") create_network = "yes" == params.get("create_network", "no") attach_iface = "yes" == params.get("attach_iface", "no") serial_login = "******" == params.get("serial_login", "no") change_iface_option = "yes" == params.get("change_iface_option", "no") test_bridge = "yes" == params.get("test_bridge", "no") test_dnsmasq = "yes" == params.get("test_dnsmasq", "no") test_dhcp_range = "yes" == params.get("test_dhcp_range", "no") test_dns_host = "yes" == params.get("test_dns_host", "no") test_qos_bandwidth = "yes" == params.get("test_qos_bandwidth", "no") test_pg_bandwidth = "yes" == params.get("test_portgroup_bandwidth", "no") test_qos_remove = "yes" == params.get("test_qos_remove", "no") test_ipv4_address = "yes" == params.get("test_ipv4_address", "no") test_ipv6_address = "yes" == params.get("test_ipv6_address", "no") test_guest_libvirt = "yes" == params.get("test_guest_libvirt", "no") net_no_bridge = "yes" == params.get("no_bridge", "no") net_no_mac = "yes" == params.get("no_mac", "no") net_no_ip = "yes" == params.get("no_ip", "no") net_with_dev = "yes" == params.get("with_dev", "no") username = params.get("username") password = params.get("password") forward = ast.literal_eval(params.get("net_forward", "{}")) boot_failure = "yes" == params.get("boot_failure", "no") ipt_rules = [] ipt6_rules = [] # Destroy VM first if vm.is_alive(): vm.destroy(gracefully=False) # Back up xml file. netxml_backup = NetworkXML.new_from_net_dumpxml("default") iface_mac = vm_xml.VMXML.get_first_mac_by_name(vm_name) params["guest_mac"] = iface_mac vmxml_backup = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) vms_list = [] if "floor" in ast.literal_eval(iface_bandwidth_inbound): if not libvirt_version.version_compare(1, 0, 1): test.cancel("Not supported Qos options 'floor'") # Enabling IPv6 forwarding with RA routes without accept_ra set to 2 # is likely to cause routes loss sysctl_cmd = 'sysctl net.ipv6.conf.all.accept_ra' original_accept_ra = to_text(process.system_output(sysctl_cmd + ' -n')) if test_ipv6_address and original_accept_ra != '2': process.system(sysctl_cmd + '=2') # Build the xml and run test. try: if test_dnsmasq: # Check the settings before modifying network xml if net_dns_forward == "no": run_dnsmasq_default_test("domain-needed", exists=False) run_dnsmasq_default_test("local", "//", exists=False) if net_domain: run_dnsmasq_default_test("domain", net_domain, exists=False) run_dnsmasq_default_test("expand-hosts", exists=False) # Prepare pxe boot directory if pxe_boot: prepare_pxe_boot() # Edit the network xml or create a new one. if create_network: net_ifs = utils_net.get_net_if(state="UP") # Check forward device is valid or not, # if it's not in host interface list, try to set # forward device to first active interface of host if ('mode' in forward and forward['mode'] in ['passthrough', 'private', 'bridge', 'macvtap'] and 'dev' in forward and forward['dev'] not in net_ifs): logging.warn("Forward device %s is not a interface" " of host, reset to %s", forward['dev'], net_ifs[0]) forward['dev'] = net_ifs[0] params["net_forward"] = str(forward) forward_iface = params.get("forward_iface") if forward_iface: interface = [x for x in forward_iface.split()] # The guest will use first interface of the list, # check if it's valid or not, if it's not in host # interface list, try to set forward interface to # first active interface of host. if interface[0] not in net_ifs: logging.warn("Forward interface %s is not a " " interface of host, reset to %s", interface[0], net_ifs[0]) interface[0] = net_ifs[0] params["forward_iface"] = " ".join(interface) netxml = libvirt.create_net_xml(net_name, params) if "mode" in forward and forward["mode"] == "open": netxml.mac = utils_net.generate_mac_address_simple() try: if net_no_bridge: netxml.del_bridge() if net_no_ip: netxml.del_ip() netxml.del_ip() if net_no_mac: netxml.del_mac() except xcepts.LibvirtXMLNotFoundError: pass if net_with_dev: net_forward = netxml.forward net_forward.update({"dev": net_ifs[0]}) netxml.forward = net_forward logging.info("netxml before define is %s", netxml) try: netxml.sync() except xcepts.LibvirtXMLError as details: logging.info(str(details)) if define_error: return else: test.fail("Failed to define network") # Check open mode network xml if "mode" in forward and forward["mode"] == "open": netxml_new = NetworkXML.new_from_net_dumpxml(net_name) logging.info("netxml after define is %s", netxml_new) try: if net_no_bridge: net_bridge = str(netxml_new.bridge) if net_no_mac: netxml_new.mac except xcepts.LibvirtXMLNotFoundError as details: test.fail("Failed to check %s xml: %s" % (net_name, details)) logging.info("mac/bridge still exist even if removed before define") # Edit the interface xml. if change_iface_option: try: modify_iface_xml() except xcepts.LibvirtXMLError as details: logging.info(str(details)) if define_error: if not str(details).count("Failed to define"): test.fail("VM sync failed msg not expected") return else: test.fail("Failed to sync VM") # Attach interface if needed if attach_iface: iface_type = params.get("iface_type", "network") for i in range(int(iface_num)): logging.info("Try to attach interface loop %s" % i) options = ("%s %s --model %s --config" % (iface_type, net_name, iface_model)) ret = virsh.attach_interface(vm_name, options, ignore_status=True) if ret.exit_status: logging.error("Command output %s" % ret.stdout.strip()) test.fail("Failed to attach-interface") if multiple_guests: # Clone more vms for testing for i in range(int(multiple_guests)): guest_name = "%s_%s" % (vm_name, i) timeout = params.get("clone_timeout", 360) utils_libguestfs.virt_clone_cmd(vm_name, guest_name, True, timeout=timeout) vms_list.append(vm.clone(guest_name)) if test_bridge: bridge = ast.literal_eval(net_bridge) br_if = utils_net.Interface(bridge['name']) if not br_if.is_up(): test.fail("Bridge interface isn't up") if test_dnsmasq: # Check dnsmasq process dnsmasq_cmd = to_text(process.system_output("ps -aux|grep dnsmasq", shell=True)) logging.debug(dnsmasq_cmd) if not re.search("dnsmasq --conf-file=/var/lib/libvirt/dnsmasq/%s.conf" % net_name, dnsmasq_cmd): test.fail("Can not find dnsmasq process or the process is not correct") # Check the settings in dnsmasq config file if net_dns_forward == "no": run_dnsmasq_default_test("domain-needed") run_dnsmasq_default_test("local", "//") if net_domain: run_dnsmasq_default_test("domain", net_domain) run_dnsmasq_default_test("expand-hosts") if net_bridge: bridge = ast.literal_eval(net_bridge) run_dnsmasq_default_test("interface", bridge['name'], name=net_name) if 'stp' in bridge and bridge['stp'] == 'on': if 'delay' in bridge and bridge['delay'] != '0': # network xml forward delay value in seconds, while on # host, check by ip command, the value is in second*100 br_delay = int(bridge['delay'])*100 logging.debug("Expect forward_delay is %s ms" % br_delay) cmd = ("ip -d link sh %s | grep 'bridge forward_delay'" % bridge['name']) out = to_text(process.system_output( cmd, shell=True, ignore_status=False)) logging.debug("bridge statistics output: %s", out) pattern = (r"\s*bridge forward_delay\s+(\d+)") match_obj = re.search(pattern, out, re.M) if not match_obj: test.fail("Can't see forward delay messages from command") elif int(match_obj.group(1)) != br_delay: test.fail("Foward delay setting can't take effect") else: logging.debug("Foward delay set successfully!") if dhcp_start_ipv4 and dhcp_end_ipv4: run_dnsmasq_default_test("dhcp-range", "%s,%s" % (dhcp_start_ipv4, dhcp_end_ipv4), name=net_name) if dhcp_start_ipv6 and dhcp_end_ipv6: run_dnsmasq_default_test("dhcp-range", "%s,%s,64" % (dhcp_start_ipv6, dhcp_end_ipv6), name=net_name) if guest_name and guest_ipv4: run_dnsmasq_host_test(iface_mac, guest_ipv4, guest_name) # check the left part in dnsmasq conf run_dnsmasq_default_test("strict-order", name=net_name) run_dnsmasq_default_test("pid-file", "/var/run/libvirt/network/%s.pid" % net_name, name=net_name) run_dnsmasq_default_test("except-interface", "lo", name=net_name) run_dnsmasq_default_test("bind-dynamic", name=net_name) run_dnsmasq_default_test("dhcp-no-override", name=net_name) if dhcp_start_ipv6 and dhcp_start_ipv4: run_dnsmasq_default_test("dhcp-lease-max", "493", name=net_name) else: range_num = int(params.get("dhcp_range", "252")) run_dnsmasq_default_test("dhcp-lease-max", str(range_num+1), name=net_name) run_dnsmasq_default_test("dhcp-hostsfile", "/var/lib/libvirt/dnsmasq/%s.hostsfile" % net_name, name=net_name) run_dnsmasq_default_test("addn-hosts", "/var/lib/libvirt/dnsmasq/%s.addnhosts" % net_name, name=net_name) if dhcp_start_ipv6: run_dnsmasq_default_test("enable-ra", name=net_name) if test_dns_host: if net_dns_txt: dns_txt = ast.literal_eval(net_dns_txt) run_dnsmasq_default_test("txt-record", "%s,%s" % (dns_txt["name"], dns_txt["value"])) if net_dns_srv: dns_srv = ast.literal_eval(net_dns_srv) run_dnsmasq_default_test("srv-host", "_%s._%s.%s,%s,%s,%s,%s" % (dns_srv["service"], dns_srv["protocol"], dns_srv["domain"], dns_srv["target"], dns_srv["port"], dns_srv["priority"], dns_srv["weight"])) if net_dns_hostip and net_dns_hostnames: run_dnsmasq_addnhosts_test(net_dns_hostip, net_dns_hostnames) # Run bandwidth test for network if test_qos_bandwidth: run_bandwidth_test(check_net=True) # Check routes if needed if routes: check_host_routes() try: # Start the VM. vm.start() if start_error: test.fail("VM started unexpectedly") if pxe_boot: # Just check network boot messages here try: vm.serial_console.read_until_output_matches( ["Loading vmlinuz", "Loading initrd.img"], utils_misc.strip_console_codes) output = vm.serial_console.get_stripped_output() logging.debug("Boot messages: %s", output) except ExpectTimeoutError as details: if boot_failure: logging.info("Fail to boot from pxe as expected") else: test.fail("Fail to boot from pxe") else: if serial_login: session = vm.wait_for_serial_login(username=username, password=password) else: session = vm.wait_for_login() if test_dhcp_range: dhcp_range = int(params.get("dhcp_range", "252")) utils_net.restart_guest_network(session, iface_mac) vm_ip = utils_net.get_guest_ip_addr(session, iface_mac) logging.debug("Guest has ip: %s", vm_ip) if not vm_ip and dhcp_range: test.fail("Guest has invalid ip address") elif vm_ip and not dhcp_range: test.fail("Guest has ip address: %s" % vm_ip) dhcp_range = dhcp_range - 1 for vms in vms_list: # Start other VMs. vms.start() sess = vms.wait_for_serial_login() vms_mac = vms.get_virsh_mac_address() # restart guest network to get ip addr utils_net.restart_guest_network(sess, vms_mac) vms_ip = utils_net.get_guest_ip_addr(sess, vms_mac) if not vms_ip and dhcp_range: test.fail("Guest has invalid ip address") elif vms_ip and not dhcp_range: # Get IP address on guest should return Null # if it exceeds the dhcp range test.fail("Guest has ip address: %s" % vms_ip) dhcp_range = dhcp_range - 1 if vms_ip: ping_s, _ = ping(dest=vm_ip, count=5, timeout=10, session=sess) if ping_s: test.fail("Failed to ping, src: %s, " "dst: %s" % (vms_ip, vm_ip)) sess.close() # Check dnsmasq settings if take affect in guest if guest_ipv4: check_name_ip(session) # Run bandwidth test for interface if test_qos_bandwidth: run_bandwidth_test(check_iface=True) # Run bandwidth test for portgroup if test_pg_bandwidth: pg_bandwidth_inbound = params.get( "portgroup_bandwidth_inbound", "").split() pg_bandwidth_outbound = params.get( "portgroup_bandwidth_outbound", "").split() pg_name = params.get("portgroup_name", "").split() pg_default = params.get("portgroup_default", "").split() iface_inbound = ast.literal_eval(iface_bandwidth_inbound) iface_outbound = ast.literal_eval(iface_bandwidth_outbound) iface_name = libvirt.get_ifname_host(vm_name, iface_mac) if_source = ast.literal_eval(iface_source) if "portgroup" in if_source: pg = if_source["portgroup"] else: pg = "default" for (name, df, bw_ib, bw_ob) in zip(pg_name, pg_default, pg_bandwidth_inbound, pg_bandwidth_outbound): if pg == name: inbound = ast.literal_eval(bw_ib) outbound = ast.literal_eval(bw_ob) elif pg == "default" and df == "yes": inbound = ast.literal_eval(bw_ib) outbound = ast.literal_eval(bw_ob) else: continue # Interface bandwidth settings will # overwriting portgroup settings if iface_inbound: inbound = iface_inbound if iface_outbound: outbound = iface_outbound check_class_rules(iface_name, "1:1", inbound) check_filter_rules(iface_name, outbound) if test_qos_remove: # Remove the bandwidth settings in network xml logging.debug("Removing network bandwidth settings...") netxml_backup.sync() vm.destroy(gracefully=False) # Should fail to start vm vm.start() if restart_error: test.fail("VM started unexpectedly") if test_ipv6_address: ipt6_rules = check_ipt_rules(check_ipv4=False, check_ipv6=True) if not ("mode" in forward and forward["mode"] == "open"): run_ip_test(session, "ipv6") if test_ipv4_address: ipt_rules = check_ipt_rules(check_ipv4=True) if not ("mode" in forward and forward["mode"] == "open"): run_ip_test(session, "ipv4") if test_guest_libvirt: run_guest_libvirt(session) session.close() except virt_vm.VMStartError as details: logging.info(str(details)) if not (start_error or restart_error): test.fail('VM failed to start:\n%s' % details) # Destroy created network and check iptable rules if net_name != "default": virsh.net_destroy(net_name) if ipt_rules: output_des = to_text(process.system_output('iptables-save')) for ipt in ipt_rules: if re.search(r"%s" % ipt, output_des, re.M): test.fail("Find iptable rule %s after net destroyed" % ipt) if ipt6_rules: output_des = to_text(process.system_output('ip6tables-save')) for ipt in ipt6_rules: if re.search(r"%s" % ipt, output_des, re.M): test.fail("Find ip6table rule %s after net destroyed" % ipt) finally: # Recover VM. if vm.is_alive(): vm.destroy(gracefully=False) for vms in vms_list: virsh.remove_domain(vms.name, "--remove-all-storage") logging.info("Restoring network...") if net_name == "default": netxml_backup.sync() else: # Destroy and undefine new created network virsh.net_destroy(net_name) virsh.net_undefine(net_name) vmxml_backup.sync() if test_ipv6_address and original_accept_ra != '2': process.system(sysctl_cmd + "=%s" % original_accept_ra)
def run(test, params, env): """ Test start domain with nwfilter rules. 1) Prepare parameters. 2) Prepare nwfilter rule and update domain interface to apply. 3) Start domain and check rule. 4) Clean env """ # Prepare parameters filter_name = params.get("filter_name", "testcase") exist_filter = params.get("exist_filter", "no-mac-spoofing") status_error = "yes" == params.get("status_error", "no") mount_noexec_tmp = "yes" == params.get("mount_noexec_tmp", "no") kill_libvirtd = "yes" == params.get("kill_libvirtd", "no") bug_url = params.get("bug_url", "") ipset_command = params.get("ipset_command") vm_name = params.get("main_vm") vm = env.get_vm(vm_name) username = params.get("username") password = params.get("password") need_vm2 = "yes" == params.get("need_vm2", "no") add_vm_name = params.get("add_vm_name", "vm2") vms = [vm] dst_outside = params.get("dst_outside", "www.google.com") ping_timeout = int(params.get("ping_timeout", "10")) # Prepare vm filterref parameters dict list filter_param_list = [] params_key = [] for i in params.keys(): if 'parameter_name_' in i: params_key.append(i) params_key.sort() for i in range(len(params_key)): params_dict = {} params_dict['name'] = params[params_key[i]] params_dict['value'] = params['parameter_value_%s' % i] if params_dict['value'] == "MAC_of_virbr0": virbr0_info = process.run("ip a | grep virbr0: -A1", shell=True).stdout_text.strip() virbr0_mac = re.search( r'link/ether\s+(\w{2}:\w{2}:\w{2}:\w{2}:\w{2}:\w{2})', virbr0_info, re.M | re.I).group(1) params_dict['value'] = virbr0_mac logging.debug("params_dict['value'] is %s " % params_dict['value']) filter_param_list.append(params_dict) filterref_dict = {} filterref_dict['name'] = filter_name filterref_dict['parameters'] = filter_param_list params['filter_uuid'] = process.run("uuidgen", ignore_status=True, shell=True).stdout_text.strip() # get all the check commands and corresponding expected results form config file and make a dictionary cmd_list_ = params.get('check_cmd', '') if cmd_list_: cmd_list = cmd_list_.split(',') expect_res = params.get('expect_match', '').split(',') logging.debug("cmd_list is %s" % cmd_list) logging.debug("expect_res is %s" % expect_res) cmd_result_dict = dict(zip(cmd_list, expect_res)) logging.debug("the check dict is %s" % cmd_result_dict) # backup vm xml vmxml_backup = libvirt_xml.VMXML.new_from_inactive_dumpxml(vm_name) libvirtd = utils_libvirtd.Libvirtd("virtqemud") device_name = None def check_nwfilter_rules(check_cmd, expect_match): """"check the nwfilter corresponding rule is added by iptables commands""" ret = utils_misc.wait_for(lambda: not process.system( check_cmd, ignore_status=True, shell=True), timeout=30) if not ret: test.fail("Rum command '%s' failed" % check_cmd) # This change anchors nwfilter_vm_start.possitive_test.new_filter.variable_notation case # The matched destination could be ip address or hostname if "iptables -L" in check_cmd and expect_match and 'ACCEPT' in expect_match: # ip address that need to be replaced replace_param = params.get("parameter_value_2") # Get hostname by ip address. hostname_info = None try: hostname_info = socket.gethostbyaddr(replace_param) except socket.error as e: logging.info( "Failed to get hostname from ip address with error: %s", str(e)) if hostname_info: # String is used to replace ip address replace_with = "%s|%s" % (replace_param, hostname_info[0]) expect_match = r"%s" % expect_match.replace( replace_param, replace_with) logging.debug("final iptables match string:%s", expect_match) out = astring.to_text( process.system_output(check_cmd, ignore_status=False, shell=True)) if expect_match and not re.search(expect_match, out): test.fail("'%s' not found in output: %s" % (expect_match, out)) def clean_up_dirty_nwfilter_binding(): cmd_result = virsh.nwfilter_binding_list(debug=True) binding_list = cmd_result.stdout_text.strip().splitlines() binding_list = binding_list[2:] result = [] # If binding list is not empty. if binding_list: for line in binding_list: # Split on whitespace, assume 1 column linesplit = line.split(None, 1) result.append(linesplit[0]) logging.info("nwfilter binding list is: %s", result) for binding_uuid in result: try: virsh.nwfilter_binding_delete(binding_uuid) except Exception as e: logging.error( "Exception thrown while undefining nwfilter-binding: %s", str(e)) raise try: # Clean up dirty nwfilter binding if there are. clean_up_dirty_nwfilter_binding() rule = params.get("rule") if rule: # Add pre-check whether nwfilter exists or not since # utlv.create_nwfilter_xml will fail if there is no any nwfilter exists nwfilter_list = libvirt_nwfilter.get_nwfilter_list() if not nwfilter_list: test.error("There is no any nwfilter existed on the host") # Create new filter xml filterxml = utlv.create_nwfilter_xml(params) # Define filter xml virsh.nwfilter_define(filterxml.xml, debug=True) # Update first vm interface with filter vmxml = libvirt_xml.VMXML.new_from_inactive_dumpxml(vm_name) iface_xml = vmxml.get_devices('interface')[0] vmxml.del_device(iface_xml) new_iface = interface.Interface('network') new_iface.xml = iface_xml.xml new_filterref = new_iface.new_filterref(**filterref_dict) new_iface.filterref = new_filterref logging.debug("new interface xml is: %s" % new_iface) vmxml.add_device(new_iface) vmxml.sync() if mount_noexec_tmp: device_name = utlv.setup_or_cleanup_iscsi(is_setup=True) utlv.mkfs(device_name, 'ext4') cmd = "mount %s /tmp -o noexec,nosuid" % device_name process.run(cmd, shell=True) if ipset_command: pkg = "ipset" if not utils_package.package_install(pkg): test.cancel("Can't install ipset on host") process.run(ipset_command, shell=True) # Run command try: vm.start() if not mount_noexec_tmp: vm.wait_for_serial_login(username=username, password=password) vmxml = libvirt_xml.VMXML.new_from_dumpxml(vm_name) iface_xml = vmxml.get_devices('interface')[0] iface_target = iface_xml.target['dev'] iface_mac = iface_xml.mac_address logging.debug("iface target dev name is %s", iface_target) # Check iptables or ebtables on host if need_vm2: # Clone more vm for testing result = virsh.dom_list('--inactive').stdout_text if add_vm_name in result: logging.debug("%s is already exists!" % add_vm_name) vms.append(env.get_vm(add_vm_name)) else: vm.destroy() ret_clone = utils_libguestfs.virt_clone_cmd(vm_name, add_vm_name, True, timeout=360) if ret_clone.exit_status: test.fail("Error when clone a second vm!") vms.append(vm.clone(add_vm_name)) vm.start() vm2 = vms[1] logging.debug("Now the vms is: %s", [dom.name for dom in vms]) # update the vm2 interface with the nwfilter logging.debug("filter_params_list is %s" % filter_param_list) iface_dict = { "filter": filter_name, "filter_parameters": filter_param_list, "del_mac": True } if vm2.is_alive(): vm2.destroy() utlv.modify_vm_iface(vm2.name, "update_iface", iface_dict) vmxml = libvirt_xml.VMXML.new_from_inactive_dumpxml(vm2.name) iface_xml = vmxml.get_devices('interface')[0] logging.debug("iface_xml for vm2 is %s" % iface_xml) vm2.start() vm2_session = vm2.wait_for_serial_login() vm2_mac = vm2.get_mac_address() vm2_ip = utils_net.get_guest_ip_addr(vm2_session, vm2_mac) vm.session = vm.wait_for_serial_login() # test network functions, the 2 vms can not access to each other gateway_ip = utils_net.get_ip_address_by_interface("virbr0") status1, output1 = utils_net.ping(dest=vm2_ip, count='3', timeout=ping_timeout, session=vm.session, force_ipv4=True) status2, output2 = utils_net.ping(dest=gateway_ip, count='3', timeout=ping_timeout, session=vm.session, force_ipv4=True) status3, output3 = utils_net.ping(dest=dst_outside, count='3', timeout=ping_timeout, session=vm.session, force_ipv4=True) if not status1: test.fail( "vm with clean-traffic-gateway ping succeed to %s %s, but it is not expected!" % (vm2.name, vm2_ip)) if status2 or status3: test.fail("vm ping failed! check %s \n %s" % (output2, output3)) if cmd_list_: loop = 0 for check_cmd_, expect_match_ in cmd_result_dict.items(): check_cmd = check_cmd_.strip() expect_match = expect_match_.strip() if "DEVNAME" in check_cmd: check_cmd = check_cmd.replace("DEVNAME", iface_target) if "VMMAC" in expect_match: expect_match = expect_match.replace("VMMAC", iface_mac) logging.debug( "the check_cmd is %s, and expected result is %s" % (check_cmd, expect_match)) check_nwfilter_rules(check_cmd, expect_match) loop += 1 except virt_vm.VMStartError as e: # Starting VM failed. if not status_error: test.fail("Test failed in positive case.\n error:" " %s\n%s" % (e, bug_url)) if kill_libvirtd: daemon_name = libvirtd.service_name pid = process.run('pidof %s' % daemon_name, shell=True).stdout_text.strip() cmd = "kill -s TERM %s" % pid process.run(cmd, shell=True) ret = utils_misc.wait_for(lambda: not libvirtd.is_running(), timeout=30) # After libvirt 5.6.0, libvirtd is using systemd socket activation by default if not ret and not libvirt_version.version_compare(5, 6, 0): test.fail("Failed to kill libvirtd. %s" % bug_url) finally: if kill_libvirtd: libvirtd.restart() # Clean env if vm.is_alive(): vm.destroy(gracefully=False) # Recover xml of vm. vmxml_backup.sync() # Undefine created filter except clean-traffic as it is built-in nwfilter if filter_name != exist_filter and filter_name != 'clean-traffic': virsh.nwfilter_undefine(filter_name, debug=True) if mount_noexec_tmp: if device_name: process.run("umount -l %s" % device_name, ignore_status=True, shell=True) utlv.setup_or_cleanup_iscsi(is_setup=False) if ipset_command: process.run("ipset destroy blacklist", shell=True) # Remove additional vms if need_vm2: result = virsh.dom_list("--all").stdout_text if add_vm_name in result: virsh.remove_domain(add_vm_name, "--remove-all-storage")
def run(test, params, env): """ Test storage pool and volumes with applications such as: install vms, attached to vms... """ pool_type = params.get("pool_type") pool_name = "test_%s_app" % pool_type pool_target = params.get("pool_target") emulated_img = params.get("emulated_image", "emulated-image") volume_count = int(params.get("volume_count", 1)) volume_size = params.get("volume_size", "1G") emulated_size = "%sG" % (volume_count * int(volume_size[:-1]) + 1) application = params.get("application", "install") disk_target = params.get("disk_target", "vdb") test_message = params.get("test_message", "") vm_name = params.get("main_vm", "avocado-vt-vm1") block_device = params.get("block_device", "/DEV/EXAMPLE") if application == "install": cdrom_path = os.path.join(data_dir.get_data_dir(), params.get("cdrom_cd1")) if not os.path.exists(cdrom_path): raise error.TestNAError("Can't find installation cdrom:%s" % cdrom_path) # Get a nonexist domain name vm_name = "vol_install_test" try: pvtest = utlv.PoolVolumeTest(test, params) pvtest.pre_pool(pool_name, pool_type, pool_target, emulated_img, image_size=emulated_size, pre_disk_vol=[volume_size], device_name=block_device) logging.debug("Current pools:\n%s", libvirt_storage.StoragePool().list_pools()) new_pool = libvirt_storage.PoolVolume(pool_name) if pool_type == "disk": volumes = new_pool.list_volumes() logging.debug("Current volumes:%s", volumes) else: volumes = create_volumes(new_pool, volume_count, volume_size) if application == "attach": vm = env.get_vm(vm_name) session = vm.wait_for_login() virsh.attach_disk(vm_name, volumes.values()[volume_count - 1], disk_target) vm_attach_device = "/dev/%s" % disk_target if session.cmd_status("which parted"): # No parted command, check device only if session.cmd_status("ls %s" % vm_attach_device): raise error.TestFail("Didn't find attached device:%s" % vm_attach_device) return # Test if attached disk can be used normally utlv.mk_part(vm_attach_device, session=session) session.cmd("mkfs.ext4 %s1" % vm_attach_device) session.cmd("mount %s1 /mnt" % vm_attach_device) session.cmd("echo %s > /mnt/test" % test_message) output = session.cmd_output("cat /mnt/test").strip() if output != test_message: raise error.TestFail("%s cannot be used normally!" % vm_attach_device) elif application == "install": # Get a nonexist domain name anyway while virsh.domain_exists(vm_name): vm_name += "_test" # Prepare installation parameters params["main_vm"] = vm_name vm = env.create_vm("libvirt", None, vm_name, params, test.bindir) env.register_vm(vm_name, vm) params["image_name"] = volumes.values()[volume_count - 1] params["image_format"] = "raw" params['force_create_image'] = "yes" params['remove_image'] = "yes" params['shutdown_cleanly'] = "yes" params['shutdown_cleanly_timeout'] = 120 params['guest_port_unattended_install'] = 12323 params['inactivity_watcher'] = "error" params['inactivity_treshold'] = 1800 params['image_verify_bootable'] = "no" params['unattended_delivery_method'] = "cdrom" params['drive_index_unattended'] = 1 params['drive_index_cd1'] = 2 params['boot_once'] = "d" params['medium'] = "cdrom" params['wait_no_ack'] = "yes" params['image_raw_device'] = "yes" params['backup_image_before_testing'] = "no" params['kernel_params'] = ("ks=cdrom nicdelay=60 " "console=ttyS0,115200 console=tty0") params['cdroms'] = "unattended cd1" params['redirs'] += " unattended_install" selinux_mode = None try: selinux_mode = utils_selinux.get_status() utils_selinux.set_status("permissive") try: unattended_install.run(test, params, env) except process.CmdError, detail: raise error.TestFail("Guest install failed:%s" % detail) finally: if selinux_mode is not None: utils_selinux.set_status(selinux_mode) env.unregister_vm(vm_name) finally: try: if application == "install": if virsh.domain_exists(vm_name): virsh.remove_domain(vm_name) elif application == "attach": virsh.detach_disk(vm_name, disk_target) finally: pvtest.cleanup_pool(pool_name, pool_type, pool_target, emulated_img, device_name=block_device)
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 params.itervalues(): if "V2V_EXAMPLE" in v: raise exceptions.TestSkipError("Please set real value for %s" % v) vm_name = params.get("main_vm", "EXAMPLE") new_vm_name = params.get("new_vm_name") input_mode = params.get("input_mode") 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") output_mode = params.get("output_mode") output_storage = params.get("output_storage", "default") disk_img = params.get("input_disk_image", "") nfs_storage = params.get("nfs_storage") mnt_point = params.get("mount_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_path", "v2v_pool") emulated_img = params.get("emulated_image_path", "v2v-emulated-img") pvt = utlv.PoolVolumeTest(test, params) new_v2v_user = False restore_image_owner = False address_cache = env.get('address_cache') params['vmcheck_flag'] = False checkpoint = params.get('checkpoint', '') def create_pool(): """ Create libvirt pool as the output storage """ if output_uri == "qemu:///session": target_path = os.path.join("/home", v2v_user, pool_target) cmd = su_cmd + "'mkdir %s'" % target_path process.system(cmd, verbose=True) cmd = su_cmd + "'virsh pool-create-as %s dir" % pool_name cmd += " --target %s'" % target_path process.system(cmd, verbose=True) else: pvt.pre_pool(pool_name, pool_type, pool_target, emulated_img) def cleanup_pool(): """ Clean up libvirt pool """ if output_uri == "qemu:///session": cmd = su_cmd + "'virsh pool-destroy %s'" % pool_name process.system(cmd, verbose=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\sconvert\s.+\s'(\S+)'\n", output) if len(tmp_target) < 1: raise exceptions.TestError("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 = 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: raise exceptions.TestFail("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): raise exceptions.TestError("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: raise exceptions.TestFail("%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: raise exceptions.TestFail("%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: raise exceptions.TestFail("%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: raise exceptions.TestFail("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: raise exceptions.TestFail("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: raise exceptions.TestFail("Not find message: %s" % init_msg) def check_result(cmd, result, status_error): """ Check virt-v2v command result """ utlv.check_exit_status(result, status_error) output = result.stdout + result.stderr 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 if v2v_start and line > 72: raise exceptions.TestFail('Error log longer than 72 ' 'charactors: %s', line) else: error_map = { 'conflict_options': ['option used more than once'], 'xen_no_output_format': ['The input metadata did not define' ' the disk format'] } if not utils_v2v.check_log(output, error_map[checkpoint]): raise exceptions.TestFail('Not found error message %s' % error_map[checkpoint]) else: if output_mode == "rhev" and checkpoint != 'quiet': ovf = get_ovf_content(output) logging.debug("ovf content: %s", 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) check_image(img_path, "allocation", expected_mode) if '-of' in cmd and '--no-copy' not in cmd and checkpoint != 'quiet': 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): raise exceptions.TestFail("Import VM failed") else: params['vmcheck_flag'] = True if output_mode == "libvirt": if "qemu:///session" not in v2v_options: virsh.start(vm_name, debug=True, ignore_status=False) if checkpoint == 'quiet': if len(output.strip()) != 0: raise exceptions.TestFail('Output is not empty in quiet mode') backup_xml = None vdsm_domain_dir, vdsm_image_dir, vdsm_vm_dir = ("", "", "") try: # 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) input_option = "-i %s -ic %s %s" % (input_mode, ic_uri, vm_name) # 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 in ['libvirtxml', 'ova']: raise exceptions.TestNAError("Unsupported input mode: %s" % input_mode) else: raise exceptions.TestError("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 -os %s" % (output_mode, output_storage) output_format = params.get("output_format") if output_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"): raise exceptions.TestError("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.mkdir(vdsm_domain_dir) os.mkdir(vdsm_image_dir) os.mkdir(vdsm_vm_dir) # Output more messages except quiet mode if checkpoint == 'quiet': v2v_options += ' -q' elif checkpoint == 'length_of_error': pass else: v2v_options += " -v -x" # Prepare for libvirt unprivileged user session connection if "qemu:///session" in v2v_options: 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": # Change the image owner and group ori_owner = os.stat(disk_img).st_uid ori_group = os.stat(disk_img).st_uid os.chown(disk_img, user_info.pw_uid, user_info.pw_gid) restore_image_owner = True else: raise exceptions.TestNAError("Only support convert local disk") # Setup ssh-agent access to xen hypervisor if hypervisor == 'xen': os.environ['LIBGUESTFS_BACKEND'] = 'direct' user = params.get("xen_host_user", "root") passwd = params.get("xen_host_passwd", "redhat") logging.info("set up ssh-agent access ") ssh_key.setup_ssh_key(remote_host, user=user, port=22, password=passwd) utils_misc.add_identities_into_ssh_agent() # 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': os.environ['LIBGUESTFS_BACKEND'] = 'direct' vpx_passwd = params.get("vpx_passwd") vpx_passwd_file = os.path.join(test.tmpdir, "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 += " --password-file %s" % vpx_passwd_file # Create libvirt dir pool if output_mode == "libvirt": create_pool() # Running virt-v2v command cmd = "%s %s %s %s" % (utils_v2v.V2V_EXEC, input_option, output_option, v2v_options) if v2v_user: cmd = su_cmd + "'%s'" % cmd 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 == "xen": process.run("ssh-agent -k") if hypervisor == "esx": process.run("rm -rf %s" % vpx_passwd_file) 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: cmd = su_cmd + "'virsh undefine %s'" % vm_name process.system(cmd) else: virsh.remove_domain(vm_name) cleanup_pool() vmcheck_flag = params.get("vmcheck_flag") if vmcheck_flag: vmcheck = utils_v2v.VMCheck(test, params, env) vmcheck.cleanup() if new_v2v_user: process.system("userdel -f %s" % v2v_user) if restore_image_owner: os.chown(disk_img, ori_owner, ori_group) if backup_xml: backup_xml.sync()
def run(test, params, env): """ Test interafce xml options. 1.Prepare test environment,destroy or suspend a VM. 2.Edit xml and start the domain. 3.Perform test operation. 4.Recover test environment. 5.Confirm the test result. """ vm_name = params.get("main_vm") vm = env.get_vm(vm_name) def prepare_pxe_boot(): """ Prepare tftp server and pxe boot files """ pkg_list = ["syslinux", "tftp-server", "tftp", "ipxe-roms-qemu", "wget"] # Try to install required packages if not utils_misc.yum_install(pkg_list): raise error.TestNAError("Failed ot install " "required packages") boot_initrd = params.get("boot_initrd") boot_vmlinuz = params.get("boot_vmlinuz") # Download pxe boot images utils.run("wget %s -O %s/initrd.img" % (boot_initrd, tftp_root)) utils.run("wget %s -O %s/vmlinuz" % (boot_vmlinuz, tftp_root)) utils.run("cp -f /usr/share/syslinux/pxelinux.0 {0};" " mkdir -m 777 -p {0}/pxelinux.cfg".format(tftp_root)) pxe_file = "%s/pxelinux.cfg/default" % tftp_root boot_txt = """ DISPLAY boot.txt DEFAULT rhel LABEL rhel kernel vmlinuz append initrd=initrd.img PROMPT 1 TIMEOUT 3""" with open(pxe_file, 'w') as p_file: p_file.write(boot_txt) def modify_iface_xml(): """ Modify interface xml options """ vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) if pxe_boot: # Config boot console for pxe boot osxml = vm_xml.VMOSXML() osxml.type = vmxml.os.type osxml.arch = vmxml.os.arch osxml.machine = vmxml.os.machine osxml.loader = "/usr/share/seabios/bios.bin" osxml.bios_useserial = "yes" osxml.bios_reboot_timeout = "-1" osxml.boots = ['network'] del vmxml.os vmxml.os = osxml xml_devices = vmxml.devices iface_index = xml_devices.index( xml_devices.by_device_tag("interface")[0]) iface = xml_devices[iface_index] iface_bandwidth = {} iface_inbound = eval(iface_bandwidth_inbound) iface_outbound = eval(iface_bandwidth_outbound) if iface_inbound: iface_bandwidth["inbound"] = iface_inbound if iface_outbound: iface_bandwidth["outbound"] = iface_outbound if iface_bandwidth: bandwidth = iface.new_bandwidth(**iface_bandwidth) iface.bandwidth = bandwidth iface_source = params.get("iface_source") if iface_source: source = eval(iface_source) if source: iface.source = source logging.debug("New interface xml file: %s", iface) vmxml.devices = xml_devices vmxml.xmltreefile.write() vmxml.sync() def run_dnsmasq_default_test(key, value=None, exists=True): """ Test dnsmasq configuration. """ conf_file = "/var/lib/libvirt/dnsmasq/default.conf" configs = "" with open(conf_file) as f: configs = f.read() logging.debug("configs in file %s: %s", conf_file, configs) if value: config = "%s=%s" % (key, value) else: config = key if not configs.count(config): if exists: raise error.TestFail("Can't find %s=%s in configuration" " file" % (key, value)) else: if not exists: raise error.TestFail("Found %s=%s in configuration" " file" % (key, value)) def run_dnsmasq_addnhosts_test(hostip, hostnames): """ Test host ip and names configuration """ conf_file = "/var/lib/libvirt/dnsmasq/default.addnhosts" hosts_re = ".*".join(hostnames) configs = "" with open(conf_file) as f: configs = f.read() logging.debug("configs in file %s: %s", conf_file, configs) if not re.search(r"%s.*%s" % (hostip, hosts_re), configs, re.M): raise error.TestFail("Can't find '%s' in configuration" " file" % hostip) def run_dnsmasq_host_test(iface_mac, guest_ip, guest_name): """ Test host name and ip configuration for dnsmasq """ conf_file = "/var/lib/libvirt/dnsmasq/default.hostsfile" config = "%s,%s,%s" % (iface_mac, guest_ip, guest_name) configs = "" with open(conf_file) as f: configs = f.read() logging.debug("configs in file %s: %s", conf_file, configs) if not configs.count(config): raise error.TestFail("Can't find host configuration" " in file %s" % conf_file) def check_class_rules(ifname, rule_id, bandwidth): """ Check bandwidth settings via 'tc class' output """ cmd = "tc class show dev %s" % ifname class_output = utils.run(cmd).stdout logging.debug("Bandwidth class output: %s", class_output) class_pattern = (r"class htb %s.*rate (\d+)Kbit ceil" " (\d+)Kbit burst (\d+)(K?M?)b.*" % rule_id) se = re.search(class_pattern, class_output, re.M) if not se: raise error.TestFail("Can't find outbound setting" " for htb %s" % rule_id) logging.debug("bandwidth from tc output:%s" % str(se.groups())) ceil = None if bandwidth.has_key("floor"): ceil = int(bandwidth["floor"]) * 8 elif bandwidth.has_key("average"): ceil = int(bandwidth["average"]) * 8 if ceil: assert int(se.group(1)) == ceil if bandwidth.has_key("peak"): assert int(se.group(2)) == int(bandwidth["peak"]) * 8 if bandwidth.has_key("burst"): if se.group(4) == 'M': tc_burst = int(se.group(3)) * 1024 else: tc_burst = int(se.group(3)) assert tc_burst == int(bandwidth["burst"]) def check_filter_rules(ifname, bandwidth): """ Check bandwidth settings via 'tc filter' output """ cmd = "tc -d filter show dev %s parent ffff:" % ifname filter_output = utils.run(cmd).stdout logging.debug("Bandwidth filter output: %s", filter_output) if not filter_output.count("filter protocol all pref"): raise error.TestFail("Can't find 'protocol all' settings" " in filter rules") filter_pattern = ".*police.*rate (\d+)Kbit burst (\d+)Kb.*" se = re.search(r"%s" % filter_pattern, filter_output, re.M) if not se: raise error.TestFail("Can't find any filter policy") logging.debug("bandwidth from tc output:%s" % str(se.groups())) if bandwidth.has_key("average"): assert int(se.group(1)) == int(bandwidth["average"]) * 8 if bandwidth.has_key("burst"): assert int(se.group(2)) == int(bandwidth["burst"]) def run_bandwidth_test(check_net=False, check_iface=False): """ Test bandwidth option for network or interface by tc command. """ iface_inbound = eval(iface_bandwidth_inbound) iface_outbound = eval(iface_bandwidth_outbound) net_inbound = eval(net_bandwidth_inbound) net_outbound = eval(net_bandwidth_outbound) net_bridge_name = eval(net_bridge)["name"] iface_name = libvirt.get_ifname_host(vm_name, iface_mac) try: if check_net and net_inbound: # Check qdisc rules cmd = "tc -d qdisc show dev %s" % net_bridge_name qdisc_output = utils.run(cmd).stdout logging.debug("Bandwidth qdisc output: %s", qdisc_output) if not qdisc_output.count("qdisc ingress ffff:"): raise error.TestFail("Can't find ingress setting") check_class_rules(net_bridge_name, "1:1", {"average": net_inbound["average"], "peak": net_inbound["peak"]}) check_class_rules(net_bridge_name, "1:2", net_inbound) # Check filter rules on bridge interface if check_net and net_outbound: check_filter_rules(net_bridge_name, net_outbound) # Check class rules on interface inbound settings if check_iface and iface_inbound: check_class_rules(iface_name, "1:1", {'average': iface_inbound['average'], 'peak': iface_inbound['peak'], 'burst': iface_inbound['burst']}) if iface_inbound.has_key("floor"): check_class_rules(net_bridge_name, "1:3", {'floor': iface_inbound["floor"]}) # Check filter rules on interface outbound settings if check_iface and iface_outbound: check_filter_rules(iface_name, iface_outbound) except AssertionError: utils.log_last_traceback() raise error.TestFail("Failed to check network bandwidth") def check_name_ip(session): """ Check dns resolving on guest """ # Check if bind-utils is installed if not utils_misc.yum_install(['bind-utils'], session): raise error.TestNAError("Failed to install bind-utils" " on guest") # Run host command to check if hostname can be resolved if not guest_ipv4 and not guest_ipv6: raise error.TestFail("No ip address found from parameters") guest_ip = guest_ipv4 if guest_ipv4 else guest_ipv6 cmd = "host %s | grep %s" % (guest_name, guest_ip) if session.cmd_status(cmd): raise error.TestFail("Can't resolve name %s on guest" % guest_name) def check_ipt_rules(check_ipv4=True, check_ipv6=False): """ Check iptables for network/interface """ br_name = eval(net_bridge)["name"] net_forward = eval(params.get("net_forward", "{}")) net_ipv4 = params.get("net_ipv4") net_ipv6 = params.get("net_ipv6") ipt_rules = ("FORWARD -i {0} -o {0} -j ACCEPT".format(br_name), "FORWARD -o %s -j REJECT --reject-with icmp" % br_name, "FORWARD -i %s -j REJECT --reject-with icmp" % br_name) net_dev_in = "" net_dev_out = "" if net_forward.has_key("dev"): net_dev_in = " -i %s" % net_forward["dev"] net_dev_out = " -o %s" % net_forward["dev"] if check_ipv4: ipv4_rules = list(ipt_rules) ctr_rule = "" nat_rules = [] if net_forward.has_key("mode") and net_forward["mode"] == "nat": nat_port = eval(params.get("nat_port")) p_start = nat_port["start"] p_end = nat_port["end"] ctr_rule = " -m conntrack --ctstate RELATED,ESTABLISHED" nat_rules = ["POSTROUTING -s %s -d 224.0.0.0/24 -j RETURN" % net_ipv4, "POSTROUTING -s %s -d 255.255.255.255/32 -j RETURN" % net_ipv4, ("POSTROUTING -s {0} ! -d {0} -p tcp -j MASQUERADE" " --to-ports {1}-{2}".format(net_ipv4, p_start, p_end)), ("POSTROUTING -s {0} ! -d {0} -p udp -j MASQUERADE" " --to-ports {1}-{2}".format(net_ipv4, p_start, p_end)), ("POSTROUTING -s {0} ! -d {0} -p udp" " -j MASQUERADE".format(net_ipv4))] if nat_rules: ipv4_rules.extend(nat_rules) if (net_ipv4 and net_forward.has_key("mode") and net_forward["mode"] in ["nat", "route"]): rules = [("FORWARD -d %s%s -o %s%s -j ACCEPT" % (net_ipv4, net_dev_in, br_name, ctr_rule)), ("FORWARD -s %s -i %s%s -j ACCEPT" % (net_ipv4, br_name, net_dev_out))] ipv4_rules.extend(rules) output = utils.run("iptables-save").stdout.strip() logging.debug("iptables: %s", output) for ipt in ipv4_rules: if not output.count(ipt): raise error.TestFail("Can't find iptable rule:\n%s" % ipt) if check_ipv6: ipv6_rules = list(ipt_rules) if (net_ipv6 and net_forward.has_key("mode") and net_forward["mode"] in ["nat", "route"]): rules = [("FORWARD -d %s%s -o %s -j ACCEPT" % (net_ipv6, net_dev_in, br_name)), ("FORWARD -s %s -i %s%s -j ACCEPT" % (net_ipv6, br_name, net_dev_out))] ipv6_rules.extend(rules) output = utils.run("ip6tables-save").stdout.strip() logging.debug("iptables: %s", output) for ipt in ipv6_rules: if not output.count(ipt): raise error.TestFail("Can't find ipbtable rule:\n%s" % ipt) def run_ip_test(session, ip_ver): """ Check iptables on host and ipv6 address on guest """ if ip_ver == "ipv6": # Clean up iptables rules for guest to get ipv6 address session.cmd_status("ip6tables -F") utils_net.restart_guest_network(session, iface_mac, ip_version=ip_ver) # It may take some time to get the ip address def get_ip_func(): return utils_net.get_guest_ip_addr(session, iface_mac, ip_version=ip_ver) utils_misc.wait_for(get_ip_func, 10) vm_ip = get_ip_func() logging.debug("Guest has ip: %s", vm_ip) if not vm_ip: raise error.TestFail("Can't find ip address on guest") ping_cmd = "ping -c 5" ip_gateway = net_ip_address if ip_ver == "ipv6": ping_cmd = "ping6 -c 5" ip_gateway = net_ipv6_address if ip_gateway: if utils.system("%s %s" % (ping_cmd, ip_gateway), ignore_status=True): raise error.TestFail("Failed to ping gateway address: %s" % ip_gateway) def run_guest_libvirt(session): """ Check guest libvirt network """ # Try to install required packages if not utils_misc.yum_install(['libvirt'], session): raise error.TestNAError("Failed ot install libvirt" " package on guest") result = True # Check network state on guest cmd = ("service libvirtd restart; virsh net-info default" " | grep 'Active:.*no'") if session.cmd_status(cmd): result = False logging.error("Default network isn't in inactive state") # Try to start default network on guest, check error messages if result: cmd = "virsh net-start default" status, output = session.cmd_status_output(cmd) logging.debug("Run command on guest exit %s, output %s" % (status, output)) if not status or not output.count("already in use"): result = False logging.error("Failed to see network messges on guest") if session.cmd_status("rpm -e libvirt"): logging.error("Failed to remove libvirt packages on guest") if not result: raise error.TestFail("Check libvirt network on guest failed") start_error = "yes" == params.get("start_error", "no") restart_error = "yes" == params.get("restart_error", "no") # network specific attributes. net_name = params.get("net_name", "default") net_bridge = params.get("net_bridge", "{'name':'virbr0'}") net_domain = params.get("net_domain") net_ip_address = params.get("net_ip_address") net_ipv6_address = params.get("net_ipv6_address") net_dns_forward = params.get("net_dns_forward") net_dns_txt = params.get("net_dns_txt") net_dns_srv = params.get("net_dns_srv") net_dns_hostip = params.get("net_dns_hostip") net_dns_hostnames = params.get("net_dns_hostnames", "").split() dhcp_start_ipv4 = params.get("dhcp_start_ipv4") dhcp_end_ipv4 = params.get("dhcp_end_ipv4") guest_name = params.get("guest_name") guest_ipv4 = params.get("guest_ipv4") guest_ipv6 = params.get("guest_ipv6") tftp_root = params.get("tftp_root") pxe_boot = "yes" == params.get("pxe_boot", "no") net_bandwidth_inbound = params.get("net_bandwidth_inbound", "{}") net_bandwidth_outbound = params.get("net_bandwidth_outbound", "{}") iface_bandwidth_inbound = params.get("iface_bandwidth_inbound", "{}") iface_bandwidth_outbound = params.get("iface_bandwidth_outbound", "{}") multiple_guests = params.get("multiple_guests") create_network = "yes" == params.get("create_network", "no") serial_login = "******" == params.get("serial_login", "no") change_iface_option = "yes" == params.get("change_iface_option", "no") test_bridge = "yes" == params.get("test_bridge", "no") test_dnsmasq = "yes" == params.get("test_dnsmasq", "no") test_dhcp_range = "yes" == params.get("test_dhcp_range", "no") test_dns_host = "yes" == params.get("test_dns_host", "no") test_qos_bandwidth = "yes" == params.get("test_qos_bandwidth", "no") test_qos_remove = "yes" == params.get("test_qos_remove", "no") test_ipv4_address = "yes" == params.get("test_ipv4_address", "no") test_ipv6_address = "yes" == params.get("test_ipv6_address", "no") test_guest_libvirt = "yes" == params.get("test_guest_libvirt", "no") if serial_login: # Set serial console for serial login if vm.is_dead(): vm.start() session = vm.wait_for_login() # Set console option vm.set_kernel_console("ttyS0", "115200") # Shutdown here for sync fs vm.shutdown() else: if vm.is_alive(): vm.destroy(gracefully=False) # Back up xml file. netxml_backup = NetworkXML.new_from_net_dumpxml("default") iface_mac = vm_xml.VMXML.get_first_mac_by_name(vm_name) params["guest_mac"] = iface_mac vmxml_backup = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) vms_list = [] # Build the xml and run test. try: if test_dnsmasq: # Check the settings before modifying network xml if net_dns_forward == "no": run_dnsmasq_default_test("domain-needed", exists=False) run_dnsmasq_default_test("local", "//", exists=False) if net_domain: run_dnsmasq_default_test("domain", net_domain, exists=False) run_dnsmasq_default_test("expand-hosts", exists=False) # Prepare pxe boot directory if pxe_boot: prepare_pxe_boot() # Edit the network xml or create a new one. if create_network: libvirt.create_net_xml(net_name, params) # Edit the interface xml. if change_iface_option: modify_iface_xml() if multiple_guests: # Clone more vms for testing for i in range(int(multiple_guests)): guest_name = "%s_%s" % (vm_name, i) utils_libguestfs.virt_clone_cmd(vm_name, guest_name, True) vms_list.append(vm.clone(guest_name)) if test_bridge: bridge = eval(net_bridge) br_if = utils_net.Interface(bridge['name']) if not br_if.is_up(): raise error.TestFail("Bridge interface isn't up") if test_dnsmasq: # Check the settings in dnsmasq config file if net_dns_forward == "no": run_dnsmasq_default_test("domain-needed") run_dnsmasq_default_test("local", "//") if net_domain: run_dnsmasq_default_test("domain", net_domain) run_dnsmasq_default_test("expand-hosts") if net_bridge: bridge = eval(net_bridge) run_dnsmasq_default_test("interface", bridge['name']) if bridge.has_key('stp') and bridge['stp'] == 'on': if bridge.has_key('delay'): br_delay = float(bridge['delay']) cmd = ("brctl showstp %s | grep 'bridge forward delay'" % bridge['name']) out = utils.run(cmd, ignore_status=False).stdout.strip() logging.debug("brctl showstp output: %s", out) pattern = (r"\s*forward delay\s+(\d+.\d+)\s+bridge" " forward delay\s+(\d+.\d+)") match_obj = re.search(pattern, out, re.M) if not match_obj or len(match_obj.groups()) != 2: raise error.TestFail("Can't see forward delay" " messages from command") elif (float(match_obj.groups()[0]) != br_delay or float(match_obj.groups()[1]) != br_delay): raise error.TestFail("Foward delay setting" " can't take effect") if dhcp_start_ipv4 and dhcp_end_ipv4: run_dnsmasq_default_test("dhcp-range", "%s,%s" % (dhcp_start_ipv4, dhcp_end_ipv4)) if guest_name and guest_ipv4: run_dnsmasq_host_test(iface_mac, guest_ipv4, guest_name) if test_dns_host: if net_dns_txt: dns_txt = eval(net_dns_txt) run_dnsmasq_default_test("txt-record", "%s,%s" % (dns_txt["name"], dns_txt["value"])) if net_dns_srv: dns_srv = eval(net_dns_srv) run_dnsmasq_default_test("srv-host", "_%s._%s.%s,%s,%s,%s,%s" % (dns_srv["service"], dns_srv["protocol"], dns_srv["domain"], dns_srv["target"], dns_srv["port"], dns_srv["priority"], dns_srv["weight"])) if net_dns_hostip and net_dns_hostnames: run_dnsmasq_addnhosts_test(net_dns_hostip, net_dns_hostnames) # Run bandwidth test for network if test_qos_bandwidth: run_bandwidth_test(check_net=True) try: # Start the VM. vm.start() if start_error: raise error.TestFail("VM started unexpectedly") if pxe_boot: # Just check network boot messages here vm.serial_console.read_until_output_matches( ["Loading vmlinuz", "Loading initrd.img"], utils_misc.strip_console_codes) output = vm.serial_console.get_stripped_output() logging.debug("Boot messages: %s", output) else: if serial_login: session = vm.wait_for_serial_login() else: session = vm.wait_for_login() if test_dhcp_range: # First vm should have a valid ip address utils_net.restart_guest_network(session, iface_mac) vm_ip = utils_net.get_guest_ip_addr(session, iface_mac) logging.debug("Guest has ip: %s", vm_ip) if not vm_ip: raise error.TestFail("Guest has invalid ip address") # Other vms cloudn't get the ip address for vms in vms_list: # Start other VMs. vms.start() sess = vms.wait_for_serial_login() vms_mac = vms.get_virsh_mac_address() # restart guest network to get ip addr utils_net.restart_guest_network(sess, vms_mac) vms_ip = utils_net.get_guest_ip_addr(sess, vms_mac) if vms_ip: # Get IP address on guest should return Null raise error.TestFail("Guest has ip address: %s" % vms_ip) sess.close() # Check dnsmasq settings if take affect in guest if guest_ipv4: check_name_ip(session) # Run bandwidth test for interface if test_qos_bandwidth: run_bandwidth_test(check_iface=True) if test_qos_remove: # Remove the bandwidth settings in network xml logging.debug("Removing network bandwidth settings...") netxml_backup.sync() vm.destroy(gracefully=False) # Should fail to start vm vm.start() if restart_error: raise error.TestFail("VM started unexpectedly") if test_ipv4_address: check_ipt_rules(check_ipv4=True) run_ip_test(session, "ipv4") if test_ipv6_address: check_ipt_rules(check_ipv6=True) run_ip_test(session, "ipv6") if test_guest_libvirt: run_guest_libvirt(session) session.close() except virt_vm.VMStartError, details: logging.info(str(details)) if start_error or restart_error: pass else: raise error.TestFail('VM Failed to start for some reason!') finally: # Recover VM. if vm.is_alive(): vm.destroy(gracefully=False) for vms in vms_list: virsh.remove_domain(vms.name, "--remove-all-storage") logging.info("Restoring network...") if net_name == "default": netxml_backup.sync() else: # Destroy and undefine new created network virsh.net_destroy(net_name) virsh.net_undefine(net_name) vmxml_backup.sync()
def run(test, params, env): """ Test storage pool and volumes with applications such as: install vms, attached to vms... """ pool_type = params.get("pool_type") pool_name = "test_%s_app" % pool_type pool_target = params.get("pool_target") emulated_img = params.get("emulated_img", "emulated_img") volume_count = int(params.get("volume_count", 1)) volume_size = params.get("volume_size", "1G") emulated_size = "%sG" % (volume_count * int(volume_size[:-1]) + 1) application = params.get("application", "install") disk_target = params.get("disk_target", "vdb") test_message = params.get("test_message", "") vm_name = params.get("main_vm", "virt-tests-vm1") if application == "install": vm_name = params.get("vm_name", "vm1") try: pvtest = utlv.PoolVolumeTest(test, params) pvtest.pre_pool(pool_name, pool_type, pool_target, emulated_img, emulated_size) logging.debug("Current pools:\n%s", libvirt_storage.StoragePool().list_pools()) new_pool = libvirt_storage.PoolVolume(pool_name) volumes = create_volumes(new_pool, volume_count, volume_size) if application == "attach": vm = env.get_vm(vm_name) session = vm.wait_for_login() # The attach-disk action based on running guest, # so no need to recover the guest, it will be # recovered automatically after shutdown/reboot virsh.attach_disk(vm_name, volumes.values()[volume_count-1], disk_target) vm_attach_device = "/dev/%s" % disk_target # Test if attached disk can be used normally utlv.mk_part(vm_attach_device, session=session) session.cmd("mkfs.ext4 %s1" % vm_attach_device) session.cmd("mount %s1 /mnt" % vm_attach_device) session.cmd("echo %s > /mnt/test" % test_message) output = session.cmd_output("cat /mnt/test").strip() if output != test_message: raise error.TestFail("%s cannot be used normally!" % vm_attach_device) elif application == "install": # Get a nonexist domain name while virsh.domain_exists(vm_name): vm_name += "_test" params["image_name"] = volumes.values()[volume_count-1] params["image_format"] = "raw" try: unattended_install.run(test, params, env) except error.CmdError, detail: raise error.TestFail("Guest install failed:%s" % detail) finally: try: if application == "install": if virsh.domain_exists(vm_name): virsh.remove_domain(vm_name) finally: pvtest.cleanup_pool(pool_name, pool_type, pool_target, emulated_img)
def run(test, params, env): """ Test interafce xml options. 1.Prepare test environment,destroy or suspend a VM. 2.Edit xml and start the domain. 3.Perform test operation. 4.Recover test environment. 5.Confirm the test result. """ vm_name = params.get("main_vm") vm = env.get_vm(vm_name) host_arch = platform.machine() virsh_dargs = {'debug': True, 'ignore_status': False} if not utils_package.package_install(["lsof"]): test.cancel("Failed to install dependency package lsof" " on host") def create_iface_xml(iface_mac): """ Create interface xml file """ iface = Interface(type_name=iface_type) source = ast.literal_eval(iface_source) if source: iface.source = source iface.model = iface_model if iface_model else "virtio" iface.mac_address = iface_mac driver_dict = {} driver_host = {} driver_guest = {} if iface_driver: driver_dict = ast.literal_eval(iface_driver) if iface_driver_host: driver_host = ast.literal_eval(iface_driver_host) if iface_driver_guest: driver_guest = ast.literal_eval(iface_driver_guest) iface.driver = iface.new_driver(driver_attr=driver_dict, driver_host=driver_host, driver_guest=driver_guest) if test_target: iface.target = {"dev": target_dev} logging.debug("Create new interface xml: %s", iface) return iface def modify_iface_xml(update, status_error=False): """ Modify interface xml options """ vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) xml_devices = vmxml.devices iface_index = xml_devices.index( xml_devices.by_device_tag("interface")[0]) iface = xml_devices[iface_index] if iface_model: iface.model = iface_model else: del iface.model if iface_type: iface.type_name = iface_type del iface.source source = ast.literal_eval(iface_source) if source: net_ifs = utils_net.get_net_if(state="UP") # Check source device is valid or not, # if it's not in host interface list, try to set # source device to first active interface of host if (iface.type_name == "direct" and 'dev' in source and source['dev'] not in net_ifs): logging.warn( "Source device %s is not a interface" " of host, reset to %s", source['dev'], net_ifs[0]) source['dev'] = net_ifs[0] iface.source = source backend = ast.literal_eval(iface_backend) if backend: iface.backend = backend driver_dict = {} driver_host = {} driver_guest = {} if iface_driver: driver_dict = ast.literal_eval(iface_driver) if iface_driver_host: driver_host = ast.literal_eval(iface_driver_host) if iface_driver_guest: driver_guest = ast.literal_eval(iface_driver_guest) iface.driver = iface.new_driver(driver_attr=driver_dict, driver_host=driver_host, driver_guest=driver_guest) if test_target: logging.debug("iface.target is %s" % target_dev) iface.target = {"dev": target_dev} if iface.address: del iface.address if set_ip: iface.ips = [ast.literal_eval(x) for x in set_ips] logging.debug("New interface xml file: %s", iface) if unprivileged_user: # Create disk image for unprivileged user disk_index = xml_devices.index( xml_devices.by_device_tag("disk")[0]) disk_xml = xml_devices[disk_index] logging.debug("source: %s", disk_xml.source) disk_source = disk_xml.source.attrs["file"] cmd = ("cp -fZ {0} {1} && chown {2}:{2} {1}" "".format(disk_source, dst_disk, unprivileged_user)) process.run(cmd, shell=True) disk_xml.source = disk_xml.new_disk_source( attrs={"file": dst_disk}) vmxml.devices = xml_devices # Remove all channels to avoid of permission problem channels = vmxml.get_devices(device_type="channel") for channel in channels: vmxml.del_device(channel) logging.info("Unprivileged users can't use 'dac' security driver," " removing from domain xml if present...") vmxml.del_seclabel([('model', 'dac')]) # Set vm memory to 2G if it's larger than 2G if vmxml.memory > 2097152: vmxml.memory = vmxml.current_mem = 2097152 vmxml.xmltreefile.write() logging.debug("New VM xml: %s", vmxml) process.run("chmod a+rw %s" % vmxml.xml, shell=True) virsh.define(vmxml.xml, **virsh_dargs) # Try to modify interface xml by update-device or edit xml elif update: iface.xmltreefile.write() ret = virsh.update_device(vm_name, iface.xml, ignore_status=True) libvirt.check_exit_status(ret, status_error) else: vmxml.devices = xml_devices vmxml.xmltreefile.write() try: vmxml.sync() if define_error: test.fail("Define VM succeed, but it should fail") except xcepts.LibvirtXMLError as e: if not define_error: test.fail("Define VM fail: %s" % e) def check_offloads_option(if_name, driver_options, session=None): """ Check interface offloads by ethtool output """ offloads = { "csum": "tx-checksumming", "tso4": "tcp-segmentation-offload", "tso6": "tx-tcp6-segmentation", "ecn": "tx-tcp-ecn-segmentation", "ufo": "udp-fragmentation-offload" } if session: ret, output = session.cmd_status_output("ethtool -k %s | head" " -18" % if_name) else: out = process.run("ethtool -k %s | head -18" % if_name, shell=True) ret, output = out.exit_status, out.stdout_text if ret: test.fail("ethtool return error code") logging.debug("ethtool output: %s", output) for offload in list(driver_options.keys()): if offload in offloads: if (output.count(offloads[offload]) and not output.count( "%s: %s" % (offloads[offload], driver_options[offload]))): test.fail("offloads option %s: %s isn't" " correct in ethtool output" % (offloads[offload], driver_options[offload])) def run_xml_test(iface_mac): """ Test for interface options in vm xml """ # Get the interface object according the mac address vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) iface_devices = vmxml.get_devices(device_type="interface") iface = None for iface_dev in iface_devices: if iface_dev.mac_address == iface_mac: iface = iface_dev if not iface: test.fail("Can't find interface with mac" " '%s' in vm xml" % iface_mac) driver_dict = {} if iface_driver: driver_dict = ast.literal_eval(iface_driver) for driver_opt in list(driver_dict.keys()): if not driver_dict[driver_opt] == iface.driver.driver_attr[ driver_opt]: test.fail("Can't see driver option %s=%s in vm xml" % (driver_opt, driver_dict[driver_opt])) else: logging.info("Find %s=%s in vm xml" % (driver_opt, driver_dict[driver_opt])) if iface_target: if ("dev" not in iface.target or not iface.target["dev"].startswith(iface_target)): test.fail("Can't see device target dev in vm xml") # Check macvtap mode by ip link command if iface_target == "macvtap" and "mode" in iface.source: cmd = "ip -d link show %s" % iface.target["dev"] output = process.run(cmd, shell=True).stdout_text logging.debug("ip link output: %s", output) mode = iface.source["mode"] if mode == "passthrough": mode = "passthru" if not re.search(r"macvtap\s+mode %s" % mode, output): test.fail("Failed to verify macvtap mode") # Check if the "target dev" is set successfully # 1. Target dev name with prefix as "vnet" will always be override; # 2. Target dev name with prefix as "macvtap" or "macvlan" with direct # type interface will be override; # 3. Other scenarios, the target dev should be set successfully. if test_target: if target_dev != iface.target["dev"]: if target_dev.startswith("vnet") or \ (iface_type == "direct" and (target_dev.startswith("macvtap") or target_dev.startswith("macvlan"))): logging.debug("target dev %s is override" % target_dev) else: test.fail("Failed to set target dev to %s", target_dev) else: logging.debug("target dev set successfully to %s", iface.target["dev"]) def run_cmdline_test(iface_mac, host_arch): """ Test qemu command line :param iface_mac: expected MAC :param host_arch: host architecture, e.g. x86_64 :raise avocado.core.exceptions.TestError: if preconditions are not met :raise avocado.core.exceptions.TestFail: if commandline doesn't match :return: None """ cmd = ("ps -ef | grep %s | grep -v grep " % vm_name) ret = process.run(cmd, shell=True) logging.debug("Command line %s", ret.stdout_text) if test_vhost_net: if not ret.stdout_text.count("vhost=on") and not rm_vhost_driver: test.fail("Can't see vhost options in" " qemu-kvm command line") if iface_model == "virtio": if host_arch == 's390x': model_option = "device virtio-net-ccw" else: model_option = "device virtio-net-pci" elif iface_model == 'rtl8139': model_option = "device rtl8139" else: test.error( "Don't know which device driver to expect on qemu cmdline" " for iface_model %s" % iface_model) iface_cmdline = re.findall( r"%s,(.+),mac=%s" % (model_option, iface_mac), ret.stdout_text) if not iface_cmdline: test.fail("Can't see %s with mac %s in command" " line" % (model_option, iface_mac)) cmd_opt = {} for opt in iface_cmdline[0].split(','): tmp = opt.rsplit("=") cmd_opt[tmp[0]] = tmp[1] logging.debug("Command line options %s", cmd_opt) driver_dict = {} # Test <driver> xml options. if iface_driver: iface_driver_dict = ast.literal_eval(iface_driver) for driver_opt in list(iface_driver_dict.keys()): if driver_opt == "name": continue elif driver_opt == "txmode": if iface_driver_dict["txmode"] == "iothread": driver_dict["tx"] = "bh" else: driver_dict["tx"] = iface_driver_dict["txmode"] elif driver_opt == "queues": driver_dict["mq"] = "on" if "pci" in model_option: driver_dict["vectors"] = str( int(iface_driver_dict["queues"]) * 2 + 2) else: driver_dict[driver_opt] = iface_driver_dict[driver_opt] # Test <driver><host/><driver> xml options. if iface_driver_host: driver_dict.update(ast.literal_eval(iface_driver_host)) # Test <driver><guest/><driver> xml options. if iface_driver_guest: driver_dict.update(ast.literal_eval(iface_driver_guest)) for driver_opt in list(driver_dict.keys()): if (driver_opt not in cmd_opt or not cmd_opt[driver_opt] == driver_dict[driver_opt]): test.fail("Can't see option '%s=%s' in qemu-kvm " " command line" % (driver_opt, driver_dict[driver_opt])) logging.info("Find %s=%s in qemu-kvm command line" % (driver_opt, driver_dict[driver_opt])) if test_backend: guest_pid = ret.stdout_text.rsplit()[1] cmd = "lsof %s | grep %s" % (backend["tap"], guest_pid) if process.system(cmd, ignore_status=True, shell=True): test.fail("Guest process didn't open backend file" " %s" % backend["tap"]) cmd = "lsof %s | grep %s" % (backend["vhost"], guest_pid) if process.system(cmd, ignore_status=True, shell=True): test.fail("Guest process didn't open backend file" " %s" % backend["vhost"]) def get_guest_ip(session, mac): """ Wrapper function to get guest ip address """ utils_net.restart_guest_network(session, mac) # Wait for IP address is ready utils_misc.wait_for(lambda: utils_net.get_guest_ip_addr(session, mac), 10) return utils_net.get_guest_ip_addr(session, mac) def check_user_network(session): """ Check user network ip address on guest """ vm_ips = [] vm_ips.append(get_guest_ip(session, iface_mac_old)) if attach_device: vm_ips.append(get_guest_ip(session, iface_mac)) logging.debug("IP address on guest: %s", vm_ips) if len(vm_ips) != len(set(vm_ips)): logging.debug( "Duplicated IP address on guest. Check bug: " "https://bugzilla.redhat.com/show_bug.cgi?id=1147238") for vm_ip in vm_ips: if not vm_ip or vm_ip != expect_ip: logging.debug("vm_ip is %s, expect_ip is %s", vm_ip, expect_ip) test.fail("Found wrong IP address" " on guest") # Check gateway address gateway = str(utils_net.get_default_gateway(False, session)) if expect_gw not in gateway: test.fail("The gateway on guest is %s, while expect is %s" % (gateway, expect_gw)) # Check dns server address ns_list = utils_net.get_guest_nameserver(session) if expect_ns not in ns_list: test.fail("The dns found is %s, which expect is %s" % (ns_list, expect_ns)) def check_mcast_network(session, add_session): """ Check multicast ip address on guests :param session: vm session :param add_session: additional vm session """ src_addr = ast.literal_eval(iface_source)['address'] vms_sess_dict = {vm_name: session, additional_vm.name: add_session} # Check mcast address on host cmd = "netstat -g | grep %s" % src_addr if process.run(cmd, ignore_status=True, shell=True).exit_status: test.fail("Can't find multicast ip address" " on host") vms_ip_dict = {} # Get ip address on each guest for vms in list(vms_sess_dict.keys()): vm_mac = vm_xml.VMXML.get_first_mac_by_name(vms) vm_ip = get_guest_ip(vms_sess_dict[vms], vm_mac) if not vm_ip: test.fail("Can't get multicast ip" " address on guest") vms_ip_dict.update({vms: vm_ip}) if len(set(vms_ip_dict.values())) != len(vms_sess_dict): test.fail("Got duplicated multicast ip address") logging.debug("Found ips on guest: %s", vms_ip_dict) # Run omping server on host if not utils_package.package_install(["omping"]): test.error("Failed to install omping" " on host") cmd = ("iptables -F;omping -m %s %s" % (src_addr, "192.168.122.1 %s" % ' '.join(list(vms_ip_dict.values())))) # Run a backgroup job waiting for connection of client bgjob = utils_misc.AsyncJob(cmd) # Run omping client on guests for vms in list(vms_sess_dict.keys()): # omping should be installed first if not utils_package.package_install(["omping"], vms_sess_dict[vms]): test.error("Failed to install omping" " on guest") cmd = ("iptables -F; omping -c 5 -T 5 -m %s %s" % (src_addr, "192.168.122.1 %s" % vms_ip_dict[vms])) ret, output = vms_sess_dict[vms].cmd_status_output(cmd) logging.debug("omping ret: %s, output: %s", ret, output) if (not output.count('multicast, xmt/rcv/%loss = 5/5/0%') or not output.count('unicast, xmt/rcv/%loss = 5/5/0%')): test.fail("omping failed on guest") # Kill the backgroup job bgjob.kill_func() def get_iface_model(iface_model, host_arch): """ Get iface_model. On s390x use default model 'virtio' if non-virtio given :param iface_model: value as by test configuration or default :param host_arch: host architecture, e.g. x86_64 :return: iface_model """ if 's390x' == host_arch and 'virtio' not in iface_model: return "virtio" else: return iface_model def check_vhostuser_guests(session1, session2): """ Check the vhostuser interface in guests param session1: Session of original guest param session2: Session of original additional guest """ logging.debug("iface details is %s" % libvirt.get_interface_details(vm_name)) vm1_mac = str(libvirt.get_interface_details(vm_name)[0]['mac']) vm2_mac = str(libvirt.get_interface_details(add_vm_name)[0]['mac']) utils_net.set_guest_ip_addr(session1, vm1_mac, guest1_ip) utils_net.set_guest_ip_addr(session2, vm2_mac, guest2_ip) ping_status, ping_output = utils_net.ping(dest=guest2_ip, count='3', timeout=5, session=session1) logging.info("output:%s" % ping_output) if ping_status != 0: if ping_expect_fail: logging.info("Can not ping guest2 as expected") else: test.fail("Can not ping guest2 from guest1") else: if ping_expect_fail: test.fail("Ping guest2 successfully not expected") else: logging.info("Can ping guest2 from guest1") def get_ovs_statis(ovs): """ Get ovs-vsctl interface statistics and format in dict param ovs: openvswitch instance """ ovs_statis_dict = {} ovs_iface_info = ovs.ovs_vsctl(["list", "interface"]).stdout_text.strip() ovs_iface_list = re.findall( 'name\s+: (\S+)\n.*?statistics\s+: {(.*?)}\n', ovs_iface_info, re.S) logging.info("ovs iface list is %s", ovs_iface_list) # Dict of iface name and statistics for iface_name in vhostuser_names.split(): for ovs_iface in ovs_iface_list: if iface_name == eval(ovs_iface[0]): format_statis = dict( re.findall(r'(\S*?)=(\d*?),', ovs_iface[1])) ovs_statis_dict[iface_name] = format_statis break return ovs_statis_dict status_error = "yes" == params.get("status_error", "no") start_error = "yes" == params.get("start_error", "no") define_error = "yes" == params.get("define_error", "no") unprivileged_user = params.get("unprivileged_user") # Interface specific attributes. iface_type = params.get("iface_type", "network") iface_source = params.get("iface_source", "{}") iface_driver = params.get("iface_driver") iface_model = get_iface_model(params.get("iface_model", "virtio"), host_arch) iface_target = params.get("iface_target") iface_backend = params.get("iface_backend", "{}") iface_driver_host = params.get("iface_driver_host") iface_driver_guest = params.get("iface_driver_guest") ovs_br_name = params.get("ovs_br_name") vhostuser_names = params.get("vhostuser_names") attach_device = params.get("attach_iface_device") expect_tx_size = params.get("expect_tx_size") guest1_ip = params.get("vhostuser_guest1_ip", "192.168.100.1") guest2_ip = params.get("vhostuser_guest2_ip", "192.168.100.2") change_option = "yes" == params.get("change_iface_options", "no") update_device = "yes" == params.get("update_iface_device", "no") additional_guest = "yes" == params.get("additional_guest", "no") serial_login = "******" == params.get("serial_login", "no") rm_vhost_driver = "yes" == params.get("rm_vhost_driver", "no") test_option_cmd = "yes" == params.get("test_iface_option_cmd", "no") test_option_xml = "yes" == params.get("test_iface_option_xml", "no") test_vhost_net = "yes" == params.get("test_vhost_net", "no") test_option_offloads = "yes" == params.get("test_option_offloads", "no") test_iface_user = "******" == params.get("test_iface_user", "no") test_iface_mcast = "yes" == params.get("test_iface_mcast", "no") test_libvirtd = "yes" == params.get("test_libvirtd", "no") restart_libvirtd = "yes" == params.get("restart_libvirtd", "no") restart_vm = "yes" == params.get("restart_vm", "no") test_guest_ip = "yes" == params.get("test_guest_ip", "no") test_backend = "yes" == params.get("test_backend", "no") check_guest_trans = "yes" == params.get("check_guest_trans", "no") set_ip = "yes" == params.get("set_user_ip", "no") set_ips = params.get("set_ips", "").split() expect_ip = params.get("expect_ip") expect_gw = params.get("expect_gw") expect_ns = params.get("expect_ns") test_target = "yes" == params.get("test_target", "no") target_dev = params.get("target_dev", None) # test params for vhostuser test huge_page = ast.literal_eval(params.get("huge_page", "{}")) numa_cell = ast.literal_eval(params.get("numa_cell", "{}")) additional_iface_source = ast.literal_eval( params.get("additional_iface_source", "{}")) vcpu_num = params.get("vcpu_num") cpu_mode = params.get("cpu_mode") hugepage_num = params.get("hugepage_num") log_pattern = params.get("log_pattern") # judgement params for vhostuer test need_vhostuser_env = "yes" == params.get("need_vhostuser_env", "no") ping_expect_fail = "yes" == params.get("ping_expect_fail", "no") check_libvirtd_log = "yes" == params.get("check_libvirtd_log", "no") check_statistics = "yes" == params.get("check_statistics", "no") enable_multiqueue = "yes" == params.get("enable_multiqueue", "no") queue_size = None if iface_driver: driver_dict = ast.literal_eval(iface_driver) if "queues" in driver_dict: queue_size = int(driver_dict.get("queues")) if iface_driver_host or iface_driver_guest or test_backend: if not libvirt_version.version_compare(1, 2, 8): test.cancel("Offloading/backend options not " "supported in this libvirt version") if iface_driver and "queues" in ast.literal_eval(iface_driver): if not libvirt_version.version_compare(1, 0, 6): test.cancel("Queues options not supported" " in this libvirt version") if unprivileged_user: if not libvirt_version.version_compare(1, 1, 1): test.cancel("qemu-bridge-helper not supported" " on this host") virsh_dargs["unprivileged_user"] = unprivileged_user # Create unprivileged user if needed cmd = ("grep {0} /etc/passwd || " "useradd {0}".format(unprivileged_user)) process.run(cmd, shell=True) # Need another disk image for unprivileged user to access dst_disk = "/tmp/%s.img" % unprivileged_user # Destroy VM first if vm.is_alive(): vm.destroy(gracefully=False) # Back up xml file. vmxml_backup = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) iface_mac_old = vm_xml.VMXML.get_first_mac_by_name(vm_name) # iface_mac will update if attach a new interface iface_mac = iface_mac_old # Additional vm for test additional_vm = None libvirtd = utils_libvirtd.Libvirtd() libvirtd_log_path = None libvirtd_conf = None if check_libvirtd_log: libvirtd_log_path = os.path.join(test.tmpdir, "libvirtd.log") libvirtd_conf = utils_config.LibvirtdConfig() libvirtd_conf["log_outputs"] = '"1:file:%s"' % libvirtd_log_path libvirtd.restart() # Prepare vhostuser ovs = None if need_vhostuser_env: # Reserve selinux status selinux_mode = utils_selinux.get_status() # Reserve orig page size orig_size = utils_memory.get_num_huge_pages() ovs_dir = data_dir.get_tmp_dir() ovs = utils_net.setup_ovs_vhostuser(hugepage_num, ovs_dir, ovs_br_name, vhostuser_names, queue_size) try: # Build the xml and run test. try: # Prepare interface backend files if test_backend: if not os.path.exists("/dev/vhost-net"): process.run("modprobe vhost-net", shell=True) backend = ast.literal_eval(iface_backend) backend_tap = "/dev/net/tun" backend_vhost = "/dev/vhost-net" if not backend: backend["tap"] = backend_tap backend["vhost"] = backend_vhost if not start_error: # Create backend files for normal test if not os.path.exists(backend["tap"]): os.rename(backend_tap, backend["tap"]) if not os.path.exists(backend["vhost"]): os.rename(backend_vhost, backend["vhost"]) # Edit the interface xml. if change_option: modify_iface_xml(update=False) if define_error: return if test_target: logging.debug("Setting target device name to %s", target_dev) modify_iface_xml(update=False) if rm_vhost_driver: # remove vhost driver on host and # the character file /dev/vhost-net cmd = ("modprobe -r {0}; " "rm -f /dev/vhost-net".format("vhost_net")) if process.system(cmd, ignore_status=True, shell=True): test.error("Failed to remove vhost_net driver") else: # Load vhost_net driver by default cmd = "modprobe vhost_net" process.system(cmd, shell=True) # Attach a interface when vm is shutoff if attach_device == 'config': iface_mac = utils_net.generate_mac_address_simple() iface_xml_obj = create_iface_xml(iface_mac) iface_xml_obj.xmltreefile.write() ret = virsh.attach_device(vm_name, iface_xml_obj.xml, flagstr="--config", ignore_status=True) libvirt.check_exit_status(ret) # Add hugepage and update cpu for vhostuser testing if huge_page: vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) membacking = vm_xml.VMMemBackingXML() hugepages = vm_xml.VMHugepagesXML() pagexml = hugepages.PageXML() pagexml.update(huge_page) hugepages.pages = [pagexml] membacking.hugepages = hugepages vmxml.mb = membacking vmxml.vcpu = int(vcpu_num) cpu_xml = vm_xml.VMCPUXML() cpu_xml.xml = "<cpu><numa/></cpu>" cpu_xml.numa_cell = cpu_xml.dicts_to_cells([numa_cell]) cpu_xml.mode = cpu_mode if cpu_mode == "custom": vm_capability = capability_xml.CapabilityXML() cpu_xml.model = vm_capability.model vmxml.cpu = cpu_xml vmxml.sync() logging.debug("xmltreefile:%s", vmxml.xmltreefile) # Clone additional vm if additional_guest: add_vm_name = "%s_%s" % (vm_name, '1') # Clone additional guest timeout = params.get("clone_timeout", 360) utils_libguestfs.virt_clone_cmd(vm_name, add_vm_name, True, timeout=timeout) additional_vm = vm.clone(add_vm_name) # Update iface source if needed if additional_iface_source: add_vmxml = vm_xml.VMXML.new_from_dumpxml(add_vm_name) add_xml_devices = add_vmxml.devices add_iface_index = add_xml_devices.index( add_xml_devices.by_device_tag("interface")[0]) add_iface = add_xml_devices[add_iface_index] add_iface.source = additional_iface_source add_vmxml.devices = add_xml_devices add_vmxml.xmltreefile.write() add_vmxml.sync() logging.debug("add vm xmltreefile:%s", add_vmxml.xmltreefile) additional_vm.start() # additional_vm.wait_for_login() username = params.get("username") password = params.get("password") add_session = additional_vm.wait_for_serial_login( username=username, password=password) # Start the VM. if unprivileged_user: virsh.start(vm_name, **virsh_dargs) cmd = ("su - %s -c 'virsh console %s'" % (unprivileged_user, vm_name)) session = aexpect.ShellSession(cmd) session.sendline() remote.handle_prompts(session, params.get("username"), params.get("password"), r"[\#\$]\s*$", 60) # Get ip address on guest if not get_guest_ip(session, iface_mac): test.error("Can't get ip address on guest") else: # Will raise VMStartError exception if start fails vm.start() if serial_login: session = vm.wait_for_serial_login() else: session = vm.wait_for_login() if start_error: test.fail("VM started unexpectedly") # Attach a interface when vm is running if attach_device == 'live': iface_mac = utils_net.generate_mac_address_simple() iface_xml_obj = create_iface_xml(iface_mac) iface_xml_obj.xmltreefile.write() ret = virsh.attach_device(vm_name, iface_xml_obj.xml, flagstr="--live", ignore_status=True, debug=True) libvirt.check_exit_status(ret, status_error) # Need sleep here for attachment take effect time.sleep(5) # Update a interface options if update_device: modify_iface_xml(update=True, status_error=status_error) # Run tests for qemu-kvm command line options if test_option_cmd: run_cmdline_test(iface_mac, host_arch) # Run tests for vm xml if test_option_xml: run_xml_test(iface_mac) # Run tests for offloads options if test_option_offloads: if iface_driver_host: ifname_guest = utils_net.get_linux_ifname( session, iface_mac) check_offloads_option(ifname_guest, ast.literal_eval(iface_driver_host), session) if iface_driver_guest: ifname_host = libvirt.get_ifname_host(vm_name, iface_mac) check_offloads_option(ifname_host, ast.literal_eval(iface_driver_guest)) if test_iface_user: # Test user type network check_user_network(session) if test_iface_mcast: # Test mcast type network check_mcast_network(session, add_session) # Check guest ip address if test_guest_ip: if not get_guest_ip(session, iface_mac): test.fail("Guest can't get a" " valid ip address") # Check guest RX/TX ring if check_guest_trans: ifname_guest = utils_net.get_linux_ifname(session, iface_mac) ret, outp = session.cmd_status_output("ethtool -g %s" % ifname_guest) if ret: test.fail("ethtool return error code") logging.info("ethtool output is %s", outp) driver_dict = ast.literal_eval(iface_driver) if expect_tx_size: driver_dict['tx_queue_size'] = expect_tx_size for outp_p in outp.split("Current hardware"): if 'rx_queue_size' in driver_dict: if re.search( r"RX:\s*%s" % driver_dict['rx_queue_size'], outp_p): logging.info("Find RX setting RX:%s by ethtool", driver_dict['rx_queue_size']) else: test.fail("Cannot find matching rx setting") if 'tx_queue_size' in driver_dict: if re.search( r"TX:\s*%s" % driver_dict['tx_queue_size'], outp_p): logging.info("Find TX settint TX:%s by ethtool", driver_dict['tx_queue_size']) else: test.fail("Cannot find matching tx setting") if test_target: logging.debug("Check if the target dev is set") run_xml_test(iface_mac) # Check vhostuser guest if additional_iface_source: check_vhostuser_guests(session, add_session) # Check libvirtd log if check_libvirtd_log: find = 0 with open(libvirtd_log_path) as f: lines = "".join(f.readlines()) if log_pattern in lines: logging.info("Finding msg<%s> in libvirtd log", log_pattern) else: test.fail("Can not find msg:<%s> in libvirtd.log" % log_pattern) # Check statistics if check_statistics: session.sendline("ping %s" % guest2_ip) add_session.sendline("ping %s" % guest1_ip) time.sleep(5) vhost_name = vhostuser_names.split()[0] ovs_statis_dict = get_ovs_statis(ovs)[vhost_name] domif_info = {} domif_info = libvirt.get_interface_details(vm_name) virsh.domiflist(vm_name, debug=True) domif_stat_result = virsh.domifstat(vm_name, vhost_name) if domif_stat_result.exit_status != 0: test.fail("domifstat cmd fail with msg:%s" % domif_stat_result.stderr) else: domif_stat = domif_stat_result.stdout.strip() logging.debug("vhost_name is %s, domif_stat is %s", vhost_name, domif_stat) domif_stat_dict = dict( re.findall("%s (\S*) (\d*)" % vhost_name, domif_stat)) logging.debug("ovs_statis is %s, domif_stat is %s", ovs_statis_dict, domif_stat_dict) ovs_cmp_dict = { 'tx_bytes': ovs_statis_dict['rx_bytes'], 'tx_drop': ovs_statis_dict['rx_dropped'], 'tx_errs': ovs_statis_dict['rx_errors'], 'tx_packets': ovs_statis_dict['rx_packets'], 'rx_bytes': ovs_statis_dict['tx_bytes'], 'rx_drop': ovs_statis_dict['tx_dropped'] } logging.debug("ovs_cmp_dict is %s", ovs_cmp_dict) for dict_key in ovs_cmp_dict.keys(): if domif_stat_dict[dict_key] != ovs_cmp_dict[dict_key]: test.fail( "Find ovs %s result (%s) different with domifstate result (%s)" % (dict_key, ovs_cmp_dict[dict_key], domif_stat_dict[dict_key])) else: logging.info("ovs %s value %s is same with domifstate", dict_key, domif_stat_dict[dict_key]) # Check multi_queue if enable_multiqueue: ifname_guest = utils_net.get_linux_ifname(session, iface_mac) for comb_size in (queue_size, queue_size - 1): logging.info("Setting multiqueue size to %s" % comb_size) session.cmd_status("ethtool -L %s combined %s" % (ifname_guest, comb_size)) ret, outp = session.cmd_status_output("ethtool -l %s" % ifname_guest) logging.debug("ethtool cmd output:%s" % outp) if not ret: pre_comb = re.search( "Pre-set maximums:[\s\S]*?Combined:.*?(\d+)", outp).group(1) cur_comb = re.search( "Current hardware settings:[\s\S]*?Combined:.*?(\d+)", outp).group(1) if int(pre_comb) != queue_size or int(cur_comb) != int( comb_size): test.fail( "Fail to check the combined size: setting: %s," "Pre-set: %s, Current-set: %s, queue_size: %s" % (comb_size, pre_comb, cur_comb, queue_size)) else: logging.info( "Getting correct Pre-set and Current set value" ) else: test.error("ethtool list fail: %s" % outp) session.close() if additional_guest: add_session.close() # Restart libvirtd and guest, then test again if restart_libvirtd: libvirtd.restart() if restart_vm: vm.destroy(gracefully=True) vm.start() if test_option_xml: run_xml_test(iface_mac) # Detach hot/cold-plugged interface at last if attach_device and not status_error: ret = virsh.detach_device(vm_name, iface_xml_obj.xml, flagstr="", ignore_status=True, debug=True) libvirt.check_exit_status(ret) except virt_vm.VMStartError as e: logging.info(str(e)) if not start_error: test.fail('VM failed to start\n%s' % e) finally: # Recover VM. logging.info("Restoring vm...") # Restore interface backend files if test_backend: if not os.path.exists(backend_tap): os.rename(backend["tap"], backend_tap) if not os.path.exists(backend_vhost): os.rename(backend["vhost"], backend_vhost) if rm_vhost_driver: # Restore vhost_net driver process.system("modprobe vhost_net", shell=True) if unprivileged_user: virsh.remove_domain(vm_name, **virsh_dargs) process.run('rm -f %s' % dst_disk, shell=True) if additional_vm: virsh.remove_domain(additional_vm.name, "--remove-all-storage") # Kill all omping server process on host process.system("pidof omping && killall omping", ignore_status=True, shell=True) if vm.is_alive(): vm.destroy(gracefully=True) vmxml_backup.sync() if need_vhostuser_env: utils_net.clean_ovs_env(selinux_mode=selinux_mode, page_size=orig_size, clean_ovs=True) if libvirtd_conf: libvirtd_conf.restore() libvirtd.restart() if libvirtd_log_path and os.path.exists(libvirtd_log_path): os.unlink(libvirtd_log_path)
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 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.") status_error = ("yes" == params.get("status_error", "no")) 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)) multi_vms = ("yes" == params.get("multi_vms", "no")) # 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") 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() 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(): """ Check whether the added devices are shown in the guest xml """ 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 str(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 str(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 str(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 str(xml_after_adding_device): test.fail("Can not find the %s device path xml for tpm dev " "in the guest xml file." % device_path) logging.info('------PASS on guest dumpxml check------') def check_qemu_cmd_line(): """ Check whether the added devices are shown in the qemu cmd line """ 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 = "-device.%s" % tpm_model if not re.search(pattern, cmdline): test.fail("Can not find the %s tpm device " "in qemu cmd line." % tpm_model) # Check backend type if backend_type == "passthrough": pattern_list = ["-tpmdev.passthrough"] dev_num = re.search(r"\d+", device_path).group() pattern_list.append("id=tpm-tpm%s" % dev_num) for pattern in pattern_list: if not re.search(pattern, cmdline): test.fail("Can not find the %s tpm device " "in qemu cmd line." % pattern) logging.info("------PASS on qemu cmd line check------") 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 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 'elif' 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') elif 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") if process.run("tpm2_getrandom 5", 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": if not process.run("tpm2_getrandom 7", 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(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: status, output = session.cmd_status_output("tpm_version") logging.debug(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: status, output = session.cmd_status_output("tpm2_getrandom 11") logging.debug(output) if status: test.fail("Guest tpm can not work") logging.info("------PASS on guest tpm device work check------") def reuse_by_vm2(tpm_dev): """ Try to passthrough 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 passthrough 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 ret: logging.info("Expected failure when try to passthrough a tpm" " that being used by another guest") return else: test.fail("Reuse a passthroughed tpm should not succeed.") try: tpm_real_v = None 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) vm_xml.remove_all_device_by_type('tpm') tpm_dev = Tpm() if tpm_model: tpm_dev.tpm_model = tpm_model backend = tpm_dev.Backend() backend.backend_type = backend_type if device_path: backend.device_path = device_path tpm_dev.backend = backend logging.debug("tpm dev xml to add is %s", tpm_dev) for num in range(tpm_num): vm_xml.add_device(tpm_dev, True) try: vm_xml.sync() except LibvirtXMLError as e: if tpm_num > 1 and backend_type == "passthrough": logging.info("Expected failure when define a guest with multi tpm passthrough" " configured in xml.") # Stop test when get expected failure return else: test.fail("Test failed in vmxml.sync(), detail:%s." % e) if tpm_num > 1 and backend_type == "passthrough": test.fail("Passthrough multi tpm should not succeed.") check_dumpxml() # For default model, no need start guest to test if tpm_model: expect_fail = False virsh.start(vm_name, ignore_status=False, debug=True) check_qemu_cmd_line() session = vm.wait_for_login() if backend_type == "passthrough": if tpm_real_v == "1.2" and tpm_model == "tpm-crb": expect_fail = True test_guest_tpm(tpm_real_v, session, expect_fail) if multi_vms: reuse_by_vm2(tpm_dev) # Stop test when get expected failure return test_host_tpm_aft(tpm_real_v) else: # emulator backend test_guest_tpm(backend_version, session, expect_fail) session.close() finally: vm_xml_backup.sync() if vm2: if len(vm_names) > 1: vm2_xml_backup.sync() else: virsh.remove_domain(vm2_name, "--remove-all-storage", debug=True)
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 params.itervalues(): if "V2V_EXAMPLE" in v: test.cancel("Please set real value for %s" % v) vm_name = params.get("main_vm", "EXAMPLE") new_vm_name = params.get("new_vm_name") input_mode = params.get("input_mode") 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") 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_path", "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', '') 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 %s'" % target_path process.system(cmd, verbose=True) cmd = su_cmd + "'virsh pool-create-as %s dir" % pool_name cmd += " --target %s'" % target_path process.system(cmd, verbose=True) else: pvt.pre_pool(pool_name, pool_type, pool_target, emulated_img) 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: cmd = su_cmd + "'virsh pool-destroy %s'" % pool_name process.system(cmd, verbose=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 = 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', 'display', 'CPU features', 'disks', 'NICs'] for key in checklist: if key not in source_info: test.fail('%s info missing' % key) # Check single values fail = [] xml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) 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)' 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 source_info[key] != str(check_map[key]): fail.append(key) # Check disk info disk = xml.get_disk_all().values()[0] bus, type = disk.find('target').get('bus'), disk.find('driver').get('type') path = disk.find('source').get('file') disks_info = "%s (%s) [%s]" % (path, type, bus) source_disks = source_info['disks'].split() source_disks_path = source_disks[0] source_disks_type = source_disks[1].strip('()') source_disks_bus = source_disks[2].strip('[]') logging.info('disks:%s<->%s', source_info['disks'], disks_info) if source_disks_path != path or source_disks_type != type or bus not in source_disks_bus: fail.append('disks') # Check nic info nic = 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 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.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_result(cmd, result, status_error): """ Check virt-v2v command result """ utlv.check_exit_status(result, status_error) output = result.stdout + result.stderr 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 if v2v_start and len(line) > 72: test.fail('Error log longer than 72 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 checkpoint != 'quiet': 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: 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 == 'vmx': 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()) != 0: 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 'VMF' not in output: 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') 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 result.stdout.lower(): test.fail('Expect log not found: %s' % target_str) if checkpoint == 'print_source': check_source(result.stdout) if checkpoint == 'machine_readable': if os.path.exists(params.get('example_file', '')): expect_output = open(params['example_file']).read().strip() logging.debug(expect_output) if expect_output != result.stdout.strip(): test.fail('machine readable content not correct') else: test.error('No content to compare with') if checkpoint == 'compress': img_path = get_img_path(output) logging.info('Image path: %s', img_path) disk_check = process.run('qemu-img check %s' % img_path).stdout 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) 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 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) if checkpoint == 'with_ic': ic_uri = 'qemu:///session' input_option = "-i %s -ic %s %s" % (input_mode, ic_uri, vm_name) if checkpoint == 'without_ic': input_option = '-i %s %s' % (input_mode, vm_name) # 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 -os %s" % (output_mode, output_storage) if checkpoint == 'rhv': output_option = output_option.replace('rhev', 'rhv') 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) # 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']: 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 = string.replace(input_option, 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") passwd = params.get("xen_host_passwd", "redhat") logging.info("set up ssh-agent access ") ssh_key.setup_ssh_key(remote_host, user=user, port=22, password=passwd) 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': vpx_passwd = params.get("vpx_password") vpx_passwd_file = os.path.join(test.tmpdir, "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 += " --password-file %s" % vpx_passwd_file # Create libvirt dir pool if output_mode == "libvirt": create_pool() # 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 create_pool(user_pool=True, pool_name='src_pool', pool_target='v2v_src_pool') create_pool(user_pool=True) logging.debug(virsh.pool_list(uri='qemu:///session')) sh_install_vm = params.get('sh_install_vm') if not sh_install_vm: test.error('Source vm installing script missing') with open(sh_install_vm) as fh: cmd_install_vm = fh.read().strip() process.run('su - %s -c "%s"' % (v2v_user, cmd_install_vm), timeout=10, shell=True) 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")) # Running virt-v2v command cmd = "%s %s %s %s" % (utils_v2v.V2V_EXEC, input_option, output_option, v2v_options) if v2v_user: cmd = su_cmd + "'%s'" % cmd if params.get('cmd_free') == 'yes': cmd = params.get('check_command') # 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 == "xen": process.run("ssh-agent -k") if hypervisor == "esx": process.run("rm -rf %s" % vpx_passwd_file) 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: logging.error('Undefine "%s" failed', vm_name) if no_root: cleanup_pool(user_pool=True, pool_name='src_pool', pool_target='v2v_src_pool') cleanup_pool(user_pool=True) else: virsh.remove_domain(vm_name) cleanup_pool() vmcheck_flag = params.get("vmcheck_flag") if vmcheck_flag: vmcheck = utils_v2v.VMCheck(test, params, env) vmcheck.cleanup() if new_v2v_user: process.system("userdel -f %s" % v2v_user) if backup_xml: backup_xml.sync() if checkpoint == 'vmx': utils_misc.umount(params['nfs_vmx'], params['mount_point'], 'nfs') os.rmdir(params['mount_point'])
if test_ipv4_address: check_ipt_rules(check_ipv4=True) run_ip_test(session, "ipv4") if test_guest_libvirt: run_guest_libvirt(session) session.close() except virt_vm.VMStartError as details: logging.info(str(details)) if not (start_error or restart_error): test.fail('VM failed to start:\n%s' % details) finally: # Recover VM. if vm.is_alive(): vm.destroy(gracefully=False) for vms in vms_list: virsh.remove_domain(vms.name, "--remove-all-storage") logging.info("Restoring network...") if net_name == "default": netxml_backup.sync() else: # Destroy and undefine new created network virsh.net_destroy(net_name) virsh.net_undefine(net_name) vmxml_backup.sync() if test_ipv6_address and original_accept_ra != '2': process.system(sysctl_cmd + "=%s" % original_accept_ra)
session.close() except virt_vm.VMStartError, e: logging.info(str(e)) if start_error: pass else: raise error.TestFail('VM Failed to start for some reason!') except xcepts.LibvirtXMLError, e: logging.info(str(e)) if define_error: pass else: raise error.TestFail("Failed to define VM") finally: # Recover VM. logging.info("Restoring vm...") if unprivileged_user: virsh.remove_domain(vm_name, "--remove-all-storage", **virsh_dargs) if additional_vm: virsh.remove_domain(additional_vm.name, "--remove-all-storage") # Kill all omping server process on host utils.system("pidof omping && killall omping", ignore_status=True) if vm.is_alive(): vm.destroy(gracefully=False) vmxml_backup.sync()
def run(test, params, env): """ Test for virt-clone, it is used to clone a guest to another with given name. (1). Get source guest and destination guest name. (2). Clone source guest to dest guest with virt-clone. (3). Check the dest guest. """ # Get the full path of virt-clone command. try: VIRT_CLONE = process.run("which virt-clone", shell=True).stdout_text.strip() except ValueError: test.cancel("Not find virt-clone command on host.") vm_name = params.get("main_vm", "avocado-vt-vm1") vm = env.get_vm(vm_name) dest_guest_name = params.get("dest_vm", "test-clone") dest_guest_file = params.get("dest_image") dest_guest_path = None # Destroy and undefine the test-clone guest before # executing virt-clone command. virsh.remove_domain(dest_guest_name) cmd = "%s --connect=%s -o %s -n %s" % (VIRT_CLONE, vm.connect_uri, vm_name, dest_guest_name) domblklist_result = virsh.domblklist(vm_name) if len(domblklist_result.stdout.strip().splitlines()) >= 3: # We need a file for destination if guest has block devices. dest_guest_path = os.path.join(data_dir.get_data_dir(), dest_guest_file) if os.path.exists(dest_guest_path): os.remove(dest_guest_path) cmd = "%s -f %s" % (cmd, dest_guest_path) try: cmd_result = process.run(cmd, ignore_status=True, shell=True) if cmd_result.exit_status: test.fail("command of virt-clone failed.\n" "output: %s." % cmd_result) start_result = None # We will get an error of "error: monitor socket did not show up:" # when start vm immediately after virt-clone. def _start_success(): start_result = virsh.start(dest_guest_name) if start_result.exit_status: return False return True if not utils_misc.wait_for(_start_success, timeout=5): test.fail("command virt-clone exit successfully.\n" "but start it failed.\n Detail: %s." % start_result) finally: # cleanup remove the dest guest. virsh.remove_domain(dest_guest_name) # remove image file if we created it. if dest_guest_path and os.path.exists(dest_guest_path): os.remove(dest_guest_path)
def run(test, params, env): """ Convert a remote vm to local libvirt(KVM). """ for v in list(params.values()): if "V2V_EXAMPLE" in v: raise exceptions.TestSkipError("Please set real value for %s" % v) vm_name = params.get("main_vm") 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_pwd_file = params.get("vpx_passwd_file") vpx_dc = params.get("vpx_dc") esx_ip = params.get("esx_hostname") hypervisor = params.get("hypervisor") input_mode = params.get("input_mode") target = params.get("target") v2v_opts = params.get("v2v_opts") # 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_pwd_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") raise exceptions.TestError("Fail to setup ssh-agent") else: raise exceptions.TestSkipError("Unspported hypervisor: %s" % hypervisor) # Create libvirt URI for the source node v2v_uri = utils_v2v.Uri(hypervisor) remote_uri = v2v_uri.get_uri(source_ip, vpx_dc, esx_ip) logging.debug("Remote host uri for converting: %s", remote_uri) # Make sure the VM exist before convert virsh_dargs = { 'uri': remote_uri, 'remote_ip': source_ip, 'remote_user': source_user, 'remote_pwd': source_pwd, 'debug': True } remote_virsh = virsh.VirshPersistent(**virsh_dargs) try: if not remote_virsh.domain_exists(vm_name): raise exceptions.TestError("VM '%s' not exist" % vm_name) finally: remote_virsh.close_session() # Prepare libvirt storage pool pool_type = params.get("pool_type") pool_name = params.get("pool_name") pool_target = params.get("pool_target") libvirt_pool = utlv.PoolVolumeTest(test, params) libvirt_pool.pre_pool(pool_name, pool_type, pool_target, '') # Preapre libvirt virtual network network = params.get("network") net_kwargs = { 'net_name': network, 'address': params.get('network_addr'), 'dhcp_start': params.get('network_dhcp_start'), 'dhcp_end': params.get('network_dhcp_end') } libvirt_net = utlv.LibvirtNetwork('vnet', **net_kwargs) net_info = virsh.net_info(network).stdout.strip() bridge = re.search(r'Bridge:\s+(\S+)', net_info).group(1) params['netdst'] = bridge # 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': pool_name, 'hostname': source_ip } 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}) # Set libguestfs environment if hypervisor == 'xen': os.environ['LIBGUESTFS_BACKEND'] = 'direct' try: # Execute virt-v2v command ret = utils_v2v.v2v_cmd(v2v_params) logging.debug("virt-v2v verbose messages:\n%s", ret) if ret.exit_status != 0: raise exceptions.TestFail("Convert VM failed") logging.debug("XML info:\n%s", virsh.dumpxml(vm_name)) vm = env.create_vm("libvirt", "libvirt", vm_name, params, test.bindir) # Win10 is not supported by some cpu model, # need to modify to 'host-model' if params.get('os_version') in ['win10', 'win2016']: logging.info('Set cpu mode to "host-model" for win10 and win2016') vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) cpu_xml = vm_xml.VMCPUXML() cpu_xml.mode = 'host-model' cpu_xml.fallback = 'allow' vmxml['cpu'] = cpu_xml vmxml.sync() vm.start() # Check all checkpoints after convert vmchecker = VMChecker(test, params, env) ret = vmchecker.run() if len(ret) == 0: logging.info("All checkpoints passed") else: raise exceptions.TestFail("%d checkpoints failed: %s" % (len(ret), ret)) finally: vmcheck = utils_v2v.VMCheck(test, params, env) vmcheck.cleanup() utils_v2v.cleanup_constant_files(params) if hypervisor == "xen": process.run("ssh-agent -k") # Clean libvirt VM virsh.remove_domain(vm_name) # Clean libvirt pool if libvirt_pool: libvirt_pool.cleanup_pool(pool_name, pool_type, pool_target, '') # Clean libvirt network if libvirt_net: libvirt_net.cleanup()
class Virt_install(object): """ Test virt-install with abnormal resource """ def __init__(self, test, params): self.vm_name = params.get("vm_name", "test-vm1") while virsh.domain_exists(self.vm_name): self.vm_name += ".test" params["main_vm"] = self.vm_name ios_file = os.path.join(data_dir.get_data_dir(), params.get('cdrom_cd1')) if not os.path.exists(ios_file): raise error.TestNAError("Please prepare ios file:%s" % ios_file) self.env = params.get('env') self.vm = self.env.create_vm("libvirt", None, self.vm_name, params, test.bindir) self.env.register_vm(self.vm_name, self.vm) self.twice_execute = "yes" == params.get("twice_execute", "no") self.kill_first = "yes" == params.get("kill_first", "no") self.read_only = "yes" == params.get("read_only", "no") self.selinux_enforcing = utils_selinux.is_enforcing() if self.selinux_enforcing: utils_selinux.set_status("permissive") self.image_path = os.path.join(test.virtdir, "test_image") if not os.path.exists(self.image_path): os.mkdir(self.image_path) if self.read_only: os.chmod(self.image_path, stat.S_IRUSR | stat.S_IRGRP | stat.S_IROTH) params["image_name"] = os.path.join(self.image_path, self.vm_name) params["image_format"] = "raw" params['force_create_image'] = "yes" params['remove_image'] = "yes" params['shutdown_cleanly'] = "yes" params['shutdown_cleanly_timeout'] = 120 params['guest_port_unattended_install'] = 12323 params['inactivity_watcher'] = "error" params['inactivity_treshold'] = 1800 params['image_verify_bootable'] = "no" params['unattended_delivery_method'] = "cdrom" params['drive_index_unattended'] = 1 params['drive_index_cd1'] = 2 params['boot_once'] = "d" params['medium'] = "cdrom" params['wait_no_ack'] = "yes" params['image_raw_device'] = "yes" params['backup_image_before_testing'] = "no" params['kernel_params'] = ("ks=cdrom nicdelay=60 " "console=ttyS0,115200 console=tty0") params['cdroms'] += " unattended" params['redirs'] += " unattended_install" self.params = params self.test = test def run_test(self): """ Start test, Creat a threading to install VM. """ self.td = threading.Thread(target=unattended_install.run, args=(self.test, self.params, self.env)) self.td.start() # Wait for install start time.sleep(10) def result_confirm(self, params): """ Confirm if VM installation is succeed """ if self.twice_execute and self.kill_first: get_pid_cmd = "ps -ef | grep '%s' | grep qemu-kvm | grep -v grep"\ % self.vm_name result = utils.run(get_pid_cmd, ignore_status=True) if result.exit_status: raise error.TestFail("First install failed!") install_pid = result.stdout.strip().split()[1] utils_misc.safe_kill(int(install_pid), signal.SIGKILL) self.td.join() if self.read_only: if virsh.domain_exists(self.vm_name): raise error.TestFail("Domain '%s' should not exist" % self.vm_name) os.chmod(self.image_path, stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO) else: if not virsh.domain_exists(self.vm_name): raise error.TestFail("Domain '%s' should exists, no matter its" " installation is succeed or failed!" % self.vm_name) else: if not self.kill_first: if self.vm.is_dead(): self.vm.start() try: self.vm.wait_for_login() except remote.LoginTimeoutError, detail: raise error.TestFail(str(detail)) else: virsh.remove_domain(self.vm_name)
def run(test, params, env): """ Test for virt-clone, it is used to clone a guest to another with given name. (1). Get source guest and destination guest name. (2). Clone source guest to dest guest with virt-clone. (3). Check the dest guest. """ # Get the full path of virt-clone command. VIRT_CLONE = os_dep.command("virt-clone") vm_name = params.get("main_vm", "virt-tests-vm1") vm = env.get_vm(vm_name) dest_guest_name = params.get("dest_vm", "test-clone") dest_guest_file = params.get("dest_image") dest_guest_path = None # Destroy and undefine the test-clone guest before # executing virt-clone command. virsh.remove_domain(dest_guest_name) cmd = "%s --connect=%s -o %s -n %s" % (VIRT_CLONE, vm.connect_uri, vm_name, dest_guest_name) domblklist_result = virsh.domblklist(vm_name) if len(domblklist_result.stdout.strip().splitlines()) >= 3: # We need a file for destination if guest has block devices. dest_guest_path = os.path.join(data_dir.get_data_dir(), dest_guest_file) if os.path.exists(dest_guest_path): os.remove(dest_guest_path) cmd = "%s -f %s" % (cmd, dest_guest_path) try: cmd_result = utils.run(cmd, ignore_status=True) if cmd_result.exit_status: raise error.TestFail("command of virt-clone failed.\n" "output: %s." % cmd_result) start_result = None # We will get an error of "error: monitor socket did not show up:" # when start vm immediately after virt-clone. def _start_success(): start_result = virsh.start(dest_guest_name) if start_result.exit_status: return False return True if not utils_misc.wait_for(_start_success, timeout=5): raise error.TestFail("command virt-clone exit successfully.\n" "but start it failed.\n Detail: %s." % start_result) finally: # cleanup remove the dest guest. virsh.remove_domain(dest_guest_name) # remove image file if we created it. if dest_guest_path and os.path.exists(dest_guest_path): os.remove(dest_guest_path)
def run(test, params, env): """ Test rbd disk device. 1.Prepare test environment,destroy or suspend a VM. 2.Prepare disk image. 3.Edit disks xml and start the domain. 4.Perform test operation. 5.Recover test environment. """ vm_name = params.get("main_vm") vm = env.get_vm(vm_name) virsh_dargs = {'debug': True, 'ignore_status': True} additional_xml_file = os.path.join(data_dir.get_tmp_dir(), "additional_disk.xml") def config_ceph(): """ Write the configs to the file. """ src_host = disk_src_host.split() src_port = disk_src_port.split() conf_str = "mon_host = " hosts = [] for host, port in zip(src_host, src_port): hosts.append("%s:%s" % (host, port)) with open(disk_src_config, 'w') as f: f.write(conf_str + ','.join(hosts) + '\n') def create_pool(): """ Define and start a pool. """ sp = libvirt_storage.StoragePool() if create_by_xml: p_xml = pool_xml.PoolXML(pool_type=pool_type) p_xml.name = pool_name s_xml = pool_xml.SourceXML() s_xml.vg_name = disk_src_pool source_host = [] for (host_name, host_port) in zip(disk_src_host.split(), disk_src_port.split()): source_host.append({'name': host_name, 'port': host_port}) s_xml.hosts = source_host if auth_type: s_xml.auth_type = auth_type if auth_user: s_xml.auth_username = auth_user if auth_usage: s_xml.secret_usage = auth_usage p_xml.source = s_xml logging.debug("Pool xml: %s", p_xml) p_xml.xmltreefile.write() ret = virsh.pool_define(p_xml.xml, **virsh_dargs) libvirt.check_exit_status(ret) ret = virsh.pool_build(pool_name, **virsh_dargs) libvirt.check_exit_status(ret) ret = virsh.pool_start(pool_name, **virsh_dargs) libvirt.check_exit_status(ret) else: auth_opt = "" if client_name and client_key: auth_opt = ( "--auth-type %s --auth-username %s --secret-usage '%s'" % (auth_type, auth_user, auth_usage)) if not sp.define_rbd_pool( pool_name, mon_host, disk_src_pool, extra=auth_opt): test.fail("Failed to define storage pool") if not sp.build_pool(pool_name): test.fail("Failed to build storage pool") if not sp.start_pool(pool_name): test.fail("Failed to start storage pool") # Check pool operation ret = virsh.pool_refresh(pool_name, **virsh_dargs) libvirt.check_exit_status(ret) ret = virsh.pool_uuid(pool_name, **virsh_dargs) libvirt.check_exit_status(ret) # pool-info pool_info = sp.pool_info(pool_name) if pool_info["Autostart"] != 'no': test.fail("Failed to check pool information") # pool-autostart if not sp.set_pool_autostart(pool_name): test.fail("Failed to set pool autostart") pool_info = sp.pool_info(pool_name) if pool_info["Autostart"] != 'yes': test.fail("Failed to check pool information") # pool-autostart --disable if not sp.set_pool_autostart(pool_name, "--disable"): test.fail("Failed to set pool autostart") # If port is not pre-configured, port value should not be hardcoded in pool information. if "yes" == params.get("rbd_port", "no"): if 'port' in virsh.pool_dumpxml(pool_name): test.fail("port attribute should not be in pool information") # find-storage-pool-sources-as if "yes" == params.get("find_storage_pool_sources_as", "no"): ret = virsh.find_storage_pool_sources_as("rbd", mon_host) libvirt.check_result(ret, skip_if=unsupported_err) def create_vol(vol_params): """ Create volume. :param p_name. Pool name. :param vol_params. Volume parameters dict. :return: True if create successfully. """ pvt = libvirt.PoolVolumeTest(test, params) if create_by_xml: pvt.pre_vol_by_xml(pool_name, **vol_params) else: pvt.pre_vol(vol_name, None, '2G', None, pool_name) def check_vol(vol_params): """ Check volume information. """ pv = libvirt_storage.PoolVolume(pool_name) # Supported operation if vol_name not in pv.list_volumes(): test.fail("Volume %s doesn't exist" % vol_name) ret = virsh.vol_dumpxml(vol_name, pool_name) libvirt.check_exit_status(ret) # vol-info if not pv.volume_info(vol_name): test.fail("Can't see volume info") # vol-key ret = virsh.vol_key(vol_name, pool_name) libvirt.check_exit_status(ret) if "%s/%s" % (disk_src_pool, vol_name) not in ret.stdout.strip(): test.fail("Volume key isn't correct") # vol-path ret = virsh.vol_path(vol_name, pool_name) libvirt.check_exit_status(ret) if "%s/%s" % (disk_src_pool, vol_name) not in ret.stdout.strip(): test.fail("Volume path isn't correct") # vol-pool ret = virsh.vol_pool("%s/%s" % (disk_src_pool, vol_name)) libvirt.check_exit_status(ret) if pool_name not in ret.stdout.strip(): test.fail("Volume pool isn't correct") # vol-name ret = virsh.vol_name("%s/%s" % (disk_src_pool, vol_name)) libvirt.check_exit_status(ret) if vol_name not in ret.stdout.strip(): test.fail("Volume name isn't correct") # vol-resize ret = virsh.vol_resize(vol_name, "2G", pool_name) libvirt.check_exit_status(ret) # Not supported operation # vol-clone ret = virsh.vol_clone(vol_name, cloned_vol_name, pool_name) libvirt.check_result(ret, skip_if=unsupported_err) # vol-create-from volxml = vol_xml.VolXML() vol_params.update({"name": "%s" % create_from_cloned_volume}) v_xml = volxml.new_vol(**vol_params) v_xml.xmltreefile.write() ret = virsh.vol_create_from(pool_name, v_xml.xml, vol_name, pool_name) libvirt.check_result(ret, skip_if=unsupported_err) # vol-wipe ret = virsh.vol_wipe(vol_name, pool_name) libvirt.check_result(ret, skip_if=unsupported_err) # vol-upload ret = virsh.vol_upload(vol_name, vm.get_first_disk_devices()['source'], "--pool %s" % pool_name) libvirt.check_result(ret, skip_if=unsupported_err) # vol-download ret = virsh.vol_download(vol_name, cloned_vol_name, "--pool %s" % pool_name) libvirt.check_result(ret, skip_if=unsupported_err) def check_qemu_cmd(): """ Check qemu command line options. """ cmd = ("ps -ef | grep %s | grep -v grep " % vm_name) process.run(cmd, shell=True) if disk_src_name: cmd += " | grep file=rbd:%s:" % disk_src_name if auth_user and auth_key: cmd += ('id=%s:auth_supported=cephx' % auth_user) if disk_src_config: cmd += " | grep 'conf=%s'" % disk_src_config elif mon_host: hosts = '\:6789\;'.join(mon_host.split()) cmd += " | grep 'mon_host=%s'" % hosts if driver_iothread: cmd += " | grep iothread%s" % driver_iothread # Run the command process.run(cmd, shell=True) def check_save_restore(): """ Test save and restore operation """ save_file = os.path.join(data_dir.get_tmp_dir(), "%s.save" % vm_name) ret = virsh.save(vm_name, save_file, **virsh_dargs) libvirt.check_exit_status(ret) ret = virsh.restore(save_file, **virsh_dargs) libvirt.check_exit_status(ret) if os.path.exists(save_file): os.remove(save_file) # Login to check vm status vm.wait_for_login().close() def check_snapshot(snap_option, target_dev='vda'): """ Test snapshot operation. """ snap_name = "s1" snap_mem = os.path.join(data_dir.get_tmp_dir(), "rbd.mem") snap_disk = os.path.join(data_dir.get_tmp_dir(), "rbd.disk") xml_snap_exp = [ "disk name='%s' snapshot='external' type='file'" % target_dev ] xml_dom_exp = [ "source file='%s'" % snap_disk, "backingStore type='network' index='1'", "source protocol='rbd' name='%s'" % disk_src_name ] if snap_option.count("disk-only"): options = ("%s --diskspec %s,file=%s --disk-only" % (snap_name, target_dev, snap_disk)) elif snap_option.count("disk-mem"): options = ("%s --memspec file=%s --diskspec %s,file=" "%s" % (snap_name, snap_mem, target_dev, snap_disk)) xml_snap_exp.append("memory snapshot='external' file='%s'" % snap_mem) else: options = snap_name ret = virsh.snapshot_create_as(vm_name, options) if test_disk_internal_snapshot or test_disk_readonly: libvirt.check_result(ret, expected_fails=unsupported_err) else: libvirt.check_result(ret, skip_if=unsupported_err) # check xml file. if not ret.exit_status: snap_xml = virsh.snapshot_dumpxml(vm_name, snap_name, debug=True).stdout.strip() dom_xml = virsh.dumpxml(vm_name, debug=True).stdout.strip() # Delete snapshots. libvirt.clean_up_snapshots(vm_name) if os.path.exists(snap_mem): os.remove(snap_mem) if os.path.exists(snap_disk): os.remove(snap_disk) if not all([x in snap_xml for x in xml_snap_exp]): test.fail("Failed to check snapshot xml") if not all([x in dom_xml for x in xml_dom_exp]): test.fail("Failed to check domain xml") def check_blockcopy(target): """ Block copy operation test. """ blk_file = os.path.join(data_dir.get_tmp_dir(), "blk.rbd") if os.path.exists(blk_file): os.remove(blk_file) blk_mirror = ("mirror type='file' file='%s' " "format='raw' job='copy'" % blk_file) # Do blockcopy ret = virsh.blockcopy(vm_name, target, blk_file) libvirt.check_result(ret, skip_if=unsupported_err) dom_xml = virsh.dumpxml(vm_name, debug=True).stdout.strip() if not dom_xml.count(blk_mirror): test.fail("Can't see block job in domain xml") # Abort ret = virsh.blockjob(vm_name, target, "--abort") libvirt.check_exit_status(ret) dom_xml = virsh.dumpxml(vm_name, debug=True).stdout.strip() if dom_xml.count(blk_mirror): test.fail("Failed to abort block job") if os.path.exists(blk_file): os.remove(blk_file) # Sleep for a while after abort operation. time.sleep(5) # Do blockcopy again ret = virsh.blockcopy(vm_name, target, blk_file) libvirt.check_exit_status(ret) # Wait for complete def wait_func(): ret = virsh.blockjob(vm_name, target, "--info") return ret.stderr.count("Block Copy: [100 %]") timeout = params.get("blockjob_timeout", 600) utils_misc.wait_for(wait_func, int(timeout)) # Pivot ret = virsh.blockjob(vm_name, target, "--pivot") libvirt.check_exit_status(ret) dom_xml = virsh.dumpxml(vm_name, debug=True).stdout.strip() if not dom_xml.count("source file='%s'" % blk_file): test.fail("Failed to pivot block job") # Remove the disk file. if os.path.exists(blk_file): os.remove(blk_file) def check_in_vm(vm_obj, target, old_parts, read_only=False): """ Check mount/read/write disk in VM. :param vm. VM guest. :param target. Disk dev in VM. :return: True if check successfully. """ try: session = vm_obj.wait_for_login() new_parts = utils_disk.get_parts_list(session) added_parts = list(set(new_parts).difference(set(old_parts))) logging.info("Added parts:%s", added_parts) if len(added_parts) != 1: logging.error("The number of new partitions is invalid in VM") return False added_part = None if target.startswith("vd"): if added_parts[0].startswith("vd"): added_part = added_parts[0] elif target.startswith("hd"): if added_parts[0].startswith("sd"): added_part = added_parts[0] if not added_part: logging.error("Can't see added partition in VM") return False cmd = ("mount /dev/{0} /mnt && ls /mnt && (sleep 15;" " touch /mnt/testfile; umount /mnt)".format(added_part)) s, o = session.cmd_status_output(cmd, timeout=60) session.close() logging.info("Check disk operation in VM:\n, %s, %s", s, o) # Readonly fs, check the error messages. # The command may return True, read-only # messges can be found from the command output if read_only: if "Read-only file system" not in o: return False else: return True # Other errors if s != 0: return False return True except (remote.LoginError, virt_vm.VMError, aexpect.ShellError) as e: logging.error(str(e)) return False def clean_up_volume_snapshots(): """ Get all snapshots for rbd_vol.img volume,unprotect and then clean up them. """ cmd = ("rbd -m {0} {1} info {2}" "".format(mon_host, key_opt, os.path.join(disk_src_pool, vol_name))) if process.run(cmd, ignore_status=True, shell=True).exit_status: return # Get snapshot list. cmd = ("rbd -m {0} {1} snap" " list {2}" "".format(mon_host, key_opt, os.path.join(disk_src_pool, vol_name))) snaps_out = process.run(cmd, ignore_status=True, shell=True).stdout_text snap_names = [] if snaps_out: for line in snaps_out.rsplit("\n"): if line.startswith("SNAPID") or line == "": continue snap_line = line.rsplit() if len(snap_line) == 4: snap_names.append(snap_line[1]) logging.debug("Find snapshots: %s", snap_names) # Unprotect snapshot first,otherwise it will fail to purge volume for snap_name in snap_names: cmd = ("rbd -m {0} {1} snap" " unprotect {2}@{3}" "".format(mon_host, key_opt, os.path.join(disk_src_pool, vol_name), snap_name)) process.run(cmd, ignore_status=True, shell=True) # Purge volume,and then delete volume. cmd = ("rbd -m {0} {1} info {2} && rbd -m {0} {1} snap" " purge {2} && rbd -m {0} {1} rm {2}" "".format(mon_host, key_opt, os.path.join(disk_src_pool, vol_name))) process.run(cmd, ignore_status=True, shell=True) def make_snapshot(): """ make external snapshots. :return external snapshot path list """ logging.info("Making snapshot...") first_disk_source = vm.get_first_disk_devices()['source'] snapshot_path_list = [] snapshot2_file = os.path.join(data_dir.get_tmp_dir(), "mem.s2") snapshot3_file = os.path.join(data_dir.get_tmp_dir(), "mem.s3") snapshot4_file = os.path.join(data_dir.get_tmp_dir(), "mem.s4") snapshot4_disk_file = os.path.join(data_dir.get_tmp_dir(), "disk.s4") snapshot5_file = os.path.join(data_dir.get_tmp_dir(), "mem.s5") snapshot5_disk_file = os.path.join(data_dir.get_tmp_dir(), "disk.s5") # Attempt to take different types of snapshots. snapshots_param_dict = { "s1": "s1 --disk-only --no-metadata", "s2": "s2 --memspec %s --no-metadata" % snapshot2_file, "s3": "s3 --memspec %s --no-metadata --live" % snapshot3_file, "s4": "s4 --memspec %s --diskspec vda,file=%s --no-metadata" % (snapshot4_file, snapshot4_disk_file), "s5": "s5 --memspec %s --diskspec vda,file=%s --live --no-metadata" % (snapshot5_file, snapshot5_disk_file) } for snapshot_name in sorted(snapshots_param_dict.keys()): ret = virsh.snapshot_create_as(vm_name, snapshots_param_dict[snapshot_name], **virsh_dargs) libvirt.check_exit_status(ret) if snapshot_name != 's4' and snapshot_name != 's5': snapshot_path_list.append( first_disk_source.replace('qcow2', snapshot_name)) return snapshot_path_list def get_secret_list(): """ Get secret list. :return secret list """ logging.info("Get secret list ...") secret_list_result = virsh.secret_list() secret_list = results_stdout_52lts( secret_list_result).strip().splitlines() # First two lines contain table header followed by entries # for each secret, such as: # # UUID Usage # -------------------------------------------------------------------------------- # b4e8f6d3-100c-4e71-9f91-069f89742273 ceph client.libvirt secret secret_list = secret_list[2:] result = [] # If secret list is empty. if secret_list: for line in secret_list: # Split on whitespace, assume 1 column linesplit = line.split(None, 1) result.append(linesplit[0]) return result mon_host = params.get("mon_host") disk_src_name = params.get("disk_source_name") disk_src_config = params.get("disk_source_config") disk_src_host = params.get("disk_source_host") disk_src_port = params.get("disk_source_port") disk_src_pool = params.get("disk_source_pool") disk_format = params.get("disk_format", "raw") driver_iothread = params.get("driver_iothread") snap_name = params.get("disk_snap_name") attach_device = "yes" == params.get("attach_device", "no") attach_disk = "yes" == params.get("attach_disk", "no") test_save_restore = "yes" == params.get("test_save_restore", "no") test_snapshot = "yes" == params.get("test_snapshot", "no") test_blockcopy = "yes" == params.get("test_blockcopy", "no") test_qemu_cmd = "yes" == params.get("test_qemu_cmd", "no") test_vm_parts = "yes" == params.get("test_vm_parts", "no") additional_guest = "yes" == params.get("additional_guest", "no") create_snapshot = "yes" == params.get("create_snapshot", "no") convert_image = "yes" == params.get("convert_image", "no") create_volume = "yes" == params.get("create_volume", "no") create_by_xml = "yes" == params.get("create_by_xml", "no") client_key = params.get("client_key") client_name = params.get("client_name") auth_key = params.get("auth_key") auth_user = params.get("auth_user") auth_type = params.get("auth_type") auth_usage = params.get("secret_usage") pool_name = params.get("pool_name") pool_type = params.get("pool_type") vol_name = params.get("vol_name") cloned_vol_name = params.get("cloned_volume", "cloned_test_volume") create_from_cloned_volume = params.get("create_from_cloned_volume", "create_from_cloned_test_volume") vol_cap = params.get("vol_cap") vol_cap_unit = params.get("vol_cap_unit") start_vm = "yes" == params.get("start_vm", "no") test_disk_readonly = "yes" == params.get("test_disk_readonly", "no") test_disk_internal_snapshot = "yes" == params.get( "test_disk_internal_snapshot", "no") test_json_pseudo_protocol = "yes" == params.get("json_pseudo_protocol", "no") disk_snapshot_with_sanlock = "yes" == params.get( "disk_internal_with_sanlock", "no") auth_place_in_source = params.get("auth_place_in_source") # Prepare a blank params to confirm if delete the configure at the end of the test ceph_cfg = "" # Create config file if it doesn't exist ceph_cfg = ceph.create_config_file(mon_host) # After libvirt 3.9.0, auth element can be put into source part. if auth_place_in_source and not libvirt_version.version_compare(3, 9, 0): test.cancel( "place auth in source is not supported in current libvirt version") # Start vm and get all partions in vm. if vm.is_dead(): vm.start() session = vm.wait_for_login() old_parts = utils_disk.get_parts_list(session) session.close() vm.destroy(gracefully=False) if additional_guest: guest_name = "%s_%s" % (vm_name, '1') timeout = params.get("clone_timeout", 360) utils_libguestfs.virt_clone_cmd(vm_name, guest_name, True, timeout=timeout, ignore_status=False) additional_vm = vm.clone(guest_name) if start_vm: virsh.start(guest_name) # Back up xml file. vmxml_backup = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) key_opt = "" secret_uuid = None snapshot_path = None key_file = os.path.join(data_dir.get_tmp_dir(), "ceph.key") img_file = os.path.join(data_dir.get_tmp_dir(), "%s_test.img" % vm_name) front_end_img_file = os.path.join(data_dir.get_tmp_dir(), "%s_frontend_test.img" % vm_name) # Construct a unsupported error message list to skip these kind of tests unsupported_err = [] if driver_iothread: unsupported_err.append('IOThreads not supported') if test_snapshot: unsupported_err.append('live disk snapshot not supported') if test_disk_readonly: if not libvirt_version.version_compare(5, 0, 0): unsupported_err.append('Could not create file: Permission denied') unsupported_err.append('Permission denied') else: unsupported_err.append( 'unsupported configuration: external snapshot ' + 'for readonly disk vdb is not supported') if test_disk_internal_snapshot: unsupported_err.append( 'unsupported configuration: internal snapshot for disk ' + 'vdb unsupported for storage type raw') if test_blockcopy: unsupported_err.append('block copy is not supported') if attach_disk: unsupported_err.append('No such file or directory') if create_volume: unsupported_err.append("backing 'volume' disks isn't yet supported") unsupported_err.append('this function is not supported') try: # Clean up dirty secrets in test environments if there have. dirty_secret_list = get_secret_list() if dirty_secret_list: for dirty_secret_uuid in dirty_secret_list: virsh.secret_undefine(dirty_secret_uuid) # Prepare test environment. qemu_config = LibvirtQemuConfig() if disk_snapshot_with_sanlock: # Install necessary package:sanlock,libvirt-lock-sanlock if not utils_package.package_install(["sanlock"]): test.error("fail to install sanlock") if not utils_package.package_install(["libvirt-lock-sanlock"]): test.error("fail to install libvirt-lock-sanlock") # Set virt_use_sanlock result = process.run("setsebool -P virt_use_sanlock 1", shell=True) if result.exit_status: test.error("Failed to set virt_use_sanlock value") # Update lock_manager in qemu.conf qemu_config.lock_manager = 'sanlock' # Update qemu-sanlock.conf. san_lock_config = LibvirtSanLockConfig() san_lock_config.user = '******' san_lock_config.group = 'sanlock' san_lock_config.host_id = 1 san_lock_config.auto_disk_leases = True process.run("mkdir -p /var/lib/libvirt/sanlock", shell=True) san_lock_config.disk_lease_dir = "/var/lib/libvirt/sanlock" san_lock_config.require_lease_for_disks = False # Start sanlock service and restart libvirtd to enforce changes. result = process.run("systemctl start wdmd", shell=True) if result.exit_status: test.error("Failed to start wdmd service") result = process.run("systemctl start sanlock", shell=True) if result.exit_status: test.error("Failed to start sanlock service") utils_libvirtd.Libvirtd().restart() # Prepare lockspace and lease file for sanlock in order. sanlock_cmd_dict = OrderedDict() sanlock_cmd_dict[ "truncate -s 1M /var/lib/libvirt/sanlock/TEST_LS"] = "Failed to truncate TEST_LS" sanlock_cmd_dict[ "sanlock direct init -s TEST_LS:0:/var/lib/libvirt/sanlock/TEST_LS:0"] = "Failed to sanlock direct init TEST_LS:0" sanlock_cmd_dict[ "chown sanlock:sanlock /var/lib/libvirt/sanlock/TEST_LS"] = "Failed to chown sanlock TEST_LS" sanlock_cmd_dict[ "restorecon -R -v /var/lib/libvirt/sanlock"] = "Failed to restorecon sanlock" sanlock_cmd_dict[ "truncate -s 1M /var/lib/libvirt/sanlock/test-disk-resource-lock"] = "Failed to truncate test-disk-resource-lock" sanlock_cmd_dict[ "sanlock direct init -r TEST_LS:test-disk-resource-lock:" + "/var/lib/libvirt/sanlock/test-disk-resource-lock:0"] = "Failed to sanlock direct init test-disk-resource-lock" sanlock_cmd_dict[ "chown sanlock:sanlock " + "/var/lib/libvirt/sanlock/test-disk-resource-lock"] = "Failed to chown test-disk-resource-loc" sanlock_cmd_dict[ "sanlock client add_lockspace -s TEST_LS:1:" + "/var/lib/libvirt/sanlock/TEST_LS:0"] = "Failed to client add_lockspace -s TEST_LS:0" for sanlock_cmd in sanlock_cmd_dict.keys(): result = process.run(sanlock_cmd, shell=True) if result.exit_status: test.error(sanlock_cmd_dict[sanlock_cmd]) # Create one lease device and add it to VM. san_lock_vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) lease_device = Lease() lease_device.lockspace = 'TEST_LS' lease_device.key = 'test-disk-resource-lock' lease_device.target = { 'path': '/var/lib/libvirt/sanlock/test-disk-resource-lock' } san_lock_vmxml.add_device(lease_device) san_lock_vmxml.sync() # Install ceph-common package which include rbd command if utils_package.package_install(["ceph-common"]): if client_name and client_key: with open(key_file, 'w') as f: f.write("[%s]\n\tkey = %s\n" % (client_name, client_key)) key_opt = "--keyring %s" % key_file # Create secret xml sec_xml = secret_xml.SecretXML("no", "no") sec_xml.usage = auth_type sec_xml.usage_name = auth_usage sec_xml.xmltreefile.write() logging.debug("Secret xml: %s", sec_xml) ret = virsh.secret_define(sec_xml.xml) libvirt.check_exit_status(ret) secret_uuid = re.findall(r".+\S+(\ +\S+)\ +.+\S+", ret.stdout.strip())[0].lstrip() logging.debug("Secret uuid %s", secret_uuid) if secret_uuid is None: test.error("Failed to get secret uuid") # Set secret value auth_key = params.get("auth_key") ret = virsh.secret_set_value(secret_uuid, auth_key, **virsh_dargs) libvirt.check_exit_status(ret) # Delete the disk if it exists cmd = ("rbd -m {0} {1} info {2} && rbd -m {0} {1} rm " "{2}".format(mon_host, key_opt, disk_src_name)) process.run(cmd, ignore_status=True, shell=True) else: test.error("Failed to install ceph-common") if disk_src_config: config_ceph() disk_path = ("rbd:%s:mon_host=%s" % (disk_src_name, mon_host)) if auth_user and auth_key: disk_path += (":id=%s:key=%s" % (auth_user, auth_key)) targetdev = params.get("disk_target", "vdb") # To be compatible with create_disk_xml function, # some parameters need to be updated. params.update({ "type_name": params.get("disk_type", "network"), "target_bus": params.get("disk_target_bus"), "target_dev": targetdev, "secret_uuid": secret_uuid, "source_protocol": params.get("disk_source_protocol"), "source_name": disk_src_name, "source_host_name": disk_src_host, "source_host_port": disk_src_port }) # Prepare disk image if convert_image: first_disk = vm.get_first_disk_devices() blk_source = first_disk['source'] # Convert the image to remote storage disk_cmd = ("rbd -m %s %s info %s 2> /dev/null|| qemu-img convert" " -O %s %s %s" % (mon_host, key_opt, disk_src_name, disk_format, blk_source, disk_path)) process.run(disk_cmd, ignore_status=False, shell=True) elif create_volume: vol_params = { "name": vol_name, "capacity": int(vol_cap), "capacity_unit": vol_cap_unit, "format": disk_format } create_pool() create_vol(vol_params) check_vol(vol_params) else: # Create an local image and make FS on it. disk_cmd = ("qemu-img create -f %s %s 10M && mkfs.ext4 -F %s" % (disk_format, img_file, img_file)) process.run(disk_cmd, ignore_status=False, shell=True) # Convert the image to remote storage disk_cmd = ( "rbd -m %s %s info %s 2> /dev/null|| qemu-img convert -O" " %s %s %s" % (mon_host, key_opt, disk_src_name, disk_format, img_file, disk_path)) process.run(disk_cmd, ignore_status=False, shell=True) # Create disk snapshot if needed. if create_snapshot: snap_cmd = ("rbd -m %s %s snap create %s@%s" % (mon_host, key_opt, disk_src_name, snap_name)) process.run(snap_cmd, ignore_status=False, shell=True) if test_json_pseudo_protocol: # Create one frontend image with the rbd backing file. json_str = ('json:{"file.driver":"rbd",' '"file.filename":"rbd:%s:mon_host=%s"}' % (disk_src_name, mon_host)) # pass different json string according to the auth config if auth_user and auth_key: json_str = ('%s:id=%s:key=%s"}' % (json_str[:-2], auth_user, auth_key)) disk_cmd = ("qemu-img create -f qcow2 -b '%s' %s" % (json_str, front_end_img_file)) disk_path = front_end_img_file process.run(disk_cmd, ignore_status=False, shell=True) # If hot plug, start VM first, and then wait the OS boot. # Otherwise stop VM if running. if start_vm: if vm.is_dead(): vm.start() vm.wait_for_login().close() else: if not vm.is_dead(): vm.destroy() if attach_device: if create_volume: params.update({"source_pool": pool_name}) params.update({"type_name": "volume"}) # No need auth options for volume if "auth_user" in params: params.pop("auth_user") if "auth_type" in params: params.pop("auth_type") if "secret_type" in params: params.pop("secret_type") if "secret_uuid" in params: params.pop("secret_uuid") if "secret_usage" in params: params.pop("secret_usage") # After 3.9.0,the auth element can be place in source part. if auth_place_in_source: params.update({"auth_in_source": auth_place_in_source}) xml_file = libvirt.create_disk_xml(params) if additional_guest: # Copy xml_file for additional guest VM. shutil.copyfile(xml_file, additional_xml_file) opts = params.get("attach_option", "") ret = virsh.attach_device(vm_name, xml_file, flagstr=opts, debug=True) libvirt.check_result(ret, skip_if=unsupported_err) if additional_guest: # Make sure the additional VM is running if additional_vm.is_dead(): additional_vm.start() additional_vm.wait_for_login().close() ret = virsh.attach_device(guest_name, additional_xml_file, "", debug=True) libvirt.check_result(ret, skip_if=unsupported_err) elif attach_disk: opts = params.get("attach_option", "") ret = virsh.attach_disk(vm_name, disk_path, targetdev, opts) libvirt.check_result(ret, skip_if=unsupported_err) elif test_disk_readonly: params.update({'readonly': "yes"}) xml_file = libvirt.create_disk_xml(params) opts = params.get("attach_option", "") ret = virsh.attach_device(vm_name, xml_file, flagstr=opts, debug=True) libvirt.check_result(ret, skip_if=unsupported_err) elif test_disk_internal_snapshot: xml_file = libvirt.create_disk_xml(params) opts = params.get("attach_option", "") ret = virsh.attach_device(vm_name, xml_file, flagstr=opts, debug=True) libvirt.check_result(ret, skip_if=unsupported_err) elif disk_snapshot_with_sanlock: if vm.is_dead(): vm.start() snapshot_path = make_snapshot() if vm.is_alive(): vm.destroy() elif not create_volume: libvirt.set_vm_disk(vm, params) if test_blockcopy: logging.info("Creating %s...", vm_name) vmxml_for_test = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) if vm.is_alive(): vm.destroy(gracefully=False) vm.undefine() if virsh.create(vmxml_for_test.xml, **virsh_dargs).exit_status: vmxml_backup.define() test.fail("Can't create the domain") elif vm.is_dead(): vm.start() # Wait for vm is running vm.wait_for_login(timeout=600).close() if additional_guest: if additional_vm.is_dead(): additional_vm.start() # Check qemu command line if test_qemu_cmd: check_qemu_cmd() # Check partitions in vm if test_vm_parts: if not check_in_vm( vm, targetdev, old_parts, read_only=create_snapshot): test.fail("Failed to check vm partitions") if additional_guest: if not check_in_vm(additional_vm, targetdev, old_parts): test.fail("Failed to check vm partitions") # Save and restore operation if test_save_restore: check_save_restore() if test_snapshot: snap_option = params.get("snapshot_option", "") check_snapshot(snap_option) if test_blockcopy: check_blockcopy(targetdev) if test_disk_readonly: snap_option = params.get("snapshot_option", "") check_snapshot(snap_option, 'vdb') if test_disk_internal_snapshot: snap_option = params.get("snapshot_option", "") check_snapshot(snap_option, targetdev) # Detach the device. if attach_device: xml_file = libvirt.create_disk_xml(params) ret = virsh.detach_device(vm_name, xml_file) libvirt.check_exit_status(ret) if additional_guest: ret = virsh.detach_device(guest_name, xml_file) libvirt.check_exit_status(ret) elif attach_disk: ret = virsh.detach_disk(vm_name, targetdev) libvirt.check_exit_status(ret) # Check disk in vm after detachment. if attach_device or attach_disk: session = vm.wait_for_login() new_parts = utils_disk.get_parts_list(session) if len(new_parts) != len(old_parts): test.fail("Disk still exists in vm" " after detachment") session.close() except virt_vm.VMStartError as details: for msg in unsupported_err: if msg in str(details): test.cancel(str(details)) else: test.fail("VM failed to start." "Error: %s" % str(details)) finally: # Remove ceph configure file if created. if ceph_cfg: os.remove(ceph_cfg) # Delete snapshots. 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") # Recover VM. if vm.is_alive(): vm.destroy(gracefully=False) if additional_guest: virsh.remove_domain(guest_name, "--remove-all-storage", ignore_stauts=True) # Remove the snapshot. if create_snapshot: cmd = ("rbd -m {0} {1} info {2} && rbd -m {0} {1} snap" " purge {2} && rbd -m {0} {1} rm {2}" "".format(mon_host, key_opt, disk_src_name)) process.run(cmd, ignore_status=True, shell=True) elif create_volume: cmd = ("rbd -m {0} {1} info {2} && rbd -m {0} {1} rm {2}" "".format(mon_host, key_opt, os.path.join(disk_src_pool, cloned_vol_name))) process.run(cmd, ignore_status=True, shell=True) cmd = ("rbd -m {0} {1} info {2} && rbd -m {0} {1} rm {2}" "".format( mon_host, key_opt, os.path.join(disk_src_pool, create_from_cloned_volume))) process.run(cmd, ignore_status=True, shell=True) clean_up_volume_snapshots() else: cmd = ("rbd -m {0} {1} info {2} && rbd -m {0} {1} rm {2}" "".format(mon_host, key_opt, disk_src_name)) process.run(cmd, ignore_status=True, shell=True) # Delete tmp files. if os.path.exists(key_file): os.remove(key_file) if os.path.exists(img_file): os.remove(img_file) # Clean up volume, pool if vol_name and vol_name in str(virsh.vol_list(pool_name).stdout): virsh.vol_delete(vol_name, pool_name) if pool_name and pool_name in virsh.pool_state_dict(): virsh.pool_destroy(pool_name, **virsh_dargs) virsh.pool_undefine(pool_name, **virsh_dargs) # Clean up secret secret_list = get_secret_list() if secret_list: for secret_uuid in secret_list: virsh.secret_undefine(secret_uuid) logging.info("Restoring vm...") vmxml_backup.sync() if disk_snapshot_with_sanlock: # Restore virt_use_sanlock setting. process.run("setsebool -P virt_use_sanlock 0", shell=True) # Restore qemu config qemu_config.restore() utils_libvirtd.Libvirtd().restart() # Force shutdown sanlock service. process.run("sanlock client shutdown -f 1", shell=True) # Clean up lockspace folder process.run("rm -rf /var/lib/libvirt/sanlock/*", shell=True) if snapshot_path is not None: for snapshot in snapshot_path: if os.path.exists(snapshot): os.remove(snapshot)
else: test.fail("VM failed to start." "Error: %s" % str(details)) finally: # Delete snapshots. 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") # Recover VM. if vm.is_alive(): vm.destroy(gracefully=False) if additional_guest: virsh.remove_domain(guest_name, "--remove-all-storage", ignore_stauts=True) # Remove the snapshot. if create_snapshot: cmd = ("rbd -m {0} {1} info {2} && rbd -m {0} {1} snap" " purge {2} && rbd -m {0} {1} rm {2}" "".format(mon_host, key_opt, disk_src_name)) process.run(cmd, ignore_status=True, shell=True) elif create_volume: cmd = ("rbd -m {0} {1} info {2} && rbd -m {0} {1} rm {2}" "".format(mon_host, key_opt, os.path.join(disk_src_pool, cloned_vol_name))) process.run(cmd, ignore_status=True, shell=True) cmd = ("rbd -m {0} {1} info {2} && rbd -m {0} {1} rm {2}" "".format( mon_host, key_opt,
def run(test, params, env): """ Test interafce xml options. 1.Prepare test environment,destroy or suspend a VM. 2.Edit xml and start the domain. 3.Perform test operation. 4.Recover test environment. 5.Confirm the test result. """ vm_name = params.get("main_vm") vm = env.get_vm(vm_name) virsh_dargs = {'debug': True, 'ignore_status': False} def create_iface_xml(iface_mac): """ Create interface xml file """ iface = Interface(type_name=iface_type) source = ast.literal_eval(iface_source) if source: iface.source = source iface.model = iface_model if iface_model else "virtio" iface.mac_address = iface_mac driver_dict = {} driver_host = {} driver_guest = {} if iface_driver: driver_dict = ast.literal_eval(iface_driver) if iface_driver_host: driver_host = ast.literal_eval(iface_driver_host) if iface_driver_guest: driver_guest = ast.literal_eval(iface_driver_guest) iface.driver = iface.new_driver(driver_attr=driver_dict, driver_host=driver_host, driver_guest=driver_guest) logging.debug("Create new interface xml: %s", iface) return iface def modify_iface_xml(update, status_error=False): """ Modify interface xml options """ vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) xml_devices = vmxml.devices iface_index = xml_devices.index( xml_devices.by_device_tag("interface")[0]) iface = xml_devices[iface_index] if iface_model: iface.model = iface_model else: del iface.model if iface_type: iface.type_name = iface_type del iface.source source = ast.literal_eval(iface_source) if source: net_ifs = utils_net.get_net_if(state="UP") # Check source device is valid or not, # if it's not in host interface list, try to set # source device to first active interface of host if (iface.type_name == "direct" and source.has_key('dev') and source['dev'] not in net_ifs): logging.warn("Source device %s is not a interface" " of host, reset to %s", source['dev'], net_ifs[0]) source['dev'] = net_ifs[0] iface.source = source backend = ast.literal_eval(iface_backend) if backend: iface.backend = backend driver_dict = {} driver_host = {} driver_guest = {} if iface_driver: driver_dict = ast.literal_eval(iface_driver) if iface_driver_host: driver_host = ast.literal_eval(iface_driver_host) if iface_driver_guest: driver_guest = ast.literal_eval(iface_driver_guest) iface.driver = iface.new_driver(driver_attr=driver_dict, driver_host=driver_host, driver_guest=driver_guest) if iface.address: del iface.address logging.debug("New interface xml file: %s", iface) if unprivileged_user: # Create disk image for unprivileged user disk_index = xml_devices.index( xml_devices.by_device_tag("disk")[0]) disk_xml = xml_devices[disk_index] logging.debug("source: %s", disk_xml.source) disk_source = disk_xml.source.attrs["file"] cmd = ("cp -fZ {0} {1} && chown {2}:{2} {1}" "".format(disk_source, dst_disk, unprivileged_user)) utils.run(cmd) disk_xml.source = disk_xml.new_disk_source( attrs={"file": dst_disk}) vmxml.devices = xml_devices # Remove all channels to avoid of permission problem channels = vmxml.get_devices(device_type="channel") for channel in channels: vmxml.del_device(channel) vmxml.xmltreefile.write() logging.debug("New VM xml: %s", vmxml) utils.run("chmod a+rw %s" % vmxml.xml) virsh.define(vmxml.xml, **virsh_dargs) # Try to modify interface xml by update-device or edit xml elif update: iface.xmltreefile.write() ret = virsh.update_device(vm_name, iface.xml, ignore_status=True) libvirt.check_exit_status(ret, status_error) else: vmxml.devices = xml_devices vmxml.xmltreefile.write() vmxml.sync() def check_offloads_option(if_name, driver_options, session=None): """ Check interface offloads by ethtool output """ offloads = {"csum": "tx-checksumming", "gso": "generic-segmentation-offload", "tso4": "tcp-segmentation-offload", "tso6": "tx-tcp6-segmentation", "ecn": "tx-tcp-ecn-segmentation", "ufo": "udp-fragmentation-offload"} if session: ret, output = session.cmd_status_output("ethtool -k %s | head" " -18" % if_name) else: out = utils.run("ethtool -k %s | head -18" % if_name) ret, output = out.exit_status, out.stdout if ret: raise error.TestFail("ethtool return error code") logging.debug("ethtool output: %s", output) for offload in driver_options.keys(): if offloads.has_key(offload): if (output.count(offloads[offload]) and not output.count("%s: %s" % ( offloads[offload], driver_options[offload]))): raise error.TestFail("offloads option %s: %s isn't" " correct in ethtool output" % (offloads[offload], driver_options[offload])) def run_xml_test(iface_mac): """ Test for interface options in vm xml """ # Get the interface object according the mac address vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) iface_devices = vmxml.get_devices(device_type="interface") iface = None for iface_dev in iface_devices: if iface_dev.mac_address == iface_mac: iface = iface_dev if not iface: raise error.TestFail("Can't find interface with mac" " '%s' in vm xml" % iface_mac) driver_dict = {} if iface_driver: driver_dict = ast.literal_eval(iface_driver) for driver_opt in driver_dict.keys(): if not driver_dict[driver_opt] == iface.driver.driver_attr[driver_opt]: raise error.TestFail("Can't see driver option %s=%s in vm xml" % (driver_opt, driver_dict[driver_opt])) if iface_target: if (not iface.target.has_key("dev") or not iface.target["dev"].startswith(iface_target)): raise error.TestFail("Can't see device target dev in vm xml") # Check macvtap mode by ip link command if iface_target == "macvtap" and iface.source.has_key("mode"): cmd = "ip -d link show %s" % iface.target["dev"] output = utils.run(cmd).stdout logging.debug("ip link output: %s", output) mode = iface.source["mode"] if mode == "passthrough": mode = "passthru" if not output.count("macvtap mode %s" % mode): raise error.TestFail("Failed to verify macvtap mode") def run_cmdline_test(iface_mac): """ Test for qemu-kvm command line options """ cmd = ("ps -ef | grep %s | grep -v grep " % vm_name) if test_vhost_net: cmd += " | grep 'vhost=on'" ret = utils.run(cmd) if ret.exit_status: raise error.TestFail("Can't parse qemu-kvm command line") logging.debug("Command line %s", ret.stdout) if iface_model == "virtio": model_option = "device virtio-net-pci" else: model_option = "device rtl8139" iface_cmdline = re.findall(r"%s,(.+),mac=%s" % (model_option, iface_mac), ret.stdout) if not iface_cmdline: raise error.TestFail("Can't see %s with mac %s in command" " line" % (model_option, iface_mac)) cmd_opt = {} for opt in iface_cmdline[0].split(','): tmp = opt.rsplit("=") cmd_opt[tmp[0]] = tmp[1] logging.debug("Command line options %s", cmd_opt) driver_dict = {} # Test <driver> xml options. if iface_driver: iface_driver_dict = ast.literal_eval(iface_driver) for driver_opt in iface_driver_dict.keys(): if driver_opt == "name": continue elif driver_opt == "txmode": if iface_driver_dict["txmode"] == "iothread": driver_dict["tx"] = "bh" else: driver_dict["tx"] = iface_driver_dict["txmode"] elif driver_opt == "queues": driver_dict["mq"] = "on" driver_dict["vectors"] = str(int( iface_driver_dict["queues"]) * 2 + 2) else: driver_dict[driver_opt] = iface_driver_dict[driver_opt] # Test <driver><host/><driver> xml options. if iface_driver_host: driver_dict.update(ast.literal_eval(iface_driver_host)) # Test <driver><guest/><driver> xml options. if iface_driver_guest: driver_dict.update(ast.literal_eval(iface_driver_guest)) for driver_opt in driver_dict.keys(): if (not cmd_opt.has_key(driver_opt) or not cmd_opt[driver_opt] == driver_dict[driver_opt]): raise error.TestFail("Can't see option '%s=%s' in qemu-kvm " " command line" % (driver_opt, driver_dict[driver_opt])) if test_backend: guest_pid = ret.stdout.rsplit()[1] cmd = "lsof %s | grep %s" % (backend["tap"], guest_pid) if utils.system(cmd, ignore_status=True): raise error.TestFail("Guest process didn't open backend file" % backend["tap"]) cmd = "lsof %s | grep %s" % (backend["vhost"], guest_pid) if utils.system(cmd, ignore_status=True): raise error.TestFail("Guest process didn't open backend file" % backend["tap"]) def get_guest_ip(session, mac): """ Wrapper function to get guest ip address """ utils_net.restart_guest_network(session, mac) # Wait for IP address is ready utils_misc.wait_for( lambda: utils_net.get_guest_ip_addr(session, mac), 10) return utils_net.get_guest_ip_addr(session, mac) def check_user_network(session): """ Check user network ip address on guest """ vm_ips = [] vm_ips.append(get_guest_ip(session, iface_mac_old)) if attach_device: vm_ips.append(get_guest_ip(session, iface_mac)) logging.debug("IP address on guest: %s", vm_ips) if len(vm_ips) != len(set(vm_ips)): raise error.TestFail("Duplicated IP address on guest. " "Check bug: https://bugzilla.redhat." "com/show_bug.cgi?id=1147238") for vm_ip in vm_ips: if vm_ip is None or not vm_ip.startswith("10.0.2."): raise error.TestFail("Found wrong IP address" " on guest") # Check gateway address gateway = utils_net.get_net_gateway(session.cmd_output) if gateway != "10.0.2.2": raise error.TestFail("The gateway on guest is not" " right") # Check dns server address ns_list = utils_net.get_net_nameserver(session.cmd_output) if "10.0.2.3" not in ns_list: raise error.TestFail("The dns server can't be found" " on guest") def check_mcast_network(session): """ Check multicast ip address on guests """ src_addr = ast.literal_eval(iface_source)['address'] add_session = additional_vm.wait_for_serial_login() vms_sess_dict = {vm_name: session, additional_vm.name: add_session} # Check mcast address on host cmd = "netstat -g | grep %s" % src_addr if utils.run(cmd, ignore_status=True).exit_status: raise error.TestFail("Can't find multicast ip address" " on host") vms_ip_dict = {} # Get ip address on each guest for vms in vms_sess_dict.keys(): vm_mac = vm_xml.VMXML.get_first_mac_by_name(vms) vm_ip = get_guest_ip(vms_sess_dict[vms], vm_mac) if not vm_ip: raise error.TestFail("Can't get multicast ip" " address on guest") vms_ip_dict.update({vms: vm_ip}) if len(set(vms_ip_dict.values())) != len(vms_sess_dict): raise error.TestFail("Got duplicated multicast ip address") logging.debug("Found ips on guest: %s", vms_ip_dict) # Run omping server on host if not utils_misc.yum_install(["omping"]): raise error.TestError("Failed to install omping" " on host") cmd = ("iptables -F;omping -m %s %s" % (src_addr, "192.168.122.1 %s" % ' '.join(vms_ip_dict.values()))) # Run a backgroup job waiting for connection of client bgjob = utils.AsyncJob(cmd) # Run omping client on guests for vms in vms_sess_dict.keys(): # omping should be installed first if not utils_misc.yum_install(["omping"], vms_sess_dict[vms]): raise error.TestError("Failed to install omping" " on guest") cmd = ("iptables -F; omping -c 5 -T 5 -m %s %s" % (src_addr, "192.168.122.1 %s" % vms_ip_dict[vms])) ret, output = vms_sess_dict[vms].cmd_status_output(cmd) logging.debug("omping ret: %s, output: %s", ret, output) if (not output.count('multicast, xmt/rcv/%loss = 5/5/0%') or not output.count('unicast, xmt/rcv/%loss = 5/5/0%')): raise error.TestFail("omping failed on guest") # Kill the backgroup job bgjob.kill_func() status_error = "yes" == params.get("status_error", "no") start_error = "yes" == params.get("start_error", "no") unprivileged_user = params.get("unprivileged_user") # Interface specific attributes. iface_type = params.get("iface_type", "network") iface_source = params.get("iface_source", "{}") iface_driver = params.get("iface_driver") iface_model = params.get("iface_model") iface_target = params.get("iface_target") iface_backend = params.get("iface_backend", "{}") iface_driver_host = params.get("iface_driver_host") iface_driver_guest = params.get("iface_driver_guest") attach_device = params.get("attach_iface_device") change_option = "yes" == params.get("change_iface_options", "no") update_device = "yes" == params.get("update_iface_device", "no") additional_guest = "yes" == params.get("additional_guest", "no") serial_login = "******" == params.get("serial_login", "no") test_option_cmd = "yes" == params.get( "test_iface_option_cmd", "no") test_option_xml = "yes" == params.get( "test_iface_option_xml", "no") test_vhost_net = "yes" == params.get( "test_vhost_net", "no") test_option_offloads = "yes" == params.get( "test_option_offloads", "no") test_iface_user = "******" == params.get( "test_iface_user", "no") test_iface_mcast = "yes" == params.get( "test_iface_mcast", "no") test_libvirtd = "yes" == params.get("test_libvirtd", "no") test_guest_ip = "yes" == params.get("test_guest_ip", "no") test_backend = "yes" == params.get("test_backend", "no") if iface_driver_host or iface_driver_guest or test_backend: if not libvirt_version.version_compare(1, 2, 8): raise error.TestNAError("Offloading/backend options not " "supported in this libvirt version") if iface_driver and "queues" in ast.literal_eval(iface_driver): if not libvirt_version.version_compare(1, 0, 6): raise error.TestNAError("Queues options not supported" " in this libvirt version") if unprivileged_user: virsh_dargs["unprivileged_user"] = unprivileged_user # Create unprivileged user if needed cmd = ("grep {0} /etc/passwd || " "useradd {0}".format(unprivileged_user)) utils.run(cmd) # Need another disk image for unprivileged user to access dst_disk = "/tmp/%s.img" % unprivileged_user # Destroy VM first if vm.is_alive(): vm.destroy(gracefully=False) # Back up xml file. vmxml_backup = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) iface_mac_old = vm_xml.VMXML.get_first_mac_by_name(vm_name) # iface_mac will update if attach a new interface iface_mac = iface_mac_old # Additional vm for test additional_vm = None libvirtd = utils_libvirtd.Libvirtd() try: # Build the xml and run test. try: # Prepare interface backend files if test_backend: if not os.path.exists("/dev/vhost-net"): utils.run("modprobe vhost-net") backend = ast.literal_eval(iface_backend) backend_tap = "/dev/net/tun" backend_vhost = "/dev/vhost-net" if not backend: backend["tap"] = backend_tap backend["vhost"] = backend_vhost if not start_error: # Create backend files for normal test if not os.path.exists(backend["tap"]): os.rename(backend_tap, backend["tap"]) if not os.path.exists(backend["vhost"]): os.rename(backend_vhost, backend["vhost"]) # Edit the interface xml. if change_option: modify_iface_xml(update=False) # Check vhost driver. if test_vhost_net: if os.path.exists("/dev/vhost-net"): cmd = ("modprobe -r {0}; lsmod | " "grep {0}".format("vhost_net")) if not utils.system(cmd, ignore_status=True): raise error.TestError("Can't remove " "vhost_net driver") # Attach a interface when vm is shutoff if attach_device == 'config': iface_mac = utils_net.generate_mac_address_simple() iface_xml_obj = create_iface_xml(iface_mac) iface_xml_obj.xmltreefile.write() ret = virsh.attach_device(vm_name, iface_xml_obj.xml, flagstr="--config", ignore_status=True) libvirt.check_exit_status(ret) # Clone additional vm if additional_guest: guest_name = "%s_%s" % (vm_name, '1') # Clone additional guest timeout = params.get("clone_timeout", 360) utils_libguestfs.virt_clone_cmd(vm_name, guest_name, True, timeout=timeout) additional_vm = vm.clone(guest_name) additional_vm.start() #additional_vm.wait_for_login() # Start the VM. if unprivileged_user: virsh.start(vm_name, **virsh_dargs) cmd = ("su - %s -c 'virsh console %s'" % (unprivileged_user, vm_name)) session = aexpect.ShellSession(cmd) session.sendline() remote.handle_prompts(session, params.get("username"), params.get("password"), "[\#\$]", 30) # Get ip address on guest if not get_guest_ip(session, iface_mac): raise error.TestError("Can't get ip address on guest") else: # Will raise VMStartError exception if start fails vm.start() if serial_login: session = vm.wait_for_serial_login() else: session = vm.wait_for_login() if start_error: raise error.TestFail("VM started unexpectedly") if test_vhost_net: if utils.system("lsmod | grep vhost_net", ignore_status=True): raise error.TestFail("vhost_net module can't be" " loaded automatically") # Attach a interface when vm is running if attach_device == 'live': iface_mac = utils_net.generate_mac_address_simple() iface_xml_obj = create_iface_xml(iface_mac) iface_xml_obj.xmltreefile.write() ret = virsh.attach_device(vm_name, iface_xml_obj.xml, flagstr="--live", ignore_status=True) libvirt.check_exit_status(ret) # Need sleep here for attachment take effect time.sleep(5) # Update a interface options if update_device: modify_iface_xml(update=True, status_error=status_error) # Run tests for qemu-kvm command line options if test_option_cmd: run_cmdline_test(iface_mac) # Run tests for vm xml if test_option_xml: run_xml_test(iface_mac) # Run tests for offloads options if test_option_offloads: if iface_driver_host: ifname_guest = utils_net.get_linux_ifname( session, iface_mac) check_offloads_option( ifname_guest, ast.literal_eval( iface_driver_host), session) if iface_driver_guest: ifname_host = libvirt.get_ifname_host(vm_name, iface_mac) check_offloads_option( ifname_host, ast.literal_eval(iface_driver_guest)) if test_iface_user: # Test user type network check_user_network(session) if test_iface_mcast: # Test mcast type network check_mcast_network(session) # Check guest ip address if test_guest_ip: if not get_guest_ip(session, iface_mac): raise error.TestFail("Guest can't get a" " valid ip address") session.close() # Restart libvirtd and guest, then test again if test_libvirtd: libvirtd.restart() vm.destroy() vm.start() if test_option_xml: run_xml_test(iface_mac) # Detach hot/cold-plugged interface at last if attach_device: ret = virsh.detach_device(vm_name, iface_xml_obj.xml, flagstr="", ignore_status=True) libvirt.check_exit_status(ret) except virt_vm.VMStartError, e: logging.info(str(e)) if start_error: pass else: raise error.TestFail('VM Failed to start for some reason!') finally: # Recover VM. logging.info("Restoring vm...") # Restore interface backend files if test_backend: if not os.path.exists(backend_tap): os.rename(backend["tap"], backend_tap) if not os.path.exists(backend_vhost): os.rename(backend["vhost"], backend_vhost) if unprivileged_user: virsh.remove_domain(vm_name, "--remove-all-storage", **virsh_dargs) if additional_vm: virsh.remove_domain(additional_vm.name, "--remove-all-storage") # Kill all omping server process on host utils.system("pidof omping && killall omping", ignore_status=True) if vm.is_alive(): vm.destroy(gracefully=False) vmxml_backup.sync()
elif test_undefine: vm_undefine_check(vm_name) elif autostart_bypass_cache: libvirtd.stop() virsh_cmd = ("(service libvirtd start)") check_flags_parallel(virsh_cmd, bash_cmd % (managed_save_file, managed_save_file, "0"), flags) elif test_loop_cmd: loop_range = params.get("loop_range", "20") vm_managedsave_loop(vm_name, loop_range, libvirtd) else: vm_recover_check(option, libvirtd, check_shutdown) finally: # Restore test environment. # Restart libvirtd.service qemu_config.restore() libvirt_guests_config.restore() libvirtd.restart() if autostart_bypass_cache: virsh.autostart(vm_name, "--disable", ignore_status=True, debug=True) vm.destroy(gracefully=False) virsh.managedsave_remove(vm_name, debug=True) vmxml_backup.sync() if multi_guests: for i in range(int(multi_guests)): virsh.remove_domain("%s_%s" % (vm_name, i), "--remove-all-storage", debug=True)
def run(test, params, env): """ Test interafce xml options. 1.Prepare test environment,destroy or suspend a VM. 2.Edit xml and start the domain. 3.Perform test operation. 4.Recover test environment. 5.Confirm the test result. """ vm_name = params.get("main_vm") vm = env.get_vm(vm_name) def prepare_pxe_boot(): """ Prepare tftp server and pxe boot files """ pkg_list = ["syslinux", "tftp-server", "tftp", "ipxe-roms-qemu", "wget"] # Try to install required packages if not utils_package.package_install(pkg_list): test.error("Failed ot install required packages") boot_initrd = params.get("boot_initrd", "EXAMPLE_INITRD") boot_vmlinuz = params.get("boot_vmlinuz", "EXAMPLE_VMLINUZ") if boot_initrd.count("EXAMPLE") or boot_vmlinuz.count("EXAMPLE"): test.cancel("Please provide initrd/vmlinuz URL") # Download pxe boot images process.system("wget %s -O %s/initrd.img" % (boot_initrd, tftp_root)) process.system("wget %s -O %s/vmlinuz" % (boot_vmlinuz, tftp_root)) process.system("cp -f /usr/share/syslinux/pxelinux.0 {0};" " mkdir -m 777 -p {0}/pxelinux.cfg".format(tftp_root), shell=True) pxe_file = "%s/pxelinux.cfg/default" % tftp_root boot_txt = """ DISPLAY boot.txt DEFAULT rhel LABEL rhel kernel vmlinuz append initrd=initrd.img PROMPT 1 TIMEOUT 3""" with open(pxe_file, 'w') as p_file: p_file.write(boot_txt) def modify_iface_xml(): """ Modify interface xml options """ vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) if pxe_boot: # Config boot console for pxe boot osxml = vm_xml.VMOSXML() osxml.type = vmxml.os.type osxml.arch = vmxml.os.arch osxml.machine = vmxml.os.machine osxml.loader = "/usr/share/seabios/bios.bin" osxml.bios_useserial = "yes" osxml.bios_reboot_timeout = "-1" osxml.boots = ['network'] del vmxml.os vmxml.os = osxml xml_devices = vmxml.devices iface_index = xml_devices.index( xml_devices.by_device_tag("interface")[0]) iface = xml_devices[iface_index] iface_bandwidth = {} iface_inbound = ast.literal_eval(iface_bandwidth_inbound) iface_outbound = ast.literal_eval(iface_bandwidth_outbound) if iface_inbound: iface_bandwidth["inbound"] = iface_inbound if iface_outbound: iface_bandwidth["outbound"] = iface_outbound if iface_bandwidth: bandwidth = iface.new_bandwidth(**iface_bandwidth) iface.bandwidth = bandwidth iface_type = params.get("iface_type", "network") iface.type_name = iface_type source = ast.literal_eval(iface_source) if not source: source = {"network": "default"} net_ifs = utils_net.get_net_if(state="UP") # Check source device is valid or not, # if it's not in host interface list, try to set # source device to first active interface of host if (iface.type_name == "direct" and 'dev' in source and source['dev'] not in net_ifs): logging.warn("Source device %s is not a interface" " of host, reset to %s", source['dev'], net_ifs[0]) source['dev'] = net_ifs[0] del iface.source iface.source = source iface_model = params.get("iface_model", "virtio") iface.model = iface_model logging.debug("New interface xml file: %s", iface) vmxml.devices = xml_devices vmxml.xmltreefile.write() vmxml.sync() def run_dnsmasq_default_test(key, value=None, exists=True, name="default"): """ Test dnsmasq configuration. :param key: key in conf file to check :param value: value in conf file to check :param exists: check the key:value exist or not :param name: The name of conf file """ conf_file = "/var/lib/libvirt/dnsmasq/%s.conf" % name if not os.path.exists(conf_file): test.cancel("Can't find %s.conf file" % name) configs = "" with open(conf_file, 'r') as f: configs = f.read() logging.debug("configs in file %s: %s", conf_file, configs) if value: config = "%s=%s" % (key, value) else: config = key if not configs.count(config): if exists: test.fail("Can't find %s=%s in configuration file" % (key, value)) else: if not exists: test.fail("Found %s=%s in configuration file" % (key, value)) def run_dnsmasq_addnhosts_test(hostip, hostnames): """ Test host ip and names configuration """ conf_file = "/var/lib/libvirt/dnsmasq/default.addnhosts" hosts_re = ".*".join(hostnames) configs = "" with open(conf_file, 'r') as f: configs = f.read() logging.debug("configs in file %s: %s", conf_file, configs) if not re.search(r"%s.*%s" % (hostip, hosts_re), configs, re.M): test.fail("Can't find '%s' in configuration file" % hostip) def run_dnsmasq_host_test(iface_mac, guest_ip, guest_name): """ Test host name and ip configuration for dnsmasq """ conf_file = "/var/lib/libvirt/dnsmasq/default.hostsfile" config = "%s,%s,%s" % (iface_mac, guest_ip, guest_name) configs = "" with open(conf_file, 'r') as f: configs = f.read() logging.debug("configs in file %s: %s", conf_file, configs) if not configs.count(config): test.fail("Can't find host configuration in file %s" % conf_file) def check_class_rules(ifname, rule_id, bandwidth): """ Check bandwidth settings via 'tc class' output """ cmd = "tc class show dev %s" % ifname class_output = to_text(process.system_output(cmd)) logging.debug("Bandwidth class output: %s", class_output) class_pattern = (r"class htb %s.*rate (\d+)(K?M?)bit ceil" " (\d+)(K?M?)bit burst (\d+)(K?M?)b.*" % rule_id) se = re.search(class_pattern, class_output, re.M) if not se: test.fail("Can't find outbound setting for htb %s" % rule_id) logging.debug("bandwidth from tc output:%s" % str(se.groups())) rate = None if "floor" in bandwidth: rate = int(bandwidth["floor"]) * 8 elif "average" in bandwidth: rate = int(bandwidth["average"]) * 8 if rate: if se.group(2) == 'M': rate_check = int(se.group(1)) * 1000 else: rate_check = int(se.group(1)) assert rate_check == rate if "peak" in bandwidth: if se.group(4) == 'M': ceil_check = int(se.group(3)) * 1000 else: ceil_check = int(se.group(3)) assert ceil_check == int(bandwidth["peak"]) * 8 if "burst" in bandwidth: if se.group(6) == 'M': tc_burst = int(se.group(5)) * 1024 else: tc_burst = int(se.group(5)) assert tc_burst == int(bandwidth["burst"]) def check_filter_rules(ifname, bandwidth): """ Check bandwidth settings via 'tc filter' output """ cmd = "tc -d filter show dev %s parent ffff:" % ifname filter_output = to_text(process.system_output(cmd)) logging.debug("Bandwidth filter output: %s", filter_output) if not filter_output.count("filter protocol all pref"): test.fail("Can't find 'protocol all' settings in filter rules") filter_pattern = ".*police.*rate (\d+)(K?M?)bit burst (\d+)(K?M?)b.*" se = re.search(r"%s" % filter_pattern, filter_output, re.M) if not se: test.fail("Can't find any filter policy") logging.debug("bandwidth from tc output:%s" % str(se.groups())) logging.debug("bandwidth from setting:%s" % str(bandwidth)) if "average" in bandwidth: if se.group(2) == 'M': tc_average = int(se.group(1)) * 1000 else: tc_average = int(se.group(1)) assert tc_average == int(bandwidth["average"]) * 8 if "burst" in bandwidth: if se.group(4) == 'M': tc_burst = int(se.group(3)) * 1024 else: tc_burst = int(se.group(3)) assert tc_burst == int(bandwidth["burst"]) def check_host_routes(): """ Check network routes on host """ for rt in routes: try: route = ast.literal_eval(rt) addr = "%s/%s" % (route["address"], route["prefix"]) cmd = "ip route list %s" % addr if "family" in route and route["family"] == "ipv6": cmd = "ip -6 route list %s" % addr output = to_text(process.system_output(cmd)) match_obj = re.search(r"via (\S+).*metric (\d+)", output) if match_obj: via_addr = match_obj.group(1) metric = match_obj.group(2) logging.debug("via address %s for %s, matric is %s" % (via_addr, addr, metric)) assert via_addr == route["gateway"] if "metric" in route: assert metric == route["metric"] except KeyError: pass def run_bandwidth_test(check_net=False, check_iface=False): """ Test bandwidth option for network or interface by tc command. """ iface_inbound = ast.literal_eval(iface_bandwidth_inbound) iface_outbound = ast.literal_eval(iface_bandwidth_outbound) net_inbound = ast.literal_eval(net_bandwidth_inbound) net_outbound = ast.literal_eval(net_bandwidth_outbound) net_bridge_name = ast.literal_eval(net_bridge)["name"] iface_name = libvirt.get_ifname_host(vm_name, iface_mac) try: if check_net and net_inbound: # Check qdisc rules cmd = "tc -d qdisc show dev %s" % net_bridge_name qdisc_output = to_text(process.system_output(cmd)) logging.debug("Bandwidth qdisc output: %s", qdisc_output) if not qdisc_output.count("qdisc ingress ffff:"): test.fail("Can't find ingress setting") check_class_rules(net_bridge_name, "1:1", {"average": net_inbound["average"], "peak": net_inbound["peak"]}) check_class_rules(net_bridge_name, "1:2", net_inbound) # Check filter rules on bridge interface if check_net and net_outbound: check_filter_rules(net_bridge_name, net_outbound) # Check class rules on interface inbound settings if check_iface and iface_inbound: check_class_rules(iface_name, "1:1", {'average': iface_inbound['average'], 'peak': iface_inbound['peak'], 'burst': iface_inbound['burst']}) if "floor" in iface_inbound: if not libvirt_version.version_compare(1, 0, 1): test.cancel("Not supported Qos options 'floor'") check_class_rules(net_bridge_name, "1:3", {'floor': iface_inbound["floor"]}) # Check filter rules on interface outbound settings if check_iface and iface_outbound: check_filter_rules(iface_name, iface_outbound) except AssertionError: stacktrace.log_exc_info(sys.exc_info()) test.fail("Failed to check network bandwidth") def check_name_ip(session): """ Check dns resolving on guest """ # Check if bind-utils is installed if not utils_package.package_install(['bind-utils'], session): test.error("Failed to install bind-utils on guest") # Run host command to check if hostname can be resolved if not guest_ipv4 and not guest_ipv6: test.fail("No ip address found from parameters") guest_ip = guest_ipv4 if guest_ipv4 else guest_ipv6 cmd = "host %s | grep %s" % (guest_name, guest_ip) if session.cmd_status(cmd): test.fail("Can't resolve name %s on guest" % guest_name) def check_ipt_rules(check_ipv4=True, check_ipv6=False): """ Check iptables for network/interface """ br_name = ast.literal_eval(net_bridge)["name"] net_forward = ast.literal_eval(params.get("net_forward", "{}")) net_ipv4 = params.get("net_ipv4") net_ipv6 = params.get("net_ipv6") ipt_rules = ("INPUT -i %s -p udp -m udp --dport 53 -j ACCEPT" % br_name, "INPUT -i %s -p tcp -m tcp --dport 53 -j ACCEPT" % br_name, "INPUT -i %s -p udp -m udp --dport 67 -j ACCEPT" % br_name, "INPUT -i %s -p tcp -m tcp --dport 67 -j ACCEPT" % br_name, "FORWARD -i {0} -o {0} -j ACCEPT".format(br_name), "FORWARD -o %s -j REJECT --reject-with icmp" % br_name, "FORWARD -i %s -j REJECT --reject-with icmp" % br_name, "OUTPUT -o %s -p udp -m udp --dport 68 -j ACCEPT" % br_name) net_dev_in = "" net_dev_out = "" if "dev" in net_forward: net_dev_in = " -i %s" % net_forward["dev"] net_dev_out = " -o %s" % net_forward["dev"] if check_ipv4: ipv4_rules = list(ipt_rules) ctr_rule = "" nat_rules = [] if "mode" in net_forward and net_forward["mode"] == "nat": nat_port = ast.literal_eval(params.get("nat_port")) p_start = nat_port["start"] p_end = nat_port["end"] ctr_rule = " -m .* RELATED,ESTABLISHED" nat_rules = [("POSTROUTING -s {0} ! -d {0} -p tcp -j MASQUERADE" " --to-ports {1}-{2}".format(net_ipv4, p_start, p_end)), ("POSTROUTING -s {0} ! -d {0} -p udp -j MASQUERADE" " --to-ports {1}-{2}".format(net_ipv4, p_start, p_end)), ("POSTROUTING -s {0} ! -d {0} -p udp" " -j MASQUERADE".format(net_ipv4))] if nat_rules: ipv4_rules.extend(nat_rules) if (net_ipv4 and "mode" in net_forward and net_forward["mode"] in ["nat", "route"]): rules = [("FORWARD -d %s%s -o %s%s -j ACCEPT" % (net_ipv4, net_dev_in, br_name, ctr_rule)), ("FORWARD -s %s -i %s%s -j ACCEPT" % (net_ipv4, br_name, net_dev_out))] ipv4_rules.extend(rules) output = to_text(process.system_output('iptables-save')) logging.debug("iptables: %s", output) if "mode" in net_forward and net_forward["mode"] == "open": if re.search(r"%s|%s" % (net_ipv4, br_name), output, re.M): test.fail("Find iptable rule for open mode") utils_libvirtd.libvirtd_restart() output_again = to_text(process.system_output('iptables-save')) if re.search(r"%s|%s" % (net_ipv4, br_name), output_again, re.M): test.fail("Find iptable rule for open mode after restart " "libvirtd") else: logging.info("Can't find iptable rule for open mode as expected") else: for ipt in ipv4_rules: if not re.search(r"%s" % ipt, output, re.M): test.fail("Can't find iptable rule:\n%s" % ipt) return ipv4_rules if check_ipv6: ipv6_rules = list(ipt_rules) if (net_ipv6 and "mode" in net_forward and net_forward["mode"] in ["nat", "route"]): rules = [("FORWARD -d %s%s -o %s -j ACCEPT" % (net_ipv6, net_dev_in, br_name)), ("FORWARD -s %s -i %s%s -j ACCEPT" % (net_ipv6, br_name, net_dev_out))] ipv6_rules.extend(rules) output = to_text(process.system_output("ip6tables-save")) logging.debug("iptables: %s", output) for ipt in ipv6_rules: if not output.count(ipt): test.fail("Can't find ipbtable rule:\n%s" % ipt) return ipv6_rules def run_ip_test(session, ip_ver): """ Check iptables on host and ipv6 address on guest """ if ip_ver == "ipv6": # Clean up iptables rules for guest to get ipv6 address session.cmd_status("ip6tables -F") # It may take some time to get the ip address def get_ip_func(): return utils_net.get_guest_ip_addr(session, iface_mac, ip_version=ip_ver) utils_misc.wait_for(get_ip_func, 5) if not get_ip_func(): utils_net.restart_guest_network(session, iface_mac, ip_version=ip_ver) utils_misc.wait_for(get_ip_func, 5) vm_ip = get_ip_func() logging.debug("Guest has ip: %s", vm_ip) if not vm_ip: test.fail("Can't find ip address on guest") ip_gateway = net_ip_address if ip_ver == "ipv6": ip_gateway = net_ipv6_address # Cleanup ip6talbes on host for ping6 test process.system("ip6tables -F") if ip_gateway and not routes: ping_s, _ = ping(dest=ip_gateway, count=5, timeout=10, session=session) if ping_s: test.fail("Failed to ping gateway address: %s" % ip_gateway) def run_guest_libvirt(session): """ Check guest libvirt network """ # Try to install required packages if not utils_package.package_install(['libvirt'], session): test.error("Failed ot install libvirt package on guest") # Try to load tun module first session.cmd("lsmod | grep tun || modprobe tun") # Check network state on guest cmd = ("service libvirtd restart; virsh net-info default" " | grep 'Active:.*yes'") if session.cmd_status(cmd): test.fail("'default' network isn't in active state") # Try to destroy&start default network on guest for opt in ['net-destroy', 'net-start']: cmd = "virsh %s default" % opt status, output = session.cmd_status_output(cmd) logging.debug("Run %s on guest exit %s, output %s" % (cmd, status, output)) if status: test.fail(output) if not utils_package.package_remove("libvirt*", session): test.error("Failed to remove libvirt packages on guest") start_error = "yes" == params.get("start_error", "no") define_error = "yes" == params.get("define_error", "no") restart_error = "yes" == params.get("restart_error", "no") # network specific attributes. net_name = params.get("net_name", "default") net_bridge = params.get("net_bridge", "{'name':'virbr0'}") net_domain = params.get("net_domain") net_ip_address = params.get("net_ip_address") net_ipv6_address = params.get("net_ipv6_address") net_dns_forward = params.get("net_dns_forward") net_dns_txt = params.get("net_dns_txt") net_dns_srv = params.get("net_dns_srv") net_dns_hostip = params.get("net_dns_hostip") net_dns_hostnames = params.get("net_dns_hostnames", "").split() dhcp_start_ipv4 = params.get("dhcp_start_ipv4") dhcp_end_ipv4 = params.get("dhcp_end_ipv4") dhcp_start_ipv6 = params.get("dhcp_start_ipv6") dhcp_end_ipv6 = params.get("dhcp_end_ipv6") guest_name = params.get("guest_name") guest_ipv4 = params.get("guest_ipv4") guest_ipv6 = params.get("guest_ipv6") tftp_root = params.get("tftp_root") pxe_boot = "yes" == params.get("pxe_boot", "no") routes = params.get("routes", "").split() net_bandwidth_inbound = params.get("net_bandwidth_inbound", "{}") net_bandwidth_outbound = params.get("net_bandwidth_outbound", "{}") iface_bandwidth_inbound = params.get("iface_bandwidth_inbound", "{}") iface_bandwidth_outbound = params.get("iface_bandwidth_outbound", "{}") iface_num = params.get("iface_num", "1") iface_source = params.get("iface_source", "{}") multiple_guests = params.get("multiple_guests") create_network = "yes" == params.get("create_network", "no") attach_iface = "yes" == params.get("attach_iface", "no") serial_login = "******" == params.get("serial_login", "no") change_iface_option = "yes" == params.get("change_iface_option", "no") test_bridge = "yes" == params.get("test_bridge", "no") test_dnsmasq = "yes" == params.get("test_dnsmasq", "no") test_dhcp_range = "yes" == params.get("test_dhcp_range", "no") test_dns_host = "yes" == params.get("test_dns_host", "no") test_qos_bandwidth = "yes" == params.get("test_qos_bandwidth", "no") test_pg_bandwidth = "yes" == params.get("test_portgroup_bandwidth", "no") test_qos_remove = "yes" == params.get("test_qos_remove", "no") test_ipv4_address = "yes" == params.get("test_ipv4_address", "no") test_ipv6_address = "yes" == params.get("test_ipv6_address", "no") test_guest_libvirt = "yes" == params.get("test_guest_libvirt", "no") net_no_bridge = "yes" == params.get("no_bridge", "no") net_no_mac = "yes" == params.get("no_mac", "no") net_no_ip = "yes" == params.get("no_ip", "no") net_with_dev = "yes" == params.get("with_dev", "no") username = params.get("username") password = params.get("password") ipt_rules = [] # Destroy VM first if vm.is_alive(): vm.destroy(gracefully=False) # Back up xml file. netxml_backup = NetworkXML.new_from_net_dumpxml("default") iface_mac = vm_xml.VMXML.get_first_mac_by_name(vm_name) params["guest_mac"] = iface_mac vmxml_backup = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) vms_list = [] if "floor" in ast.literal_eval(iface_bandwidth_inbound): if not libvirt_version.version_compare(1, 0, 1): test.cancel("Not supported Qos options 'floor'") # Enabling IPv6 forwarding with RA routes without accept_ra set to 2 # is likely to cause routes loss sysctl_cmd = 'sysctl net.ipv6.conf.all.accept_ra' original_accept_ra = to_text(process.system_output(sysctl_cmd + ' -n')) if test_ipv6_address and original_accept_ra != '2': process.system(sysctl_cmd + '=2') # Build the xml and run test. try: if test_dnsmasq: # Check the settings before modifying network xml if net_dns_forward == "no": run_dnsmasq_default_test("domain-needed", exists=False) run_dnsmasq_default_test("local", "//", exists=False) if net_domain: run_dnsmasq_default_test("domain", net_domain, exists=False) run_dnsmasq_default_test("expand-hosts", exists=False) # Prepare pxe boot directory if pxe_boot: prepare_pxe_boot() # Edit the network xml or create a new one. if create_network: net_ifs = utils_net.get_net_if(state="UP") # Check forward device is valid or not, # if it's not in host interface list, try to set # forward device to first active interface of host forward = ast.literal_eval(params.get("net_forward", "{}")) if ('mode' in forward and forward['mode'] in ['passthrough', 'private', 'bridge', 'macvtap'] and 'dev' in forward and forward['dev'] not in net_ifs): logging.warn("Forward device %s is not a interface" " of host, reset to %s", forward['dev'], net_ifs[0]) forward['dev'] = net_ifs[0] params["net_forward"] = str(forward) forward_iface = params.get("forward_iface") if forward_iface: interface = [x for x in forward_iface.split()] # The guest will use first interface of the list, # check if it's valid or not, if it's not in host # interface list, try to set forward interface to # first active interface of host. if interface[0] not in net_ifs: logging.warn("Forward interface %s is not a " " interface of host, reset to %s", interface[0], net_ifs[0]) interface[0] = net_ifs[0] params["forward_iface"] = " ".join(interface) netxml = libvirt.create_net_xml(net_name, params) if "mode" in forward and forward["mode"] == "open": netxml.mac = utils_net.generate_mac_address_simple() try: if net_no_bridge: netxml.del_bridge() if net_no_ip: netxml.del_ip() netxml.del_ip() if net_no_mac: netxml.del_mac() except xcepts.LibvirtXMLNotFoundError: pass if net_with_dev: net_forward = netxml.forward net_forward.update({"dev": net_ifs[0]}) netxml.forward = net_forward logging.info("netxml before define is %s", netxml) try: netxml.sync() except xcepts.LibvirtXMLError as details: logging.info(str(details)) if define_error: return else: test.fail("Failed to define network") # Check open mode network xml if "mode" in forward and forward["mode"] == "open": netxml_new = NetworkXML.new_from_net_dumpxml(net_name) logging.info("netxml after define is %s", netxml_new) try: if net_no_bridge: net_bridge = str(netxml_new.bridge) if net_no_mac: netxml_new.mac except xcepts.LibvirtXMLNotFoundError as details: test.fail("Failed to check %s xml: %s" % (net_name, details)) logging.info("mac/bridge still exist even if removed before define") # Edit the interface xml. if change_iface_option: modify_iface_xml() # Attach interface if needed if attach_iface: iface_type = params.get("iface_type", "network") iface_model = params.get("iface_model", "virtio") for i in range(int(iface_num)): logging.info("Try to attach interface loop %s" % i) options = ("%s %s --model %s --config" % (iface_type, net_name, iface_model)) ret = virsh.attach_interface(vm_name, options, ignore_status=True) if ret.exit_status: logging.error("Command output %s" % ret.stdout.strip()) test.fail("Failed to attach-interface") if multiple_guests: # Clone more vms for testing for i in range(int(multiple_guests)): guest_name = "%s_%s" % (vm_name, i) timeout = params.get("clone_timeout", 360) utils_libguestfs.virt_clone_cmd(vm_name, guest_name, True, timeout=timeout) vms_list.append(vm.clone(guest_name)) if test_bridge: bridge = ast.literal_eval(net_bridge) br_if = utils_net.Interface(bridge['name']) if not br_if.is_up(): test.fail("Bridge interface isn't up") if test_dnsmasq: # Check dnsmasq process dnsmasq_cmd = to_text(process.system_output("ps -aux|grep dnsmasq", shell=True)) logging.debug(dnsmasq_cmd) if not re.search("dnsmasq --conf-file=/var/lib/libvirt/dnsmasq/%s.conf" % net_name, dnsmasq_cmd): test.fail("Can not find dnsmasq process or the process is not correct") # Check the settings in dnsmasq config file if net_dns_forward == "no": run_dnsmasq_default_test("domain-needed") run_dnsmasq_default_test("local", "//") if net_domain: run_dnsmasq_default_test("domain", net_domain) run_dnsmasq_default_test("expand-hosts") if net_bridge: bridge = ast.literal_eval(net_bridge) run_dnsmasq_default_test("interface", bridge['name'], name=net_name) if 'stp' in bridge and bridge['stp'] == 'on': if 'delay' in bridge and bridge['delay'] != '0': br_delay = float(bridge['delay']) cmd = ("brctl showstp %s | grep 'bridge forward delay'" % bridge['name']) out = to_text(process.system_output( cmd, shell=True, ignore_status=False)) logging.debug("brctl showstp output: %s", out) pattern = (r"\s*forward delay\s+(\d+.\d+)\s+bridge" " forward delay\s+(\d+.\d+)") match_obj = re.search(pattern, out, re.M) if not match_obj or len(match_obj.groups()) != 2: test.fail("Can't see forward delay messages from command") elif (float(match_obj.groups()[0]) != br_delay or float(match_obj.groups()[1]) != br_delay): test.fail("Foward delay setting can't take effect") if dhcp_start_ipv4 and dhcp_end_ipv4: run_dnsmasq_default_test("dhcp-range", "%s,%s" % (dhcp_start_ipv4, dhcp_end_ipv4), name=net_name) if dhcp_start_ipv6 and dhcp_end_ipv6: run_dnsmasq_default_test("dhcp-range", "%s,%s,64" % (dhcp_start_ipv6, dhcp_end_ipv6), name=net_name) if guest_name and guest_ipv4: run_dnsmasq_host_test(iface_mac, guest_ipv4, guest_name) # check the left part in dnsmasq conf run_dnsmasq_default_test("strict-order", name=net_name) run_dnsmasq_default_test("pid-file", "/var/run/libvirt/network/%s.pid" % net_name, name=net_name) run_dnsmasq_default_test("except-interface", "lo", name=net_name) run_dnsmasq_default_test("bind-dynamic", name=net_name) run_dnsmasq_default_test("dhcp-no-override", name=net_name) if dhcp_start_ipv6 and dhcp_start_ipv4: run_dnsmasq_default_test("dhcp-lease-max", "493", name=net_name) else: range_num = int(params.get("dhcp_range", "252")) run_dnsmasq_default_test("dhcp-lease-max", str(range_num+1), name=net_name) run_dnsmasq_default_test("dhcp-hostsfile", "/var/lib/libvirt/dnsmasq/%s.hostsfile" % net_name, name=net_name) run_dnsmasq_default_test("addn-hosts", "/var/lib/libvirt/dnsmasq/%s.addnhosts" % net_name, name=net_name) if dhcp_start_ipv6: run_dnsmasq_default_test("enable-ra", name=net_name) if test_dns_host: if net_dns_txt: dns_txt = ast.literal_eval(net_dns_txt) run_dnsmasq_default_test("txt-record", "%s,%s" % (dns_txt["name"], dns_txt["value"])) if net_dns_srv: dns_srv = ast.literal_eval(net_dns_srv) run_dnsmasq_default_test("srv-host", "_%s._%s.%s,%s,%s,%s,%s" % (dns_srv["service"], dns_srv["protocol"], dns_srv["domain"], dns_srv["target"], dns_srv["port"], dns_srv["priority"], dns_srv["weight"])) if net_dns_hostip and net_dns_hostnames: run_dnsmasq_addnhosts_test(net_dns_hostip, net_dns_hostnames) # Run bandwidth test for network if test_qos_bandwidth: run_bandwidth_test(check_net=True) # Check routes if needed if routes: check_host_routes() try: # Start the VM. vm.start() if start_error: test.fail("VM started unexpectedly") if pxe_boot: # Just check network boot messages here vm.serial_console.read_until_output_matches( ["Loading vmlinuz", "Loading initrd.img"], utils_misc.strip_console_codes) output = vm.serial_console.get_stripped_output() logging.debug("Boot messages: %s", output) else: if serial_login: session = vm.wait_for_serial_login(username=username, password=password) else: session = vm.wait_for_login() if test_dhcp_range: dhcp_range = int(params.get("dhcp_range", "252")) utils_net.restart_guest_network(session, iface_mac) vm_ip = utils_net.get_guest_ip_addr(session, iface_mac) logging.debug("Guest has ip: %s", vm_ip) if not vm_ip and dhcp_range: test.fail("Guest has invalid ip address") elif vm_ip and not dhcp_range: test.fail("Guest has ip address: %s" % vm_ip) dhcp_range = dhcp_range - 1 for vms in vms_list: # Start other VMs. vms.start() sess = vms.wait_for_serial_login() vms_mac = vms.get_virsh_mac_address() # restart guest network to get ip addr utils_net.restart_guest_network(sess, vms_mac) vms_ip = utils_net.get_guest_ip_addr(sess, vms_mac) if not vms_ip and dhcp_range: test.fail("Guest has invalid ip address") elif vms_ip and not dhcp_range: # Get IP address on guest should return Null # if it exceeds the dhcp range test.fail("Guest has ip address: %s" % vms_ip) dhcp_range = dhcp_range - 1 if vms_ip: ping_s, _ = ping(dest=vm_ip, count=5, timeout=10, session=sess) if ping_s: test.fail("Failed to ping, src: %s, " "dst: %s" % (vms_ip, vm_ip)) sess.close() # Check dnsmasq settings if take affect in guest if guest_ipv4: check_name_ip(session) # Run bandwidth test for interface if test_qos_bandwidth: run_bandwidth_test(check_iface=True) # Run bandwidth test for portgroup if test_pg_bandwidth: pg_bandwidth_inbound = params.get( "portgroup_bandwidth_inbound", "").split() pg_bandwidth_outbound = params.get( "portgroup_bandwidth_outbound", "").split() pg_name = params.get("portgroup_name", "").split() pg_default = params.get("portgroup_default", "").split() iface_inbound = ast.literal_eval(iface_bandwidth_inbound) iface_outbound = ast.literal_eval(iface_bandwidth_outbound) iface_name = libvirt.get_ifname_host(vm_name, iface_mac) if_source = ast.literal_eval(iface_source) if "portgroup" in if_source: pg = if_source["portgroup"] else: pg = "default" for (name, df, bw_ib, bw_ob) in zip(pg_name, pg_default, pg_bandwidth_inbound, pg_bandwidth_outbound): if pg == name: inbound = ast.literal_eval(bw_ib) outbound = ast.literal_eval(bw_ob) elif pg == "default" and df == "yes": inbound = ast.literal_eval(bw_ib) outbound = ast.literal_eval(bw_ob) else: continue # Interface bandwidth settings will # overwriting portgroup settings if iface_inbound: inbound = iface_inbound if iface_outbound: outbound = iface_outbound check_class_rules(iface_name, "1:1", inbound) check_filter_rules(iface_name, outbound) if test_qos_remove: # Remove the bandwidth settings in network xml logging.debug("Removing network bandwidth settings...") netxml_backup.sync() vm.destroy(gracefully=False) # Should fail to start vm vm.start() if restart_error: test.fail("VM started unexpectedly") if test_ipv6_address: ipt_rules = check_ipt_rules(check_ipv6=True) if not ("mode" in forward and forward["mode"] == "open"): run_ip_test(session, "ipv6") if test_ipv4_address: ipt_rules = check_ipt_rules(check_ipv4=True) if not ("mode" in forward and forward["mode"] == "open"): run_ip_test(session, "ipv4") if test_guest_libvirt: run_guest_libvirt(session) session.close() except virt_vm.VMStartError as details: logging.info(str(details)) if not (start_error or restart_error): test.fail('VM failed to start:\n%s' % details) # Destroy created network and check iptable rules if net_name != "default": virsh.net_destroy(net_name) if ipt_rules: output_des = to_text(process.system_output('iptables-save')) for ipt in ipt_rules: if re.search(r"%s" % ipt, output_des, re.M): test.fail("Find iptable rule %s after net destroyed" % ipt) finally: # Recover VM. if vm.is_alive(): vm.destroy(gracefully=False) for vms in vms_list: virsh.remove_domain(vms.name, "--remove-all-storage") logging.info("Restoring network...") if net_name == "default": netxml_backup.sync() else: # Destroy and undefine new created network virsh.net_destroy(net_name) virsh.net_undefine(net_name) vmxml_backup.sync() if test_ipv6_address and original_accept_ra != '2': process.system(sysctl_cmd + "=%s" % original_accept_ra)
def run(test, params, env): """ Test svirt in virt-install. (1). Init variables. (2). Set selinux on host. (3). Set label of image. (4). run a virt-install command. (5). clean up. As this test only care whether the qemu-kvm process can access the image. It is not necessary to install a full os in a vm. Just verify the vm is alive after virt-install command is enough. Then we can save a lot of time and make this test independent from unattended_install. """ # Get general variables. status_error = ('yes' == params.get("status_error", 'no')) host_sestatus = params.get("host_selinux", "enforcing") # Get variables about seclabel for VM. sec_type = params.get("svirt_install_vm_sec_type", "dynamic") sec_model = params.get("svirt_install_vm_sec_model", "selinux") sec_label = params.get("svirt_install_vm_sec_label", None) sec_relabel = params.get("svirt_install_vm_sec_relabel", "yes") # Set selinux status on host. backup_sestatus = utils_selinux.get_status() utils_selinux.set_status(host_sestatus) # Set the image label. disk_label = params.get("svirt_install_disk_label", None) vm_name = params.get("main_vm", None) # svirt will prevent accessing via a symble link. data_path = data_dir.get_data_dir() real_data_path = os.path.realpath(data_path) image_path = os.path.join(real_data_path, "svirt_image") if virsh.domain_exists(vm_name): virsh.remove_domain(vm_name) if not os.path.exists(image_path): utils_test.libvirt.create_local_disk("file", path=image_path) try: utils_selinux.set_context_of_file(image_path, disk_label) cmd = "virt-install --name %s --import --disk" % vm_name cmd += " path=%s --ram '1024' " % image_path cmd += " --security" if sec_type == 'static': if sec_label is None: raise ValueError("Seclabel is not setted for static.") cmd += " type=static,label=%s" % (sec_label) elif sec_type == 'dynamic': cmd += " type=dynamic" else: raise ValueError("Security type %s is not supported." % sec_type) if sec_relabel is not None: cmd += ",relabel=%s" % sec_relabel cmd += " --noautoconsole --graphics vnc --video vga &" utils.run(cmd, ignore_status=True) def _vm_alive(): return virsh.is_alive(vm_name) if (utils_misc.wait_for(_vm_alive, timeout=5)): if status_error: raise error.TestFail('Test succeeded in negative case.') else: if not status_error: raise error.TestFail("Test failed in positive case.") finally: # cleanup utils_selinux.set_status(backup_sestatus) if virsh.domain_exists(vm_name): virsh.remove_domain(vm_name) if not os.path.exists(image_path): utils_test.libvirt.delete_local_disk("file", path=image_path)
def run(test, params, env): """ Test interafce xml options. 1.Prepare test environment,destroy or suspend a VM. 2.Edit xml and start the domain. 3.Perform test operation. 4.Recover test environment. 5.Confirm the test result. """ vm_name = params.get("main_vm") vm = env.get_vm(vm_name) virsh_dargs = {'debug': True, 'ignore_status': False} def create_iface_xml(iface_mac): """ Create interface xml file """ iface = Interface(type_name=iface_type) source = ast.literal_eval(iface_source) if source: iface.source = source iface.model = iface_model if iface_model else "virtio" iface.mac_address = iface_mac driver_dict = {} driver_host = {} driver_guest = {} if iface_driver: driver_dict = ast.literal_eval(iface_driver) if iface_driver_host: driver_host = ast.literal_eval(iface_driver_host) if iface_driver_guest: driver_guest = ast.literal_eval(iface_driver_guest) iface.driver = iface.new_driver(driver_attr=driver_dict, driver_host=driver_host, driver_guest=driver_guest) logging.debug("Create new interface xml: %s", iface) return iface def modify_iface_xml(update, status_error=False): """ Modify interface xml options """ vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) xml_devices = vmxml.devices iface_index = xml_devices.index( xml_devices.by_device_tag("interface")[0]) iface = xml_devices[iface_index] if iface_model: iface.model = iface_model else: del iface.model if iface_type: iface.type_name = iface_type del iface.source source = ast.literal_eval(iface_source) if source: net_ifs = utils_net.get_net_if(state="UP") # Check source device is valid or not, # if it's not in host interface list, try to set # source device to first active interface of host if (iface.type_name == "direct" and source.has_key('dev') and source['dev'] not in net_ifs): logging.warn( "Source device %s is not a interface" " of host, reset to %s", source['dev'], net_ifs[0]) source['dev'] = net_ifs[0] iface.source = source backend = ast.literal_eval(iface_backend) if backend: iface.backend = backend driver_dict = {} driver_host = {} driver_guest = {} if iface_driver: driver_dict = ast.literal_eval(iface_driver) if iface_driver_host: driver_host = ast.literal_eval(iface_driver_host) if iface_driver_guest: driver_guest = ast.literal_eval(iface_driver_guest) iface.driver = iface.new_driver(driver_attr=driver_dict, driver_host=driver_host, driver_guest=driver_guest) if iface.address: del iface.address logging.debug("New interface xml file: %s", iface) if unprivileged_user: # Create disk image for unprivileged user disk_index = xml_devices.index( xml_devices.by_device_tag("disk")[0]) disk_xml = xml_devices[disk_index] logging.debug("source: %s", disk_xml.source) disk_source = disk_xml.source.attrs["file"] cmd = ("cp -fZ {0} {1} && chown {2}:{2} {1}" "".format(disk_source, dst_disk, unprivileged_user)) utils.run(cmd) disk_xml.source = disk_xml.new_disk_source( attrs={"file": dst_disk}) vmxml.devices = xml_devices # Remove all channels to avoid of permission problem channels = vmxml.get_devices(device_type="channel") for channel in channels: vmxml.del_device(channel) vmxml.xmltreefile.write() logging.debug("New VM xml: %s", vmxml) utils.run("chmod a+rw %s" % vmxml.xml) virsh.define(vmxml.xml, **virsh_dargs) # Try to modify interface xml by update-device or edit xml elif update: iface.xmltreefile.write() ret = virsh.update_device(vm_name, iface.xml, ignore_status=True) libvirt.check_exit_status(ret, status_error) else: vmxml.devices = xml_devices vmxml.xmltreefile.write() vmxml.sync() def check_offloads_option(if_name, driver_options, session=None): """ Check interface offloads by ethtool output """ offloads = { "csum": "tx-checksumming", "gso": "generic-segmentation-offload", "tso4": "tcp-segmentation-offload", "tso6": "tx-tcp6-segmentation", "ecn": "tx-tcp-ecn-segmentation", "ufo": "udp-fragmentation-offload" } if session: ret, output = session.cmd_status_output("ethtool -k %s | head" " -18" % if_name) else: out = utils.run("ethtool -k %s | head -18" % if_name) ret, output = out.exit_status, out.stdout if ret: raise error.TestFail("ethtool return error code") logging.debug("ethtool output: %s", output) for offload in driver_options.keys(): if offloads.has_key(offload): if (output.count(offloads[offload]) and not output.count( "%s: %s" % (offloads[offload], driver_options[offload]))): raise error.TestFail( "offloads option %s: %s isn't" " correct in ethtool output" % (offloads[offload], driver_options[offload])) def run_xml_test(iface_mac): """ Test for interface options in vm xml """ # Get the interface object according the mac address vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) iface_devices = vmxml.get_devices(device_type="interface") iface = None for iface_dev in iface_devices: if iface_dev.mac_address == iface_mac: iface = iface_dev if not iface: raise error.TestFail("Can't find interface with mac" " '%s' in vm xml" % iface_mac) driver_dict = {} if iface_driver: driver_dict = ast.literal_eval(iface_driver) for driver_opt in driver_dict.keys(): if not driver_dict[driver_opt] == iface.driver.driver_attr[ driver_opt]: raise error.TestFail( "Can't see driver option %s=%s in vm xml" % (driver_opt, driver_dict[driver_opt])) if iface_target: if (not iface.target.has_key("dev") or not iface.target["dev"].startswith(iface_target)): raise error.TestFail("Can't see device target dev in vm xml") # Check macvtap mode by ip link command if iface_target == "macvtap" and iface.source.has_key("mode"): cmd = "ip -d link show %s" % iface.target["dev"] output = utils.run(cmd).stdout logging.debug("ip link output: %s", output) mode = iface.source["mode"] if mode == "passthrough": mode = "passthru" if not output.count("macvtap mode %s" % mode): raise error.TestFail("Failed to verify macvtap mode") def run_cmdline_test(iface_mac): """ Test for qemu-kvm command line options """ cmd = ("ps -ef | grep %s | grep -v grep " % vm_name) ret = utils.run(cmd) logging.debug("Command line %s", ret.stdout) if test_vhost_net: if not ret.stdout.count("vhost=on") and not rm_vhost_driver: raise error.TestFail("Can't see vhost options in" " qemu-kvm command line") if iface_model == "virtio": model_option = "device virtio-net-pci" else: model_option = "device rtl8139" iface_cmdline = re.findall( r"%s,(.+),mac=%s" % (model_option, iface_mac), ret.stdout) if not iface_cmdline: raise error.TestFail("Can't see %s with mac %s in command" " line" % (model_option, iface_mac)) cmd_opt = {} for opt in iface_cmdline[0].split(','): tmp = opt.rsplit("=") cmd_opt[tmp[0]] = tmp[1] logging.debug("Command line options %s", cmd_opt) driver_dict = {} # Test <driver> xml options. if iface_driver: iface_driver_dict = ast.literal_eval(iface_driver) for driver_opt in iface_driver_dict.keys(): if driver_opt == "name": continue elif driver_opt == "txmode": if iface_driver_dict["txmode"] == "iothread": driver_dict["tx"] = "bh" else: driver_dict["tx"] = iface_driver_dict["txmode"] elif driver_opt == "queues": driver_dict["mq"] = "on" driver_dict["vectors"] = str( int(iface_driver_dict["queues"]) * 2 + 2) else: driver_dict[driver_opt] = iface_driver_dict[driver_opt] # Test <driver><host/><driver> xml options. if iface_driver_host: driver_dict.update(ast.literal_eval(iface_driver_host)) # Test <driver><guest/><driver> xml options. if iface_driver_guest: driver_dict.update(ast.literal_eval(iface_driver_guest)) for driver_opt in driver_dict.keys(): if (not cmd_opt.has_key(driver_opt) or not cmd_opt[driver_opt] == driver_dict[driver_opt]): raise error.TestFail("Can't see option '%s=%s' in qemu-kvm " " command line" % (driver_opt, driver_dict[driver_opt])) if test_backend: guest_pid = ret.stdout.rsplit()[1] cmd = "lsof %s | grep %s" % (backend["tap"], guest_pid) if utils.system(cmd, ignore_status=True): raise error.TestFail("Guest process didn't open backend file" " %s" % backend["tap"]) cmd = "lsof %s | grep %s" % (backend["vhost"], guest_pid) if utils.system(cmd, ignore_status=True): raise error.TestFail("Guest process didn't open backend file" " %s" % backend["tap"]) def get_guest_ip(session, mac): """ Wrapper function to get guest ip address """ utils_net.restart_guest_network(session, mac) # Wait for IP address is ready utils_misc.wait_for(lambda: utils_net.get_guest_ip_addr(session, mac), 10) return utils_net.get_guest_ip_addr(session, mac) def check_user_network(session): """ Check user network ip address on guest """ vm_ips = [] vm_ips.append(get_guest_ip(session, iface_mac_old)) if attach_device: vm_ips.append(get_guest_ip(session, iface_mac)) logging.debug("IP address on guest: %s", vm_ips) if len(vm_ips) != len(set(vm_ips)): raise error.TestFail("Duplicated IP address on guest. " "Check bug: https://bugzilla.redhat." "com/show_bug.cgi?id=1147238") for vm_ip in vm_ips: if vm_ip is None or not vm_ip.startswith("10.0.2."): raise error.TestFail("Found wrong IP address" " on guest") # Check gateway address gateway = utils_net.get_net_gateway(session.cmd_output) if gateway != "10.0.2.2": raise error.TestFail("The gateway on guest is not" " right") # Check dns server address ns_list = utils_net.get_net_nameserver(session.cmd_output) if "10.0.2.3" not in ns_list: raise error.TestFail("The dns server can't be found" " on guest") def check_mcast_network(session): """ Check multicast ip address on guests """ username = params.get("username") password = params.get("password") src_addr = ast.literal_eval(iface_source)['address'] add_session = additional_vm.wait_for_serial_login(username=username, password=password) vms_sess_dict = {vm_name: session, additional_vm.name: add_session} # Check mcast address on host cmd = "netstat -g | grep %s" % src_addr if utils.run(cmd, ignore_status=True).exit_status: raise error.TestFail("Can't find multicast ip address" " on host") vms_ip_dict = {} # Get ip address on each guest for vms in vms_sess_dict.keys(): vm_mac = vm_xml.VMXML.get_first_mac_by_name(vms) vm_ip = get_guest_ip(vms_sess_dict[vms], vm_mac) if not vm_ip: raise error.TestFail("Can't get multicast ip" " address on guest") vms_ip_dict.update({vms: vm_ip}) if len(set(vms_ip_dict.values())) != len(vms_sess_dict): raise error.TestFail("Got duplicated multicast ip address") logging.debug("Found ips on guest: %s", vms_ip_dict) # Run omping server on host if not utils_package.package_install(["omping"]): raise error.TestError("Failed to install omping" " on host") cmd = ("iptables -F;omping -m %s %s" % (src_addr, "192.168.122.1 %s" % ' '.join(vms_ip_dict.values()))) # Run a backgroup job waiting for connection of client bgjob = utils.AsyncJob(cmd) # Run omping client on guests for vms in vms_sess_dict.keys(): # omping should be installed first if not utils_package.package_install(["omping"], vms_sess_dict[vms]): raise error.TestError("Failed to install omping" " on guest") cmd = ("iptables -F; omping -c 5 -T 5 -m %s %s" % (src_addr, "192.168.122.1 %s" % vms_ip_dict[vms])) ret, output = vms_sess_dict[vms].cmd_status_output(cmd) logging.debug("omping ret: %s, output: %s", ret, output) if (not output.count('multicast, xmt/rcv/%loss = 5/5/0%') or not output.count('unicast, xmt/rcv/%loss = 5/5/0%')): raise error.TestFail("omping failed on guest") # Kill the backgroup job bgjob.kill_func() status_error = "yes" == params.get("status_error", "no") start_error = "yes" == params.get("start_error", "no") unprivileged_user = params.get("unprivileged_user") # Interface specific attributes. iface_type = params.get("iface_type", "network") iface_source = params.get("iface_source", "{}") iface_driver = params.get("iface_driver") iface_model = params.get("iface_model", "virtio") iface_target = params.get("iface_target") iface_backend = params.get("iface_backend", "{}") iface_driver_host = params.get("iface_driver_host") iface_driver_guest = params.get("iface_driver_guest") attach_device = params.get("attach_iface_device") change_option = "yes" == params.get("change_iface_options", "no") update_device = "yes" == params.get("update_iface_device", "no") additional_guest = "yes" == params.get("additional_guest", "no") serial_login = "******" == params.get("serial_login", "no") rm_vhost_driver = "yes" == params.get("rm_vhost_driver", "no") test_option_cmd = "yes" == params.get("test_iface_option_cmd", "no") test_option_xml = "yes" == params.get("test_iface_option_xml", "no") test_vhost_net = "yes" == params.get("test_vhost_net", "no") test_option_offloads = "yes" == params.get("test_option_offloads", "no") test_iface_user = "******" == params.get("test_iface_user", "no") test_iface_mcast = "yes" == params.get("test_iface_mcast", "no") test_libvirtd = "yes" == params.get("test_libvirtd", "no") test_guest_ip = "yes" == params.get("test_guest_ip", "no") test_backend = "yes" == params.get("test_backend", "no") if iface_driver_host or iface_driver_guest or test_backend: if not libvirt_version.version_compare(1, 2, 8): raise error.TestNAError("Offloading/backend options not " "supported in this libvirt version") if iface_driver and "queues" in ast.literal_eval(iface_driver): if not libvirt_version.version_compare(1, 0, 6): raise error.TestNAError("Queues options not supported" " in this libvirt version") if unprivileged_user: if not libvirt_version.version_compare(1, 1, 1): raise error.TestNAError("qemu-bridge-helper not supported" " on this host") virsh_dargs["unprivileged_user"] = unprivileged_user # Create unprivileged user if needed cmd = ("grep {0} /etc/passwd || " "useradd {0}".format(unprivileged_user)) utils.run(cmd) # Need another disk image for unprivileged user to access dst_disk = "/tmp/%s.img" % unprivileged_user # Destroy VM first if vm.is_alive(): vm.destroy(gracefully=False) # Back up xml file. vmxml_backup = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) iface_mac_old = vm_xml.VMXML.get_first_mac_by_name(vm_name) # iface_mac will update if attach a new interface iface_mac = iface_mac_old # Additional vm for test additional_vm = None libvirtd = utils_libvirtd.Libvirtd() try: # Build the xml and run test. try: # Prepare interface backend files if test_backend: if not os.path.exists("/dev/vhost-net"): utils.run("modprobe vhost-net") backend = ast.literal_eval(iface_backend) backend_tap = "/dev/net/tun" backend_vhost = "/dev/vhost-net" if not backend: backend["tap"] = backend_tap backend["vhost"] = backend_vhost if not start_error: # Create backend files for normal test if not os.path.exists(backend["tap"]): os.rename(backend_tap, backend["tap"]) if not os.path.exists(backend["vhost"]): os.rename(backend_vhost, backend["vhost"]) # Edit the interface xml. if change_option: modify_iface_xml(update=False) if rm_vhost_driver: # Check vhost driver. kvm_version = os.uname()[2] driver_path = ("/lib/modules/%s/kernel/drivers/vhost/" "vhost_net.ko" % kvm_version) driver_backup = driver_path + ".bak" cmd = ("modprobe -r {0}; lsmod | " "grep {0}".format("vhost_net")) if not utils.system(cmd, ignore_status=True): raise error.TestError("Failed to remove vhost_net driver") # Move the vhost_net driver if os.path.exists(driver_path): os.rename(driver_path, driver_backup) else: # Load vhost_net driver by default cmd = "modprobe vhost_net" utils.system(cmd) # Attach a interface when vm is shutoff if attach_device == 'config': iface_mac = utils_net.generate_mac_address_simple() iface_xml_obj = create_iface_xml(iface_mac) iface_xml_obj.xmltreefile.write() ret = virsh.attach_device(vm_name, iface_xml_obj.xml, flagstr="--config", ignore_status=True) libvirt.check_exit_status(ret) # Clone additional vm if additional_guest: guest_name = "%s_%s" % (vm_name, '1') # Clone additional guest timeout = params.get("clone_timeout", 360) utils_libguestfs.virt_clone_cmd(vm_name, guest_name, True, timeout=timeout) additional_vm = vm.clone(guest_name) additional_vm.start() # additional_vm.wait_for_login() # Start the VM. if unprivileged_user: virsh.start(vm_name, **virsh_dargs) cmd = ("su - %s -c 'virsh console %s'" % (unprivileged_user, vm_name)) session = aexpect.ShellSession(cmd) session.sendline() remote.handle_prompts(session, params.get("username"), params.get("password"), "[\#\$]", 30) # Get ip address on guest if not get_guest_ip(session, iface_mac): raise error.TestError("Can't get ip address on guest") else: # Will raise VMStartError exception if start fails vm.start() if serial_login: session = vm.wait_for_serial_login() else: session = vm.wait_for_login() if start_error: raise error.TestFail("VM started unexpectedly") # Attach a interface when vm is running if attach_device == 'live': iface_mac = utils_net.generate_mac_address_simple() iface_xml_obj = create_iface_xml(iface_mac) iface_xml_obj.xmltreefile.write() ret = virsh.attach_device(vm_name, iface_xml_obj.xml, flagstr="--live", ignore_status=True) libvirt.check_exit_status(ret) # Need sleep here for attachment take effect time.sleep(5) # Update a interface options if update_device: modify_iface_xml(update=True, status_error=status_error) # Run tests for qemu-kvm command line options if test_option_cmd: run_cmdline_test(iface_mac) # Run tests for vm xml if test_option_xml: run_xml_test(iface_mac) # Run tests for offloads options if test_option_offloads: if iface_driver_host: ifname_guest = utils_net.get_linux_ifname( session, iface_mac) check_offloads_option(ifname_guest, ast.literal_eval(iface_driver_host), session) if iface_driver_guest: ifname_host = libvirt.get_ifname_host(vm_name, iface_mac) check_offloads_option(ifname_host, ast.literal_eval(iface_driver_guest)) if test_iface_user: # Test user type network check_user_network(session) if test_iface_mcast: # Test mcast type network check_mcast_network(session) # Check guest ip address if test_guest_ip: if not get_guest_ip(session, iface_mac): raise error.TestFail("Guest can't get a" " valid ip address") session.close() # Restart libvirtd and guest, then test again if test_libvirtd: libvirtd.restart() vm.destroy() vm.start() if test_option_xml: run_xml_test(iface_mac) # Detach hot/cold-plugged interface at last if attach_device: ret = virsh.detach_device(vm_name, iface_xml_obj.xml, flagstr="", ignore_status=True) libvirt.check_exit_status(ret) except virt_vm.VMStartError as e: logging.info(str(e)) if not start_error: raise error.TestFail('VM failed to start\n%s' % e) finally: # Recover VM. logging.info("Restoring vm...") # Restore interface backend files if test_backend: if not os.path.exists(backend_tap): os.rename(backend["tap"], backend_tap) if not os.path.exists(backend_vhost): os.rename(backend["vhost"], backend_vhost) if rm_vhost_driver: # Restore vhost_net driver if os.path.exists(driver_backup): os.rename(driver_backup, driver_path) if unprivileged_user: virsh.remove_domain(vm_name, "--remove-all-storage", **virsh_dargs) if additional_vm: virsh.remove_domain(additional_vm.name, "--remove-all-storage") # Kill all omping server process on host utils.system("pidof omping && killall omping", ignore_status=True) if vm.is_alive(): vm.destroy(gracefully=False) vmxml_backup.sync()
def run(test, params, env): """ Test command: virsh rename. The command can rename a domain. 1.Prepare test environment. 2.Perform virsh rename operation. 3.Recover test environment. 4.Confirm the test result. """ # Get specific parameter value vm_name = params.get("main_vm") vm = env.get_vm(vm_name) domuuid = vm.get_uuid() vm_ref = params.get("domrename_vm_ref", "name") status_error = "yes" == params.get("status_error", "no") new_name = params.get("vm_new_name", "new") pre_vm_state = params.get("domrename_vm_state", "shutoff") domain_option = params.get("dom_opt", "") new_name_option = params.get("newname_opt", "") add_vm = "yes" == params.get("add_vm", "no") # Replace the varaiables if vm_ref == "name": vm_ref = vm_name elif vm_ref == "uuid": vm_ref = domuuid if new_name == "vm2_name": vm2_name = ("%s" % vm_name[:-1]) + "2" new_name = vm2_name # Build input params dom_param = ' '.join([domain_option, vm_ref]) new_name_param = ' '.join([new_name_option, new_name]) if vm.is_alive(): vm.destroy() # Backup for recovery. vmxml_backup = libvirt_xml.vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) logging.debug("vm xml is %s", vmxml_backup) # Clone additional vms if needed if add_vm: 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") ret_clone = utils_libguestfs.virt_clone_cmd(vm_name, vm2_name, True, timeout=360) if ret_clone.exit_status: test.fail("Error occured when clone a second vm!") vm2 = libvirt_vm.VM(vm2_name, vm.params, vm.root_dir, vm.address_cache) virsh.dom_list("--name --all", debug=True) # Create object instance for renamed domain new_vm = libvirt_vm.VM(new_name, vm.params, vm.root_dir, vm.address_cache) # Prepare vm state if pre_vm_state not in ["shutoff", "autostart"]: vm.start() if pre_vm_state == "paused": vm.pause() logging.debug("Domain state is now: %s", vm.state()) elif pre_vm_state == "managed_saved": vm.managedsave() elif pre_vm_state == "with_snapshot": virsh.snapshot_create_as(vm_name, "snap1 --disk-only", debug=True) vm.destroy(gracefully=False) try: if pre_vm_state == "autostart": virsh.autostart(dom_param, "", debug=True) virsh.dom_list("--all --autostart", debug=True) logging.debug("files under '/etc/libvirt/qemu/autostart/' are %s", os.listdir('/etc/libvirt/qemu/autostart/')) result = virsh.domrename(dom_param, new_name_param, ignore_status=True, debug=True) # Raise unexpected pass or fail libvirt.check_exit_status(result, status_error) # Return expected failure for negative tests if status_error: logging.debug("Expected failure: %s", result.stderr) return # Checkpoints after domrename succeed else: list_ret = virsh.dom_list("--name --all", debug=True).stdout.strip().splitlines() domname_ret = virsh.domname(domuuid, debug=True).stdout.strip() if new_name not in list_ret or vm_name in list_ret: test.fail("New name does not affect in virsh list") if domname_ret != new_name: test.fail( "New domain name does not affect in virsh domname uuid") if pre_vm_state != "autostart": # Try to start vm with the new name new_vm.start() else: utils_libvirtd.libvirtd_restart() list_autostart = virsh.dom_list("--autostart", debug=True).stdout logging.debug( "files under '/etc/libvirt/qemu/autostart/' are %s", os.listdir('/etc/libvirt/qemu/autostart/')) process.run("file /etc/libvirt/qemu/autostart/%s.xml" % vm_name, verbose=True) if new_name not in list_autostart: test.fail( "Domain isn't autostarted after restart libvirtd," "or becomes a never 'autostart' one.") finally: # Remove additional vms if add_vm and vm2.exists() and result.exit_status: virsh.remove_domain(vm2_name, "--remove-all-storage") # Undefine newly renamed domain if new_vm.exists(): if new_vm.is_alive(): new_vm.destroy(gracefully=False) new_vm.undefine() # Recover domain state if pre_vm_state != "shutoff": if pre_vm_state == "with_snapshot": libvirt.clean_up_snapshots(vm_name) else: if pre_vm_state == "managed_saved": vm.start() vm.destroy(gracefully=False) # Restore VM vmxml_backup.sync()
run_ip_test(session, "ipv6") if test_ipv4_address: check_ipt_rules(check_ipv4=True) run_ip_test(session, "ipv4") if test_guest_libvirt: run_guest_libvirt(session) session.close() except virt_vm.VMStartError, details: logging.info(str(details)) if start_error or restart_error: pass else: raise error.TestFail('VM Failed to start for some reason!') finally: # Recover VM. if vm.is_alive(): vm.destroy(gracefully=False) for vms in vms_list: virsh.remove_domain(vms.name, "--remove-all-storage") logging.info("Restoring network...") if net_name == "default": netxml_backup.sync() else: # Destroy and undefine new created network virsh.net_destroy(net_name) virsh.net_undefine(net_name) vmxml_backup.sync()
def run(test, params, env): """ Configuring /etc/sysconfig/libvirt-guests, then check the domains status after restarting the libvirt-guests.server, 1. Set the values in /etc/sysconfig/libvirt-guests 2. Restart libvirt-guests service 3. Check the domains states, and the guests' save files """ def get_log(): """ Tail output appended data as the file /var/log/messages grows :returns: the appended data tailed from /var/log/messages """ tailed_log_file = os.path.join(data_dir.get_tmp_dir(), 'tail_log') tailed_messages = aexpect.Tail(command='tail -f /var/log/messages', output_func=utils_misc.log_line, output_params=(tailed_log_file)) return tailed_messages def chk_on_shutdown(status_error, on_shutdown, parallel_shutdown, output): """ check domains' state when host shutdown, and if parallel_shutdown is set to non-zero, check whether the guests have been shutdown correctly. :param status_error: positive test if status_error is "no", otherwise negative test :param on_shutdown: action taking on host shutdown :param parallel_shutdown: the number of parallel_shutdown guests would be shutdown concurrently on shutdown :param output: appended message from /var/log/messages """ if on_shutdown == "shutdown" and on_boot == "start": second_boot_time = boot_time() logging.debug("The second boot time is %s", second_boot_time) if any([i >= j for i, j in zip(first_boot_time, second_boot_time)]): test.fail("The second boot time for should be larger" "than its first boot time.") expect_msg = expect_shutdown_msg(status_error, on_shutdown) logging.debug("The expected messages when host shutdown is: %s ", expect_msg) for dom in vms: if not re.search(expect_msg[dom.name], output): logging.debug("expect_mesg is: %s", expect_msg[dom.name]) if status_error == "no": test.fail("guest should be %s on shutdown" % on_shutdown) else: test.fail("Shutdown of guest should be failed to " "complete in time") if (on_shutdown == "shutdown") and int(parallel_shutdown) > 0: chk_parallel_shutdown(output, parallel_shutdown) def chk_on_boot(status_error, on_boot): """ check domains' state when host booted :param status_error: positive test if status_error is "no", otherwise negative test :param on_boot: action taking on host booting """ if status_error == "no": if on_boot == "start": for dom in vms: if not dom.is_alive(): test.fail("Since on_boot is setting to 'start', " "guest should be running after " "restarting libvirt-guests.") else: for dom in vms: if dom.is_alive(): test.fail("Since on_boot is setting to 'ignore', " "unless guests are autostart, " "guest should be shut off after " "restarting libvirt-guests, ") def check_on_shutdown_vm_status(): for dom in vms: result = virsh.domstate(dom.name, "--reason") try: dom.wait_for_shutdown() except Exception as e: test.fail('As on_boot is set to "ignore", but guest %s is ' 'not shutdown. reason: %s ' % (dom.name, e)) def chk_parallel_shutdown(output, parallel_shutdown): """ check whether the guests has been shut down concurrently on host shutdown. """ pattern = r".+ libvirt-guests.sh.*: Starting shutdown on guest: .+" shut_start_line_nums = [] for line_num, line in enumerate(output.splitlines()): if re.search(pattern, line): shut_start_line_nums.append(line_num) logging.debug("the line_numbers contains shutdown messages is: %s ", shut_start_line_nums) pattern = r".+ libvirt-guests.sh.*: Shutdown of guest.+complete" for line_num, line in enumerate(output.splitlines()): if re.search(pattern, line): shut_complete_first_line = line_num break logging.debug( "the first line contains shutdown complete messages is: %s ", shut_complete_first_line) para_shut = int(parallel_shutdown) if shut_start_line_nums[para_shut - 1] > shut_complete_first_line: test.fail("Since parallel_shutdown is setting to non_zero, " "%s guests should be shutdown concurrently." % parallel_shutdown) if shut_start_line_nums[para_shut] < shut_complete_first_line: test.fail("The number of guests shutdown concurrently " "should not be exceeded than %s." % parallel_shutdown) def expect_shutdown_msg(status_error, on_shutdown): """ the expected messages of each guests when host shutdown logged into /var/log/messages """ expect_msg = {} for dom in vms: if status_error == "no": if on_shutdown == "shutdown": expect_msg[dom.name] = ("libvirt-guests.sh.*: " "Shutdown of guest %s " "complete" % dom.name) else: expect_msg[dom.name] = ("libvirt-guests.sh.*: " "Suspending %s: done" % dom.name) else: # Now the negative tests are only about ON_SHUTDOWN=shutdown. if on_shutdown == "shutdown": expect_msg[dom.name] = ("libvirt-guests.sh.*: " "Shutdown of guest %s " "failed to complete in " "time" % dom.name) return expect_msg def chk_save_files(status_error, on_shutdown, on_boot): """ save files should exist when on_shutdown is set to shutdown, and on_boot is set to ignore. In other conditions, there should be no save files. """ save_files = dict() for dom in vms: save_files[dom] = ("/var/lib/libvirt/qemu/save/%s.save" % dom.name) if status_error == "no": if on_shutdown == "shutdown": for dom in vms: if os.path.exists(save_files[dom]): test.fail("There should be no save files since " "guests are shutdown on host shutdown.") else: if on_boot == "start": for dom in vms: if os.path.exists(save_files[dom]): test.fail("There should be no save files since " "guests are restored on host shutdown.") else: for dom in vms: if not os.path.exists(save_files[dom]): test.fail("Guests are suspended on host shutdown, " "and been ignored on host boot, there " "should be save files for the guests.") def boot_time(): booting_time = [] for vm in vms: session = vm.wait_for_login() time = session.cmd_output("uptime --since") booting_time.append(time) session.close() return booting_time def setup_nfs_backend_guest(vmxml_backup): # nfs_server setup nfs_server = libvirt.setup_or_cleanup_nfs(True) nfs_export_dir = nfs_server['export_dir'] logging.debug("nfs dir is %s", nfs_export_dir) # change the original xml and image path for dom in vms: vmxml = vm_xml.VMXML.new_from_dumpxml(dom.name) vmxml_backup.append(vmxml.copy()) disk_xml = vmxml.get_devices(device_type="disk")[0] orig_image_path_name = disk_xml.source.attrs['file'] libvirt.update_vm_disk_source(dom.name, nfs_export_dir) shutil.copy(orig_image_path_name, nfs_export_dir) # set the selinux bool if virt_use_nfs: result = process.run("setsebool virt_use_nfs 1", shell=True, verbose=True) if result.exit_status: logging.error("Failed to set virt_use_nfs on") def cleanup_nfs_backend_guest(vmxml_backup): if virt_use_nfs: result = process.run("setsebool virt_use_nfs 0", shell=True, verbose=True) if result.exit_status: logging.error("Failed to set virt_use_nfs off") # recover the guest xml for xml_backup in vmxml_backup: xml_backup.sync(options="--managed-save") nfs_server = libvirt.setup_or_cleanup_nfs(False) main_vm_name = params.get("main_vm") main_vm = env.get_vm(main_vm_name) on_boot = params.get("on_boot") on_shutdown = params.get("on_shutdown") nfs_vol = params.get("nfs_vol") == "yes" virt_use_nfs = params.get("virt_use_nfs") == "on" parallel_shutdown = params.get("parallel_shutdown") additional_vms = int(params.get("additional_vms", "0")) status_error = params.get("status_error") shutdown_timeout = params.get("shutdown_timeout", "300") config = utils_config.LibvirtGuestsConfig() libvirt_guests_service = service.Factory.create_service("libvirt-guests") if not libvirt_guests_service.status(): libvirt_guests_service.start() vms = [main_vm] if main_vm.is_alive: main_vm.destroy(gracefully=False) if not utils_misc.start_rsyslogd(): test.error("Rsyslogd service start fail") try: utils_path.find_command("virt-clone") except utils_path.CmdNotFoundError: test.cancel("No virt-clone command found.") # Clone additional vms: avocado-vt-vm2, avocado-vt-vm3..... for i in range(additional_vms): guest_name = ("%s" % main_vm_name[:-1]) + ("%s" % str(i + 2)) logging.debug("guest_name : %s", guest_name) utils_libguestfs.virt_clone_cmd(main_vm_name, guest_name, True, timeout=360, ignore_status=False) vms.append(main_vm.clone(guest_name)) logging.debug("Now the vms is: %s", [dom.name for dom in vms]) if nfs_vol: # info collected for clear env finally vmxml_backup = [] setup_nfs_backend_guest(vmxml_backup) for dom in vms: if not dom.is_alive(): dom.start() for dom in vms: dom.wait_for_login() first_boot_time = [] if on_shutdown == "shutdown" and on_boot == "start": first_boot_time = boot_time() logging.debug("The first boot time is %s", first_boot_time) try: # Config the libvirt-guests file config.ON_BOOT = on_boot config.ON_SHUTDOWN = on_shutdown config.PARALLEL_SHUTDOWN = parallel_shutdown config.SHUTDOWN_TIMEOUT = shutdown_timeout process.run("sed -i -e 's/ = /=/g' " "/etc/sysconfig/libvirt-guests", shell=True) tail_messages = get_log() # Even though libvirt-guests was designed to operate guests when # host shutdown. The purpose can also be fulfilled by restart the # libvirt-guests service. libvirt_guests_service.restart() time.sleep(10) output = tail_messages.get_output() logging.debug("Get messages in /var/log/messages: %s" % output) # check the guests state when host shutdown chk_on_shutdown(status_error, on_shutdown, parallel_shutdown, output) # check the guests state when host rebooted chk_on_boot(status_error, on_boot) # check the guests save files chk_save_files(status_error, on_shutdown, on_boot) if on_boot == "ignore" and on_shutdown == "shutdown": check_on_shutdown_vm_status() finally: config.restore() # Undefine additional vms for dom in vms[1:]: if dom.is_alive(): dom.destroy(gracefully=False) virsh.remove_domain(dom.name, "--remove-all-storage") if nfs_vol: cleanup_nfs_backend_guest(vmxml_backup) if libvirt_guests_service.status(): libvirt_guests_service.stop()
def run(test, params, env): """ Test qemu-monitor-command blockjobs by migrating with option --copy-storage-all or --copy-storage-inc. """ if not libvirt_version.version_compare(1, 0, 1): raise error.TestNAError("Blockjob functions - " "complete,pause,resume are" "not supported in current libvirt version.") vm = env.get_vm(params.get("main_vm")) cpu_size = int(params.get("cpu_size", "1")) memory_size = int(params.get("memory_size", "1048576")) primary_target = vm.get_first_disk_devices()["target"] file_path, file_size = vm.get_device_size(primary_target) # Convert to Gib file_size = int(file_size) / 1073741824 image_format = utils_test.get_image_info(file_path)["format"] remote_host = params.get("migrate_dest_host", "REMOTE.EXAMPLE") remote_user = params.get("remote_user", "root") remote_passwd = params.get("migrate_dest_pwd", "PASSWORD.EXAMPLE") if remote_host.count("EXAMPLE"): raise error.TestNAError("Config remote or local host first.") # Config ssh autologin for it ssh_key.setup_ssh_key(remote_host, remote_user, remote_passwd, port=22) # Define a new vm with modified cpu/memory new_vm_name = "%s_blockjob" % vm.name if vm.is_alive(): vm.destroy() utlv.define_new_vm(vm.name, new_vm_name) try: set_cpu_memory(new_vm_name, cpu_size, memory_size) vm = libvirt_vm.VM(new_vm_name, vm.params, vm.root_dir, vm.address_cache) except: # Make sure created vm is cleaned up virsh.remove_domain(new_vm_name) raise rdm_params = {"remote_ip": remote_host, "remote_user": remote_user, "remote_pwd": remote_passwd} rdm = utils_test.RemoteDiskManager(rdm_params) try: vm = libvirt_vm.VM(new_vm_name, vm.params, vm.root_dir, vm.address_cache) vm.start() rdm.create_image("file", file_path, file_size, None, None, img_frmt=image_format) logging.debug("Start migration...") copied_migration(vm, params, params.get("qmp_blockjob_type"), primary_target) finally: # Recover created vm if vm.is_alive(): vm.destroy() if vm.name == new_vm_name: vm.undefine() rdm.remove_path("file", file_path) rdm.runner.session.close()
def run(test, params, env): """ Convert a remote vm to local libvirt(KVM). """ for v in list(params.values()): if "V2V_EXAMPLE" in v: raise exceptions.TestSkipError("Please set real value for %s" % v) vm_name = params.get("main_vm") 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_pwd_file = params.get("vpx_passwd_file") vpx_dc = params.get("vpx_dc") esx_ip = params.get("esx_hostname") hypervisor = params.get("hypervisor") input_mode = params.get("input_mode") target = params.get("target") v2v_opts = params.get("v2v_opts") # 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') # 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_pwd_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") raise exceptions.TestError("Fail to setup ssh-agent") else: raise exceptions.TestSkipError("Unspported hypervisor: %s" % hypervisor) # Create libvirt URI for the source node v2v_uri = utils_v2v.Uri(hypervisor) remote_uri = v2v_uri.get_uri(source_ip, vpx_dc, esx_ip) logging.debug("Remote host uri for converting: %s", remote_uri) # Make sure the VM exist before convert virsh_dargs = {'uri': remote_uri, 'remote_ip': source_ip, 'remote_user': source_user, 'remote_pwd': source_pwd, 'debug': True} remote_virsh = virsh.VirshPersistent(**virsh_dargs) try: if not remote_virsh.domain_exists(vm_name): raise exceptions.TestError("VM '%s' not exist" % vm_name) finally: remote_virsh.close_session() # Prepare libvirt storage pool pool_type = params.get("pool_type") pool_name = params.get("pool_name") pool_target = params.get("pool_target") libvirt_pool = utlv.PoolVolumeTest(test, params) libvirt_pool.pre_pool(pool_name, pool_type, pool_target, '') # Preapre libvirt virtual network network = params.get("network") net_kwargs = {'net_name': network, 'address': params.get('network_addr'), 'dhcp_start': params.get('network_dhcp_start'), 'dhcp_end': params.get('network_dhcp_end')} libvirt_net = utlv.LibvirtNetwork('vnet', **net_kwargs) net_info = virsh.net_info(network).stdout.strip() bridge = re.search(r'Bridge:\s+(\S+)', net_info).group(1) params['netdst'] = bridge # 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': pool_name, 'hostname': source_ip, 'input_transport': input_transport, 'vcenter_host': vpx_ip, 'vcenter_password': vpx_pwd, 'vddk_thumbprint': vddk_thumbprint, 'vddk_libdir': vddk_libdir, 'vddk_libdir_src': vddk_libdir_src, } 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}) # Set libguestfs environment if hypervisor == 'xen': os.environ['LIBGUESTFS_BACKEND'] = 'direct' try: # Execute virt-v2v command ret = utils_v2v.v2v_cmd(v2v_params) logging.debug("virt-v2v verbose messages:\n%s", ret) if ret.exit_status != 0: raise exceptions.TestFail("Convert VM failed") logging.debug("XML info:\n%s", virsh.dumpxml(vm_name)) vm = env.create_vm("libvirt", "libvirt", vm_name, params, test.bindir) # Win10 is not supported by some cpu model, # need to modify to 'host-model' unsupport_list = ['win10', 'win2016', 'win2019'] if params.get('os_version') in unsupport_list: logging.info('Set cpu mode to "host-model" for %s.', unsupport_list) vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) cpu_xml = vm_xml.VMCPUXML() cpu_xml.mode = 'host-model' cpu_xml.fallback = 'allow' vmxml['cpu'] = cpu_xml vmxml.sync() vm.start() # Check all checkpoints after convert vmchecker = VMChecker(test, params, env) ret = vmchecker.run() if len(ret) == 0: logging.info("All checkpoints passed") else: raise exceptions.TestFail("%d checkpoints failed: %s" % (len(ret), ret)) finally: vmcheck = utils_v2v.VMCheck(test, params, env) vmcheck.cleanup() utils_v2v.cleanup_constant_files(params) if hypervisor == "xen": process.run("ssh-agent -k") # Clean libvirt VM virsh.remove_domain(vm_name) # Clean libvirt pool if libvirt_pool: libvirt_pool.cleanup_pool(pool_name, pool_type, pool_target, '') # Clean libvirt network if libvirt_net: libvirt_net.cleanup()