def get_disk_info(vm_name, options): """ Return disk info dict. :param vm_name: vm name :param options: domblkinfo command options :return: dict of disk info """ disk_info_dict = {} if "--inactive" in options: option = "--inactive" else: option = "" sourcelist = vm_xml.VMXML.get_disk_source(vm_name, option) new_disk = disk.Disk() for i in range(len(sourcelist)): new_disk['xml'] = ElementTree.tostring(sourcelist[i]) logging.debug("Current disk xml is: %s" % new_disk.xmltreefile) if hasattr(new_disk, 'source'): for key in list(new_disk.source.attrs.keys()): if key in SOURCE_LIST: source_path = new_disk.source.attrs[key] else: source_path = '-' disk_info_dict[i] = [ new_disk.type_name, new_disk.device, new_disk.target['dev'], source_path ] return disk_info_dict
def prepare_disk_obj(disk_type, disk_device, driver_name, driver_type, path_to_blk, device_target, target_bus): """ Prepare and return disk xml object """ disk_params = {'type_name': disk_type, 'device': disk_device, 'driver_name': driver_name, 'driver_type': driver_type, 'source_file': path_to_blk, 'target_dev': device_target, 'target_bus': target_bus } vd_xml = utlv.create_disk_xml(disk_params) vd_xml_str = open(vd_xml).read() disk_obj = disk.Disk() disk_obj.xml = vd_xml_str return disk_obj
def create_disk_xml(params): """ Create a disk configuration file. """ # Create attributes dict for disk's address element type_name = params.get("type_name", "file") source_file = params.get("source_file") target_dev = params.get("target_dev", "vdb") target_bus = params.get("target_bus", "virtio") diskxml = disk.Disk(type_name) diskxml.device = params.get("device_type", "disk") if type_name == "file": source_type = "file" else: source_type = "dev" diskxml.source = diskxml.new_disk_source(attrs={source_type: source_file}) diskxml.target = {'dev': target_dev, 'bus': target_bus} logging.debug("Disk XML:\n%s", str(diskxml)) return diskxml.xml
def create_disk_xml(params): """ Create a disk configuration file. :param params: a dict contains values of disk {'device_type': "file", 'source_file': ..., 'target_dev': ..., 'target_bus': "virtio", 'addr_type': ..., 'addr_domain': ..., 'addr_bus':..., 'addr_slot': ..., 'addr_function': ..., 'addr_multifunction': ...} """ # Create attributes dict for disk's address element addr_attr = {} addr_type = params.get("addr_type", "pci") addr_attr['domain'] = params.get("addr_domain", "0x0000") addr_attr['bus'] = params.get("addr_bus", "0x00") addr_attr['slot'] = params.get("addr_slot", "0x0a") addr_attr['function'] = params.get("addr_function", "0x0") if params.get("addr_multifunction") is not None: addr_attr['multifunction'] = params.get("addr_multifunction") type_name = params.get("type_name", "file") source_file = params.get("source_file") target_dev = params.get("target_dev", "vdb") target_bus = params.get("target_bus", "virtio") diskxml = disk.Disk(type_name) diskxml.device = params.get("device_type", "disk") diskxml.source = diskxml.new_disk_source(attrs={'file': source_file}) diskxml.target = {'dev': target_dev, 'bus': target_bus} diskxml.address = diskxml.new_disk_address(addr_type, attrs=addr_attr) logging.debug("Disk XML:\n%s", str(diskxml)) return diskxml.xml
def run(test, params, env): """ Test snapshot-create-as command Make sure that the clean repo can be used because qemu-guest-agent need to be installed in guest The command create a snapshot (disk and RAM) from arguments which including the following point * virsh snapshot-create-as --print-xml --diskspec --name --description * virsh snapshot-create-as --print-xml with multi --diskspec * virsh snapshot-create-as --print-xml --memspec * virsh snapshot-create-as --description * virsh snapshot-create-as --no-metadata * virsh snapshot-create-as --no-metadata --print-xml (negative test) * virsh snapshot-create-as --atomic --disk-only * virsh snapshot-create-as --quiesce --disk-only (positive and negative) * virsh snapshot-create-as --reuse-external * virsh snapshot-create-as --disk-only --diskspec * virsh snapshot-create-as --memspec --reuse-external --atomic(negative) * virsh snapshot-create-as --disk-only and --memspec (negative) * Create multi snapshots with snapshot-create-as * Create snapshot with name a--a a--a--snap1 """ if not virsh.has_help_command('snapshot-create-as'): test.cancel("This version of libvirt does not support " "the snapshot-create-as test") vm_name = params.get("main_vm") status_error = params.get("status_error", "no") options = params.get("snap_createas_opts") multi_num = params.get("multi_num", "1") diskspec_num = params.get("diskspec_num", "1") bad_disk = params.get("bad_disk") reuse_external = "yes" == params.get("reuse_external", "no") start_ga = params.get("start_ga", "yes") domain_state = params.get("domain_state") memspec_opts = params.get("memspec_opts") config_format = "yes" == params.get("config_format", "no") snapshot_image_format = params.get("snapshot_image_format") diskspec_opts = params.get("diskspec_opts") create_autodestroy = 'yes' == params.get("create_autodestroy", "no") unix_channel = "yes" == params.get("unix_channel", "yes") dac_denial = "yes" == params.get("dac_denial", "no") check_json_no_savevm = "yes" == params.get("check_json_no_savevm", "no") disk_snapshot_attr = params.get('disk_snapshot_attr', 'external') set_snapshot_attr = "yes" == params.get("set_snapshot_attr", "no") # gluster related params replace_vm_disk = "yes" == params.get("replace_vm_disk", "no") disk_src_protocol = params.get("disk_source_protocol") restart_tgtd = params.get("restart_tgtd", "no") vol_name = params.get("vol_name") tmp_dir = data_dir.get_tmp_dir() pool_name = params.get("pool_name", "gluster-pool") brick_path = os.path.join(tmp_dir, pool_name) uri = params.get("virsh_uri") usr = params.get('unprivileged_user') if usr: if usr.count('EXAMPLE'): usr = '******' if disk_src_protocol == 'iscsi': if not libvirt_version.version_compare(1, 0, 4): test.cancel("'iscsi' disk doesn't support in" " current libvirt version.") if not libvirt_version.version_compare(1, 1, 1): if params.get('setup_libvirt_polkit') == 'yes': test.cancel("API acl test not supported in current" " libvirt version.") if not libvirt_version.version_compare(1, 2, 7): # As bug 1017289 closed as WONTFIX, the support only # exist on 1.2.7 and higher if disk_src_protocol == 'gluster': test.cancel("Snapshot on glusterfs not support in " "current version. Check more info with " "https://bugzilla.redhat.com/buglist.cgi?" "bug_id=1017289,1032370") if libvirt_version.version_compare(5, 5, 0): # libvirt-5.5.0-2 commit 68e1a05f starts to allow --no-metadata and # --print-xml to be used together. if "--no-metadata" in options and "--print-xml" in options: logging.info("--no-metadata and --print-xml can be used together " "in this libvirt version. Not expecting a failure.") status_error = "no" opt_names = locals() if memspec_opts is not None: mem_options = compose_disk_options(test, params, memspec_opts) # if the parameters have the disk without "file=" then we only need to # add testdir for it. if mem_options is None: mem_options = os.path.join(data_dir.get_tmp_dir(), memspec_opts) options += " --memspec " + mem_options tag_diskspec = 0 dnum = int(diskspec_num) if diskspec_opts is not None: tag_diskspec = 1 opt_names['diskopts_1'] = diskspec_opts # diskspec_opts[n] is used in cfg when more than 1 --diskspec is used if dnum > 1: tag_diskspec = 1 for i in range(1, dnum + 1): opt_names["diskopts_%s" % i] = params.get("diskspec_opts%s" % i) if tag_diskspec == 1: for i in range(1, dnum + 1): disk_options = compose_disk_options(test, params, opt_names["diskopts_%s" % i]) options += " --diskspec " + disk_options logging.debug("options are %s", options) vm = env.get_vm(vm_name) option_dict = {} option_dict = utils_misc.valued_option_dict(options, r' --(?!-)') logging.debug("option_dict is %s", option_dict) # A backup of original vm vmxml_backup = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) logging.debug("original xml is %s", vmxml_backup) # Generate empty image for negative test if bad_disk is not None: bad_disk = os.path.join(data_dir.get_tmp_dir(), bad_disk) with open(bad_disk, 'w') as bad_file: pass # Generate external disk if reuse_external: disk_path = '' for i in range(dnum): external_disk = "external_disk%s" % i if params.get(external_disk): disk_path = os.path.join(data_dir.get_tmp_dir(), params.get(external_disk)) process.run("qemu-img create -f qcow2 %s 1G" % disk_path, shell=True) # Only chmod of the last external disk for negative case if dac_denial: process.run("chmod 500 %s" % disk_path, shell=True) qemu_conf = None libvirtd_conf = None libvirtd_log_path = None libvirtd = utils_libvirtd.Libvirtd() try: # Config "snapshot_image_format" option in qemu.conf if config_format: qemu_conf = utils_config.LibvirtQemuConfig() qemu_conf.snapshot_image_format = snapshot_image_format logging.debug("the qemu config file content is:\n %s" % qemu_conf) libvirtd.restart() if check_json_no_savevm: libvirtd_conf = utils_config.LibvirtdConfig() libvirtd_conf["log_level"] = '1' libvirtd_conf["log_filters"] = '"1:json 3:remote 4:event"' libvirtd_log_path = os.path.join(data_dir.get_tmp_dir(), "libvirtd.log") libvirtd_conf["log_outputs"] = '"1:file:%s"' % libvirtd_log_path logging.debug("the libvirtd config file content is:\n %s" % libvirtd_conf) libvirtd.restart() if replace_vm_disk: libvirt.set_vm_disk(vm, params, tmp_dir) if set_snapshot_attr: if vm.is_alive(): vm.destroy(gracefully=False) vmxml_new = vm_xml.VMXML.new_from_dumpxml(vm_name) disk_xml = vmxml_backup.get_devices(device_type="disk")[0] vmxml_new.del_device(disk_xml) # set snapshot attribute in disk xml disk_xml.snapshot = disk_snapshot_attr new_disk = disk.Disk(type_name='file') new_disk.xmltreefile = disk_xml.xmltreefile vmxml_new.add_device(new_disk) logging.debug("The vm xml now is: %s" % vmxml_new.xmltreefile) vmxml_new.sync() vm.start() # Start qemu-ga on guest if have --quiesce if unix_channel and options.find("quiesce") >= 0: vm.prepare_guest_agent() session = vm.wait_for_login() if start_ga == "no": # The qemu-ga could be running and should be killed session.cmd("kill -9 `pidof qemu-ga`") # Check if the qemu-ga get killed stat_ps = session.cmd_status("ps aux |grep [q]emu-ga") if not stat_ps: # As managed by systemd and set as autostart, qemu-ga # could be restarted, so use systemctl to stop it. session.cmd("systemctl stop qemu-guest-agent") stat_ps = session.cmd_status("ps aux |grep [q]emu-ga") if not stat_ps: test.cancel("Fail to stop agent in " "guest") if domain_state == "paused": virsh.suspend(vm_name) else: # Remove channel if exist if vm.is_alive(): vm.destroy(gracefully=False) xml_inst = vm_xml.VMXML.new_from_dumpxml(vm_name) xml_inst.remove_agent_channels() vm.start() # Record the previous snapshot-list snaps_before = virsh.snapshot_list(vm_name) # Attach disk before create snapshot if not print xml and multi disks # specified in cfg if dnum > 1 and "--print-xml" not in options: for i in range(1, dnum): disk_path = os.path.join(data_dir.get_tmp_dir(), 'disk%s.qcow2' % i) process.run("qemu-img create -f qcow2 %s 200M" % disk_path, shell=True) virsh.attach_disk(vm_name, disk_path, 'vd%s' % list(string.ascii_lowercase)[i], debug=True) # Run virsh command # May create several snapshots, according to configuration for count in range(int(multi_num)): if create_autodestroy: # Run virsh command in interactive mode vmxml_backup.undefine() vp = virsh.VirshPersistent() vp.create(vmxml_backup['xml'], '--autodestroy') cmd_result = vp.snapshot_create_as(vm_name, options, ignore_status=True, debug=True) vp.close_session() vmxml_backup.define() else: cmd_result = virsh.snapshot_create_as(vm_name, options, unprivileged_user=usr, uri=uri, ignore_status=True, debug=True) # for multi snapshots without specific snapshot name, the # snapshot name is using time string with 1 second # incremental, to avoid get snapshot failure with same name, # sleep 1 second here. if int(multi_num) > 1: time.sleep(1.1) output = cmd_result.stdout.strip() status = cmd_result.exit_status # check status_error if status_error == "yes": if status == 0: test.fail("Run successfully with wrong command!") else: # Check memspec file should be removed if failed if (options.find("memspec") >= 0 and options.find("atomic") >= 0): if os.path.isfile(option_dict['memspec']): os.remove(option_dict['memspec']) test.fail("Run failed but file %s exist" % option_dict['memspec']) else: logging.info("Run failed as expected and memspec" " file already been removed") # Check domain xml is not updated if reuse external fail elif reuse_external and dac_denial: output = virsh.dumpxml(vm_name).stdout.strip() if "reuse_external" in output: test.fail("Domain xml should not be " "updated with snapshot image") else: logging.info("Run failed as expected") elif status_error == "no": if status != 0: test.fail("Run failed with right command: %s" % output) else: # Check the special options snaps_list = virsh.snapshot_list(vm_name) logging.debug("snaps_list is %s", snaps_list) check_snapslist(test, vm_name, options, option_dict, output, snaps_before, snaps_list) # For cover bug 872292 if check_json_no_savevm: pattern = "The command savevm has not been found" with open(libvirtd_log_path) as f: for line in f: if pattern in line and "error" in line: test.fail("'%s' was found: %s" % (pattern, line)) finally: if vm.is_alive(): vm.destroy() # recover domain xml xml_recover(vmxml_backup) path = "/var/lib/libvirt/qemu/snapshot/" + vm_name if os.path.isfile(path): test.fail("Still can find snapshot metadata") if disk_src_protocol == 'gluster': gluster.setup_or_cleanup_gluster(False, brick_path=brick_path, **params) libvirtd.restart() if disk_src_protocol == 'iscsi': libvirt.setup_or_cleanup_iscsi(False, restart_tgtd=restart_tgtd) # rm bad disks if bad_disk is not None: os.remove(bad_disk) # rm attach disks and reuse external disks if dnum > 1 and "--print-xml" not in options: for i in range(dnum): disk_path = os.path.join(data_dir.get_tmp_dir(), 'disk%s.qcow2' % i) if os.path.exists(disk_path): os.unlink(disk_path) if reuse_external: external_disk = "external_disk%s" % i disk_path = os.path.join(data_dir.get_tmp_dir(), params.get(external_disk)) if os.path.exists(disk_path): os.unlink(disk_path) # restore config if config_format and qemu_conf: qemu_conf.restore() if libvirtd_conf: libvirtd_conf.restore() if libvirtd_conf or (config_format and qemu_conf): libvirtd.restart() if libvirtd_log_path and os.path.exists(libvirtd_log_path): os.unlink(libvirtd_log_path)
def run(test, params, env): """ 1. prepare a fc lun with one of following methods - create a scsi pool&vol - create a vhba 2. prepare the virtual disk xml, as one of following - source = /dev/disk/by-path - source = /dev/mapper/mpathX - source = pool&vol format 3. start a vm with above disk as vdb 4. create disk-only snapshot of vdb 5. check the snapshot-list and snapshot file's existence 6. mount vdb and touch file to it 7. revert the snapshot and check file's existence 8. delete snapshot 9. cleanup env. """ vm_name = params.get("main_vm", "avocado-vt-vm1") wwpn = params.get("wwpn", "WWPN_EXAMPLE") wwnn = params.get("wwnn", "WWNN_EXAMPLE") disk_device = params.get("disk_device", "disk") disk_type = params.get("disk_type", "file") disk_size = params.get("disk_size", "100M") device_target = params.get("device_target", "vdb") driver_name = params.get("driver_name", "qemu") driver_type = params.get("driver_type", "raw") target_bus = params.get("target_bus", "virtio") vd_format = params.get("vd_format", "") snapshot_dir = params.get("snapshot_dir", "/tmp") snapshot_name = params.get("snapshot_name", "s1") pool_name = params.get("pool_name", "") pool_target = params.get("pool_target", "/dev") snapshot_disk_only = "yes" == params.get("snapshot_disk_only", "no") new_vhbas = [] current_vhbas = [] new_vhba = [] path_to_blk = "" lun_sl = [] new_disk = "" pool_ins = None old_mpath_conf = "" mpath_conf_path = "/etc/multipath.conf" original_mpath_conf_exist = os.path.exists(mpath_conf_path) vm = env.get_vm(vm_name) online_hbas = utils_npiv.find_hbas("hba") if not online_hbas: raise exceptions.TestSkipError("There is no online hba cards.") old_mpath_conf = utils_npiv.prepare_multipath_conf( conf_path=mpath_conf_path, replace_existing=True) first_online_hba = online_hbas[0] old_vhbas = utils_npiv.find_hbas("vhba") if vm.is_dead(): vm.start() session = vm.wait_for_login() virt_vm = libvirt_vm.VM(vm_name, vm.params, vm.root_dir, vm.address_cache) old_disks = virt_vm.get_disks() if vm.is_alive(): vm.destroy(gracefully=False) if pool_name: pool_ins = libvirt_storage.StoragePool() vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) vmxml_backup = vmxml.copy() try: # prepare a fc lun if vd_format in ['scsi_vol']: if pool_ins.pool_exists(pool_name): raise exceptions.TestFail("Pool %s already exist" % pool_name) prepare_scsi_pool(pool_name, wwnn, wwpn, first_online_hba, pool_target) utils_misc.wait_for(lambda: utils_npiv.is_vhbas_added(old_vhbas), timeout=_TIMEOUT) if not utils_npiv.is_vhbas_added(old_vhbas): raise exceptions.TestFail("vHBA not successfully created") current_vhbas = utils_npiv.find_hbas("vhba") new_vhba = list(set(current_vhbas).difference(set(old_vhbas)))[0] new_vhbas.append(new_vhba) new_vhba_scsibus = re.sub("\D", "", new_vhba) utils_misc.wait_for(lambda: get_blks_by_scsi(new_vhba_scsibus), timeout=_TIMEOUT) new_blks = get_blks_by_scsi(new_vhba_scsibus) if not new_blks: raise exceptions.TestFail( "block device not found with scsi_%s", new_vhba_scsibus) vol_list = utlv.get_vol_list(pool_name, vol_check=True, timeout=_TIMEOUT * 3) path_to_blk = list(vol_list.values())[0] elif vd_format in ['mpath', 'by_path']: old_mpath_devs = utils_npiv.find_mpath_devs() new_vhba = utils_npiv.nodedev_create_from_xml({ "nodedev_parent": first_online_hba, "scsi_wwnn": wwnn, "scsi_wwpn": wwpn }) utils_misc.wait_for(lambda: utils_npiv.is_vhbas_added(old_vhbas), timeout=_TIMEOUT * 2) if not new_vhba: raise exceptions.TestFail("vHBA not successfully generated.") new_vhbas.append(new_vhba) if vd_format == "mpath": utils_misc.wait_for( lambda: utils_npiv.is_mpath_devs_added(old_mpath_devs), timeout=_TIMEOUT * 5) if not utils_npiv.is_mpath_devs_added(old_mpath_devs): raise exceptions.TestFail("mpath dev not generated.") cur_mpath_devs = utils_npiv.find_mpath_devs() new_mpath_devs = list( set(cur_mpath_devs).difference(set(old_mpath_devs))) logging.debug("The newly added mpath dev is: %s", new_mpath_devs) path_to_blk = "/dev/mapper/" + new_mpath_devs[0] elif vd_format == "by_path": new_vhba_scsibus = re.sub("\D", "", new_vhba) utils_misc.wait_for(lambda: get_blks_by_scsi(new_vhba_scsibus), timeout=_TIMEOUT) new_blks = get_blks_by_scsi(new_vhba_scsibus) if not new_blks: raise exceptions.TestFail("blk dev not found with scsi_%s", new_vhba_scsibus) first_blk_dev = new_blks[0] utils_misc.wait_for(lambda: get_symbols_by_blk(first_blk_dev), timeout=_TIMEOUT) lun_sl = get_symbols_by_blk(first_blk_dev) if not lun_sl: raise exceptions.TestFail( "lun symbolic links not found in " "/dev/disk/by-path/ for %s" % first_blk_dev) lun_dev = lun_sl[0] path_to_blk = os.path.join(_BY_PATH_DIR, lun_dev) else: pass else: raise exceptions.TestSkipError("Not provided how to pass" "virtual disk to VM.") # create qcow2 file on the block device with specified size if path_to_blk: cmd = "qemu-img create -f qcow2 %s %s" % (path_to_blk, disk_size) try: process.run(cmd, shell=True) except process.cmdError as detail: raise exceptions.TestFail( "Fail to create qcow2 on blk dev: %s", detail) else: raise exceptions.TestFail("Don't have a valid path to blk dev.") # prepare disk xml if "vol" in vd_format: vol_list = utlv.get_vol_list(pool_name, vol_check=True, timeout=_TIMEOUT * 3) test_vol = list(vol_list.keys())[0] disk_params = { 'type_name': disk_type, 'target_dev': device_target, 'target_bus': target_bus, 'source_pool': pool_name, 'source_volume': test_vol, 'driver_type': driver_type } else: disk_params = { 'type_name': disk_type, 'device': disk_device, 'driver_name': driver_name, 'driver_type': driver_type, 'source_file': path_to_blk, 'target_dev': device_target, 'target_bus': target_bus } if vm.is_alive(): vm.destroy(gracefully=False) new_disk = disk.Disk() new_disk.xml = open(utlv.create_disk_xml(disk_params)).read() # start vm with the virtual disk vmxml.devices = vmxml.devices.append(new_disk) vmxml.sync() vm.start() session = vm.wait_for_login() cur_disks = virt_vm.get_disks() mount_disk = "".join(list(set(old_disks) ^ set(cur_disks))) # mkfs and mount disk in vm, create a file on that disk. if not mount_disk: logging.debug("old_disk: %s, new_disk: %s", old_disks, cur_disks) raise exceptions.TestFail("No new disk found in vm.") mkfs_and_mount(session, mount_disk) create_file_in_vm(session, "/mnt/before_snapshot.txt", "before") # virsh snapshot-create-as vm s --disk-only --diskspec vda,file=path if snapshot_disk_only: vm_blks = list(vm.get_disk_devices().keys()) options = "%s --disk-only" % snapshot_name for vm_blk in vm_blks: snapshot_file = snapshot_dir + "/" + vm_blk + "." + snapshot_name if os.path.exists(snapshot_file): os.remove(snapshot_file) options = options + " --diskspec %s,file=%s" % (vm_blk, snapshot_file) else: options = snapshot_name utlv.check_exit_status(virsh.snapshot_create_as(vm_name, options)) # check virsh snapshot-list logging.debug("Running: snapshot-list %s", vm_name) snapshot_list = virsh.snapshot_list(vm_name) logging.debug("snapshot list is: %s", snapshot_list) if not snapshot_list: raise exceptions.TestFail("snapshots not found after creation.") # snapshot-revert doesn't support external snapshot for now. so # only check this with internal snapshot. if not snapshot_disk_only: create_file_in_vm(session, "/mnt/after_snapshot.txt", "after") logging.debug("Running: snapshot-revert %s %s", vm_name, snapshot_name) utlv.check_exit_status( virsh.snapshot_revert(vm_name, snapshot_name)) session = vm.wait_for_login() file_existence, file_content = get_file_in_vm( session, "/mnt/after_snapshot.txt") logging.debug("file exist = %s, file content = %s", file_existence, file_content) if file_existence: raise exceptions.TestFail("The file created " "after snapshot still exists.") file_existence, file_content = get_file_in_vm( session, "/mnt/before_snapshot.txt") logging.debug("file eixst = %s, file content = %s", file_existence, file_content) if ((not file_existence) or (file_content.strip() != "before")): raise exceptions.TestFail("The file created " "before snapshot is lost.") # delete snapshots # if diskonly, delete --metadata and remove files # if not diskonly, delete snapshot if snapshot_disk_only: options = "--metadata" else: options = "" for snap in snapshot_list: logging.debug("deleting snapshot %s with options %s", snap, options) result = virsh.snapshot_delete(vm_name, snap, options) logging.debug("result of snapshot-delete: %s", result.stdout.strip()) if snapshot_disk_only: vm_blks = list(vm.get_disk_devices().keys()) for vm_blk in vm_blks: snapshot_file = snapshot_dir + "/" + vm_blk + "." + snap if os.path.exists(snapshot_file): os.remove(snapshot_file) snapshot_list = virsh.snapshot_list(vm_name) if snapshot_list: raise exceptions.TestFail("Snapshot not deleted: %s", snapshot_list) except Exception as detail: raise exceptions.TestFail("exception happens: %s", detail) finally: logging.debug("Start to clean up env...") vmxml_backup.sync() if pool_ins and pool_ins.pool_exists(pool_name): virsh.pool_destroy(pool_name) for new_vhba in new_vhbas: virsh.nodedev_destroy(new_vhba) utils_npiv.restart_multipathd() if old_mpath_conf: utils_npiv.prepare_multipath_conf(conf_path=mpath_conf_path, conf_content=old_mpath_conf, replace_existing=True) if not original_mpath_conf_exist and os.path.exists(mpath_conf_path): os.remove(mpath_conf_path)
def run(test, params, env): """ Test command: virsh pool-define; pool-define-as; pool-start; vol-list pool; attach-device LUN to guest; mount the device; dd to the mounted device; unmount; pool-destroy; pool-undefine; Pre-requiste: Host needs to have a wwpn and wwnn of a vHBA which is zoned and mapped to SAN controller. """ pool_xml_f = params.get("pool_create_xml_file", "/PATH/TO/POOL.XML") pool_name = params.get("pool_create_name", "virt_test_pool_tmp") pre_def_pool = params.get("pre_def_pool", "no") define_pool = params.get("define_pool", "no") define_pool_as = params.get("define_pool_as", "no") pool_create_as = params.get("pool_create_as", "no") need_pool_build = params.get("need_pool_build", "no") need_vol_create = params.get("need_vol_create", "no") pool_type = params.get("pool_type", "dir") source_format = params.get("pool_src_format", "") source_name = params.get("pool_source_name", "") source_path = params.get("pool_source_path", "/") pool_target = params.get("pool_target", "pool_target") pool_adapter_type = params.get("pool_adapter_type", "") pool_adapter_parent = params.get("pool_adapter_parent", "") target_device = params.get("disk_target_dev", "sdc") pool_wwnn = params.get("pool_wwnn", "POOL_WWNN_EXAMPLE") pool_wwpn = params.get("pool_wwpn", "POOL_WWPN_EXAMPLE") vhba_wwnn = params.get("vhba_wwnn", "VHBA_WWNN_EXAMPLE") vhba_wwpn = params.get("vhba_wwpn", "VHBA_WWPN_EXAMPLE") volume_name = params.get("volume_name", "imagefrommapper.qcow2") volume_capacity = params.get("volume_capacity", '1G') allocation = params.get("allocation", '1G') vol_format = params.get("volume_format", 'raw') attach_method = params.get("attach_method", "hot") test_unit = None mount_disk = None pool_kwargs = {} pool_extra_args = "" emulated_image = "emulated-image" disk_xml = "" new_vhbas = [] source_dev = "" mpath_vol_path = "" old_mpath_conf = "" mpath_conf_path = "/etc/multipath.conf" original_mpath_conf_exist = os.path.exists(mpath_conf_path) if pool_type == "scsi": if ('EXAMPLE' in pool_wwnn) or ('EXAMPLE' in pool_wwpn): raise exceptions.TestSkipError( "No wwpn and wwnn provided for npiv scsi pool.") if pool_type == "logical": if ('EXAMPLE' in vhba_wwnn) or ('EXAMPLE' in vhba_wwpn): raise exceptions.TestSkipError( "No wwpn and wwnn provided for vhba.") online_hbas_list = utils_npiv.find_hbas("hba") logging.debug("The online hbas are: %s", online_hbas_list) old_mpath_conf = utils_npiv.prepare_multipath_conf(conf_path=mpath_conf_path, replace_existing=True) if not online_hbas_list: raise exceptions.TestSkipError( "Host doesn't have online hba cards") old_vhbas = utils_npiv.find_hbas("vhba") vm_name = params.get("main_vm") vm = env.get_vm(vm_name) vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) vmxml_backup = vmxml.copy() if not vm.is_alive(): vm.start() libvirt_vm = lib_vm.VM(vm_name, vm.params, vm.root_dir, vm.address_cache) pool_ins = libvirt_storage.StoragePool() if pool_ins.pool_exists(pool_name): raise exceptions.TestFail("Pool %s already exist" % pool_name) if pool_type == "scsi": if define_pool == "yes": if pool_adapter_parent == "": pool_adapter_parent = online_hbas_list[0] pool_kwargs = {'source_path': source_path, 'source_name': source_name, 'source_format': source_format, 'pool_adapter_type': pool_adapter_type, 'pool_adapter_parent': pool_adapter_parent, 'pool_wwnn': pool_wwnn, 'pool_wwpn': pool_wwpn} elif pool_type == "logical": if (not vhba_wwnn) or (not vhba_wwpn): raise exceptions.TestFail("No wwnn/wwpn provided to create vHBA.") old_mpath_devs = utils_npiv.find_mpath_devs() new_vhba = utils_npiv.nodedev_create_from_xml({ "nodedev_parent": online_hbas_list[0], "scsi_wwnn": vhba_wwnn, "scsi_wwpn": vhba_wwpn}) utils_misc.wait_for( lambda: utils_npiv.is_vhbas_added(old_vhbas), timeout=_DELAY_TIME*2) if not new_vhba: raise exceptions.TestFail("vHBA not sucessfully generated.") new_vhbas.append(new_vhba) utils_misc.wait_for( lambda: utils_npiv.is_mpath_devs_added(old_mpath_devs), timeout=_DELAY_TIME*5) if not utils_npiv.is_mpath_devs_added(old_mpath_devs): raise exceptions.TestFail("mpath dev not generated.") cur_mpath_devs = utils_npiv.find_mpath_devs() new_mpath_devs = list(set(cur_mpath_devs).difference( set(old_mpath_devs))) logging.debug("The newly added mpath dev is: %s", new_mpath_devs) source_dev = "/dev/mapper/" + new_mpath_devs[0] logging.debug("We are going to use \"%s\" as our source device" " to create a logical pool", source_dev) try: cmd = "parted %s mklabel msdos -s" % source_dev cmd_result = process.run(cmd, shell=True) except Exception as e: raise exceptions.TestError("Error occurred when parted mklable") if define_pool_as == "yes": pool_extra_args = "" if source_dev: pool_extra_args = ' --source-dev %s' % source_dev elif pool_type == "mpath": if (not vhba_wwnn) or (not vhba_wwpn): raise exceptions.TestFail("No wwnn/wwpn provided to create vHBA.") old_mpath_devs = utils_npiv.find_mpath_devs() new_vhba = utils_npiv.nodedev_create_from_xml({ "nodedev_parent": online_hbas_list[0], "scsi_wwnn": vhba_wwnn, "scsi_wwpn": vhba_wwpn}) utils_misc.wait_for( lambda: utils_npiv.is_vhbas_added(old_vhbas), timeout=_DELAY_TIME*2) if not new_vhba: raise exceptions.TestFail("vHBA not sucessfully generated.") new_vhbas.append(new_vhba) utils_misc.wait_for( lambda: utils_npiv.is_mpath_devs_added(old_mpath_devs), timeout=_DELAY_TIME*2) if not utils_npiv.is_mpath_devs_added(old_mpath_devs): raise exceptions.TestFail("mpath dev not generated.") cur_mpath_devs = utils_npiv.find_mpath_devs() new_mpath_devs = list(set(cur_mpath_devs).difference( set(old_mpath_devs))) logging.debug("The newly added mpath dev is: %s", new_mpath_devs) mpath_vol_path = "/dev/mapper/" + new_mpath_devs[0] try: cmd = "parted %s mklabel msdos -s" % mpath_vol_path cmd_result = process.run(cmd, shell=True) except Exception as e: raise exceptions.TestError("Error occurred when parted mklable") if pre_def_pool == "yes": try: pvt = utlv.PoolVolumeTest(test, params) pvt.pre_pool(pool_name, pool_type, pool_target, emulated_image, **pool_kwargs) utils_misc.wait_for( lambda: utils_npiv.is_vhbas_added(old_vhbas), _DELAY_TIME*2) virsh.pool_dumpxml(pool_name, to_file=pool_xml_f) virsh.pool_destroy(pool_name) except Exception as e: pvt.cleanup_pool(pool_name, pool_type, pool_target, emulated_image, **pool_kwargs) raise exceptions.TestError( "Error occurred when prepare pool xml:\n %s" % e) if os.path.exists(pool_xml_f): with open(pool_xml_f, 'r') as f: logging.debug("Create pool from file: %s", f.read()) try: # define/create/start the pool if (pre_def_pool == "yes") and (define_pool == "yes"): pool_define_status = virsh.pool_define(pool_xml_f, ignore_status=True, debug=True) utlv.check_exit_status(pool_define_status) if define_pool_as == "yes": pool_define_as_status = virsh.pool_define_as( pool_name, pool_type, pool_target, pool_extra_args, ignore_status=True, debug=True ) utlv.check_exit_status(pool_define_as_status) if pool_create_as == "yes": if pool_type != "scsi": raise exceptions.TestSkipError("pool-create-as only needs to " "be covered by scsi pool for " "NPIV test.") cmd = "virsh pool-create-as %s %s \ --adapter-wwnn %s --adapter-wwpn %s \ --adapter-parent %s --target %s"\ % (pool_name, pool_type, pool_wwnn, pool_wwpn, online_hbas_list[0], pool_target) cmd_status = process.system(cmd, verbose=True) if cmd_status: raise exceptions.TestFail("pool-create-as scsi pool failed.") if need_pool_build == "yes": pool_build_status = virsh.pool_build(pool_name, "--overwrite") utlv.check_exit_status(pool_build_status) pool_ins = libvirt_storage.StoragePool() if not pool_ins.pool_exists(pool_name): raise exceptions.TestFail("define or create pool failed.") else: if not pool_ins.is_pool_active(pool_name): pool_start_status = virsh.pool_start(pool_name) utlv.check_exit_status(pool_start_status) utlv.check_actived_pool(pool_name) pool_detail = libvirt_xml.PoolXML.get_pool_details(pool_name) logging.debug("Pool detail: %s", pool_detail) # create vol if required if need_vol_create == "yes": vol_create_as_status = virsh.vol_create_as( volume_name, pool_name, volume_capacity, allocation, vol_format, "", debug=True ) utlv.check_exit_status(vol_create_as_status) virsh.pool_refresh(pool_name) vol_list = utlv.get_vol_list(pool_name, vol_check=True, timeout=_DELAY_TIME*3) logging.debug('Volume list is: %s' % vol_list) # use test_unit to save the first vol in pool if pool_type == "mpath": cmd = "virsh vol-list %s | grep \"%s\" |\ awk '{FS=\" \"} {print $1}'" % (pool_name, mpath_vol_path) cmd_result = process.run(cmd, shell=True) status = cmd_result.exit_status output = cmd_result.stdout_text.strip() if cmd_result.exit_status: raise exceptions.TestFail("vol-list pool %s failed", pool_name) if not output: raise exceptions.TestFail("Newly added mpath dev not in pool.") test_unit = output logging.info( "Using %s to attach to a guest", test_unit) else: test_unit = list(vol_list.keys())[0] logging.info( "Using the first volume %s to attach to a guest", test_unit) vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) session = vm.wait_for_login() output = session.cmd_status_output('lsblk') logging.debug("%s", output[1]) old_count = vmxml.get_disk_count(vm_name) bf_disks = libvirt_vm.get_disks() # prepare disk xml which will be hot/cold attached to vm disk_params = {'type_name': 'volume', 'target_dev': target_device, 'target_bus': 'virtio', 'source_pool': pool_name, 'source_volume': test_unit, 'driver_type': vol_format} disk_xml = os.path.join(data_dir.get_tmp_dir(), 'disk_xml.xml') lun_disk_xml = utlv.create_disk_xml(disk_params) copyfile(lun_disk_xml, disk_xml) disk_xml_str = open(lun_disk_xml).read() logging.debug("The disk xml is: %s", disk_xml_str) # hot attach disk xml to vm if attach_method == "hot": copyfile(lun_disk_xml, disk_xml) dev_attach_status = virsh.attach_device(vm_name, disk_xml, debug=True) # Pool/vol virtual disk is not supported by mpath pool yet. if dev_attach_status.exit_status and pool_type == "mpath": raise exceptions.TestSkipError("mpath pool vol is not " "supported in virtual disk yet," "the error message is: %s", dev_attach_status.stderr) session.close() utlv.check_exit_status(dev_attach_status) # cold attach disk xml to vm elif attach_method == "cold": if vm.is_alive(): vm.destroy(gracefully=False) new_disk = disk.Disk() new_disk.xml = disk_xml_str vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) vmxml.devices = vmxml.devices.append(new_disk) vmxml.sync() logging.debug(vmxml) try: vm.start() except virt_vm.VMStartError as e: logging.debug(e) if pool_type == "mpath": raise exceptions.TestSkipError("'mpath' pools for backing " "'volume' disks isn't " "supported for now") else: raise exceptions.TestFail("Failed to start vm") session = vm.wait_for_login() else: pass # checking attached disk in vm logging.info("Checking disk availability in domain") if not vmxml.get_disk_count(vm_name): raise exceptions.TestFail("No disk in domain %s." % vm_name) new_count = vmxml.get_disk_count(vm_name) if new_count <= old_count: raise exceptions.TestFail( "Failed to attach disk %s" % lun_disk_xml) logging.debug("Disks before attach: %s", bf_disks) af_disks = libvirt_vm.get_disks() logging.debug("Disks after attach: %s", af_disks) mount_disk = "".join(list(set(bf_disks) ^ set(af_disks))) if not mount_disk: raise exceptions.TestFail("Can not get attached device in vm.") logging.debug("Attached device in vm:%s", mount_disk) logging.debug("Creating file system for %s", mount_disk) output = session.cmd_status_output( 'echo yes | mkfs.ext4 %s' % mount_disk) logging.debug("%s", output[1]) if mount_disk: mount_success = mount_and_dd(session, mount_disk) if not mount_success: raise exceptions.TestFail("Mount failed") else: raise exceptions.TestFail("Partition not available for disk") logging.debug("Unmounting disk") session.cmd_status_output('umount %s' % mount_disk) output = session.cmd_status_output('mount') logging.debug("%s", output[1]) mount_success = mount_and_dd(session, mount_disk) if not mount_success: raise exceptions.TestFail("Mount failed") logging.debug("Unmounting disk") session.cmd_status_output('umount %s' % mount_disk) session.close() # detach disk from vm dev_detach_status = virsh.detach_device(vm_name, disk_xml, debug=True) utlv.check_exit_status(dev_detach_status) finally: vm.destroy(gracefully=False) vmxml_backup.sync() logging.debug('Destroying pool %s', pool_name) virsh.pool_destroy(pool_name) logging.debug('Undefining pool %s', pool_name) virsh.pool_undefine(pool_name) if os.path.exists(pool_xml_f): os.remove(pool_xml_f) if os.path.exists(disk_xml): data_dir.clean_tmp_files() logging.debug("Cleanup disk xml") if pre_def_pool == "yes": # Do not apply cleanup_pool for logical pool, logical pool will # be cleaned below pvt.cleanup_pool(pool_name, pool_type, pool_target, emulated_image, **pool_kwargs) if (test_unit and (need_vol_create == "yes" and (pre_def_pool == "no")) and (pool_type == "logical")): process.system('lvremove -f %s/%s' % (pool_name, test_unit), verbose=True) process.system('vgremove -f %s' % pool_name, verbose=True) process.system('pvremove -f %s' % source_dev, verbose=True) if new_vhbas: utils_npiv.vhbas_cleanup(new_vhbas) # Restart multipathd, this is to avoid bz1399075 if source_dev: utils_misc.wait_for(lambda: utils_npiv.restart_multipathd(source_dev), _DELAY_TIME*5, 0.0, 5.0) elif mpath_vol_path: utils_misc.wait_for(lambda: utils_npiv.restart_multipathd(mpath_vol_path), _DELAY_TIME*5, 0.0, 5.0) else: utils_npiv.restart_multipathd() if old_mpath_conf: utils_npiv.prepare_multipath_conf(conf_path=mpath_conf_path, conf_content=old_mpath_conf, replace_existing=True) if not original_mpath_conf_exist and os.path.exists(mpath_conf_path): os.remove(mpath_conf_path)
'source_volume': test_vol, 'driver_type': driver_type } else: disk_params = { 'type_name': disk_type, 'device': disk_device, 'driver_name': driver_name, 'driver_type': driver_type, 'source_file': path_to_blk, 'target_dev': device_target, 'target_bus': target_bus } if vm.is_alive(): vm.destroy(gracefully=False) new_disk = disk.Disk() new_disk.xml = open(utlv.create_disk_xml(disk_params)).read() # start vm with the virtual disk vmxml.devices = vmxml.devices.append(new_disk) vmxml.sync() vm.start() session = vm.wait_for_login() cur_disks = virt_vm.get_disks() mount_disk = "".join(list(set(old_disks) ^ set(cur_disks))) # mkfs and mount disk in vm, create a file on that disk. if not mount_disk: logging.debug("old_disk: %s, new_disk: %s", old_disks, cur_disks) raise exceptions.TestFail("No new disk found in vm.") mkfs_and_mount(session, mount_disk)
def create_disk_xml(params): """ Create a disk configuration file. """ # Create attributes dict for disk's address element type_name = params.get("type_name", "file") target_dev = params.get("target_dev", "vdb") target_bus = params.get("target_bus", "virtio") diskxml = disk.Disk(type_name) diskxml.device = params.get("device_type", "disk") source_attrs = {} source_host = [] auth_attrs = {} driver_attrs = {} try: if type_name == "file": source_file = params.get("source_file", "") source_attrs = {'file': source_file} elif type_name == "block": source_file = params.get("source_file", "") source_attrs = {'dev': source_file} elif type_name == "dir": source_dir = params.get("source_dir", "") source_attrs = {'dir': source_dir} elif type_name == "volume": source_pool = params.get("source_pool") source_volume = params.get("source_volume") source_mode = params.get("source_mode", "") source_attrs = { 'pool': source_pool, 'volume': source_volume, 'mode': source_mode } elif type_name == "network": source_protocol = params.get("source_protocol") source_name = params.get("source_name") source_host_name = params.get("source_host_name") source_host_port = params.get("source_host_port") source_attrs = {'protocol': source_protocol, 'name': source_name} source_host = [{ 'name': source_host_name, 'port': source_host_port }] else: error.TestNAError("Unsupport disk type %s" % type_name) source_startupPolicy = params.get("source_startupPolicy") if source_startupPolicy: source_attrs['startupPolicy'] = source_startupPolicy diskxml.source = diskxml.new_disk_source(attrs=source_attrs, hosts=source_host) auth_user = params.get("auth_user") secret_type = params.get("secret_type") secret_usage = params.get("secret_usage") if auth_user: auth_attrs['auth_user'] = auth_user if secret_type: auth_attrs['secret_type'] = secret_type if secret_usage: auth_attrs['secret_usage'] = secret_usage if auth_attrs: diskxml.auth = diskxml.new_auth(**auth_attrs) driver_name = params.get("driver_name", "qemu") driver_type = params.get("driver_type", "") driver_cache = params.get("driver_cache", "") if driver_name: driver_attrs['name'] = driver_name if driver_type: driver_attrs['type'] = driver_type if driver_cache: driver_attrs['cache'] = driver_cache if driver_attrs: diskxml.driver = driver_attrs diskxml.readonly = "yes" == params.get("readonly", "no") diskxml.share = "yes" == params.get("shareable", "no") diskxml.target = {'dev': target_dev, 'bus': target_bus} except Exception, detail: logging.error("Fail to create disk XML:\n%s", detail)