def create_luks_vol(vol_name, sec_uuid, params, test): """ Create a luks volume :param vol_name: the name of the volume :param sec_uuid: secret's uuid to be used for luks encryption :param params: detailed params to create volume :param test: test object """ pool_name = params.get("pool_name") extra_option = params.get("extra_option", "") unprivileged_user = params.get('unprivileged_user') uri = params.get("virsh_uri") vol_arg = {} for key in list(params.keys()): if (key.startswith('vol_') and not key.startswith('vol_new')): if key[4:] in ['capacity', 'allocation']: vol_arg[key[4:]] = int( float( utils_misc.normalize_data_size(params[key], "B", 1024))) elif key[4:] in ['owner', 'group']: vol_arg[key[4:]] = int(params[key]) else: vol_arg[key[4:]] = params[key] if vol_arg[key[ 4:]] == "qcow2" and not libvirt_version.version_compare( 6, 10, 0): test.cancel("Qcow2 format with luks encryption is not" " supported in current libvirt version") vol_arg['name'] = vol_name volxml = libvirt_xml.VolXML() newvol = volxml.new_vol(**vol_arg) luks_encryption_params = {} luks_encryption_params.update({"format": "luks"}) luks_encryption_params.update( {"secret": { "type": "passphrase", "uuid": sec_uuid }}) newvol.encryption = volxml.new_encryption(**luks_encryption_params) vol_xml = newvol['xml'] if params.get('setup_libvirt_polkit') == 'yes': process.run("chmod 666 %s" % vol_xml, ignore_status=True, shell=True) logging.debug("Create volume from XML: %s" % newvol.xmltreefile) cmd_result = virsh.vol_create(pool_name, vol_xml, extra_option, unprivileged_user=unprivileged_user, uri=uri, ignore_status=True, debug=True)
def create_luks_vol(pool_name, vol_name, sec_uuid, vol_arg): """ Create a luks volume :param pool_name: the pool in which a vol will be created :param vol_name: the name of the volume :param sec_uuid: secret's uuid to be used for luks encryption :param vol_arg: detailed params to create volume """ volxml = libvirt_xml.VolXML() newvol = volxml.new_vol(**vol_arg) luks_encryption_params = {} luks_encryption_params.update({"format": "luks"}) luks_encryption_params.update({"secret": {"type": "passphrase", "uuid": sec_uuid}}) newvol.encryption = volxml.new_encryption(**luks_encryption_params) vol_xml = newvol['xml'] logging.debug("Create volume from XML: %s" % newvol.xmltreefile) cmd_result = virsh.vol_create(pool_name, vol_xml, ignore_status=True, debug=True)
def check_vol(pool_name, vol_name, expect_exist=True): """ Check volume vol_name in pool pool_name """ src_volumes = src_pv.list_volumes().keys() logging.debug("Current volumes in %s: %s", pool_name, src_volumes) if expect_exist: if vol_name not in src_volumes: test.fail("Can't find volume %s in pool %s" % (vol_name, pool_name)) # check format in volume xml volxml = libvirt_xml.VolXML() post_xml = volxml.new_from_vol_dumpxml(vol_name, pool_name) logging.debug("Volume %s XML: %s" % (vol_name, post_xml.xmltreefile)) if 'format' in post_xml.keys() and vol_format is not None: if post_xml.format != vol_format: test.fail("Volume format %s is not expected" % vol_format + " as defined.") else: if vol_name in src_volumes: test.fail("Find volume %s in pool %s, but expect not" % (vol_name, pool_name))
def run(test, params, env): """ Test virsh vol-create and vol-create-as command to cover the following matrix: pool_type = [dir, fs, netfs] volume_format = [raw, bochs, cloop, cow, dmg, iso, qcow, qcow2, qed, vmdk, vpc] pool_type = [disk] volume_format = [none, linux, fat16, fat32, linux-swap, linux-lvm, linux-raid, extended] pool_type = [logical] volume_format = [none] pool_type = [iscsi, scsi] Not supported with format type TODO: pool_type = [rbd, glusterfs] Reference: http://www.libvirt.org/storage.html """ src_pool_type = params.get("src_pool_type") src_pool_target = params.get("src_pool_target") src_pool_format = params.get("src_pool_format", "") pool_vol_num = int(params.get("src_pool_vol_num", '1')) src_emulated_image = params.get("src_emulated_image") extra_option = params.get("extra_option", "") prefix_vol_name = params.get("vol_name", "vol_create_test") vol_format = params.get("vol_format", "raw") vol_capacity = params.get("vol_capacity", 1048576) vol_allocation = params.get("vol_allocation", 1048576) image_size = params.get("emulate_image_size", "1G") lazy_refcounts = "yes" == params.get("lazy_refcounts") status_error = "yes" == params.get("status_error", "no") by_xml = "yes" == params.get("create_vol_by_xml", "yes") incomplete_target = "yes" == params.get("incomplete_target", "no") luks_encrypted = "luks" == params.get("encryption_method") encryption_secret_type = params.get("encryption_secret_type", "passphrase") virsh_readonly_mode = 'yes' == params.get("virsh_readonly", "no") if not libvirt_version.version_compare(1, 0, 0): if "--prealloc-metadata" in extra_option: test.cancel("metadata preallocation not supported in" " current libvirt version.") if incomplete_target: test.cancel("It does not support generate target path" "in current libvirt version.") pool_type = ['dir', 'disk', 'fs', 'logical', 'netfs', 'iscsi', 'scsi'] if src_pool_type not in pool_type: test.cancel("pool type %s not in supported type list: %s" % (src_pool_type, pool_type)) # libvirt acl polkit related params 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.") uri = params.get("virsh_uri") unprivileged_user = params.get('unprivileged_user') if unprivileged_user: if unprivileged_user.count('EXAMPLE'): unprivileged_user = '******' # Stop multipathd to avoid start pool fail(For fs like pool, the new add # disk may in use by device-mapper, so start pool will report disk already # mounted error). multipathd = service.Factory.create_service("multipathd") multipathd_status = multipathd.status() if multipathd_status: multipathd.stop() # Set volume xml attribute dictionary, extract all params start with 'vol_' # which are for setting volume xml, except 'lazy_refcounts'. vol_arg = {} for key in params.keys(): if key.startswith('vol_'): if key[4:] in ['capacity', 'allocation', 'owner', 'group']: vol_arg[key[4:]] = int(params[key]) else: vol_arg[key[4:]] = params[key] vol_arg['lazy_refcounts'] = lazy_refcounts def create_luks_secret(vol_path): """ Create secret for luks encryption :param vol_path. volume path. :return: secret id if create successfully. """ sec_xml = secret_xml.SecretXML("no", "yes") sec_xml.description = "volume secret" sec_xml.usage = 'volume' sec_xml.volume = vol_path sec_xml.xmltreefile.write() ret = virsh.secret_define(sec_xml.xml) utlv.check_exit_status(ret) # Get secret uuid. try: encryption_uuid = re.findall(r".+\S+(\ +\S+)\ +.+\S+", ret.stdout.strip())[0].lstrip() except IndexError as detail: test.error("Fail to get newly created secret uuid") logging.debug("Secret uuid %s", encryption_uuid) # Set secret value. encoding = locale.getpreferredencoding() secret_string = base64.b64encode( 'redhat'.encode(encoding)).decode(encoding) ret = virsh.secret_set_value(encryption_uuid, secret_string) utlv.check_exit_status(ret) return encryption_uuid def post_process_vol(ori_vol_path): """ Create or disactive a volume without libvirt :param ori_vol_path: Full path of an original volume :retur: Volume name for checking """ process_vol_name = params.get("process_vol_name", "process_vol") process_vol_options = params.get("process_vol_options", "") process_vol_capacity = params.get("process_vol_capacity", vol_capacity) process_vol_cmd = "" unsupport_err = "Unsupport do '%s %s' in this test" % ( process_vol_by, process_vol_type) if process_vol_by == "lvcreate": process_vol_cmd = "lvcreate -L %s " % process_vol_capacity if process_vol_type == "thin": if not process_vol_options: process_vol_options = "-T " process_vol_cmd += "%s " % process_vol_options processthin_pool_name = params.get("processthin_pool_name", "thinpool") processthin_vol_name = params.get("processthin_vol_name", "thinvol") process_vol_capacity = params.get("process_vol_capacity", "1G") os.path.dirname(ori_vol_path) process_vol_cmd += "%s/%s " % (os.path.dirname(ori_vol_path), processthin_pool_name) process_vol_cmd += "-V %s " % process_vol_capacity process_vol_cmd += "-n %s " % processthin_vol_name process_vol_name = processthin_vol_name elif process_vol_type == "snapshot": if not process_vol_options: process_vol_options = "-s " process_vol_cmd += "%s " % process_vol_options process_vol_cmd += "-n %s " % process_vol_name process_vol_cmd += "%s " % (ori_vol_path) else: logging.error(unsupport_err) return elif process_vol_by == "qemu-img" and process_vol_type == "create": process_vol_cmd = "qemu-img create " process_vol_path = os.path.dirname(ori_vol_path) + "/" process_vol_path += process_vol_name process_vol_cmd += "%s " % process_vol_options process_vol_cmd += "%s " % process_vol_path process_vol_cmd += "%s " % process_vol_capacity elif process_vol_by == "lvchange" and process_vol_type == "deactivate": process_vol_cmd = "lvchange %s " % ori_vol_path if not process_vol_options: process_vol_options = "-an" process_vol_cmd += process_vol_options else: logging.error(unsupport_err) return rst = process.run(process_vol_cmd, ignore_status=True, shell=True) if rst.exit_status: if "Snapshots of snapshots are not supported" in rst.stderr_text: logging.debug("%s is already a snapshot volume", ori_vol_path) process_vol_name = os.path.basename(ori_vol_path) else: logging.error(rst.stderr_text) return return process_vol_name def check_vol(pool_name, vol_name, expect_exist=True): """ Check volume vol_name in pool pool_name """ src_volumes = src_pv.list_volumes().keys() logging.debug("Current volumes in %s: %s", pool_name, src_volumes) if expect_exist: if vol_name not in src_volumes: test.fail("Can't find volume %s in pool %s" % (vol_name, pool_name)) # check format in volume xml volxml = libvirt_xml.VolXML() post_xml = volxml.new_from_vol_dumpxml(vol_name, pool_name) logging.debug("Volume %s XML: %s" % (vol_name, post_xml.xmltreefile)) if 'format' in post_xml.keys() and vol_format is not None: if post_xml.format != vol_format: test.fail("Volume format %s is not expected" % vol_format + " as defined.") else: if vol_name in src_volumes: test.fail("Find volume %s in pool %s, but expect not" % (vol_name, pool_name)) fmt_err0 = "Unknown file format '%s'" % vol_format fmt_err1 = "Formatting or formatting option not " fmt_err1 += "supported for file format '%s'" % vol_format fmt_err2 = "Driver '%s' does not support " % vol_format fmt_err2 += "image creation" fmt_err_list = [fmt_err0, fmt_err1, fmt_err2] skip_msg = "Volume format '%s' is not supported by qemu-img" % vol_format vol_path_list = [] secret_uuids = [] try: # Create the src pool src_pool_name = "virt-%s-pool" % src_pool_type pvt = utlv.PoolVolumeTest(test, params) pvt.pre_pool(src_pool_name, src_pool_type, src_pool_target, src_emulated_image, image_size=image_size, source_format=src_pool_format) src_pv = libvirt_storage.PoolVolume(src_pool_name) src_pool_uuid = libvirt_storage.StoragePool().pool_info( src_pool_name)['UUID'] # Print current pools for debugging logging.debug("Current pools:%s", libvirt_storage.StoragePool().list_pools()) # Create volumes by virsh in a loop while pool_vol_num > 0: # Set volume xml file vol_name = prefix_vol_name + "_%s" % pool_vol_num bad_vol_name = params.get("bad_vol_name", "") if bad_vol_name: vol_name = bad_vol_name pool_vol_num -= 1 # disk partition for new volume if src_pool_type == "disk": vol_name = utlv.new_disk_vol_name(src_pool_name) if vol_name is None: test.error("Fail to generate volume name") if by_xml: # According to BZ#1138523, we need inpect the right name # (disk partition) for new volume if src_pool_type == "disk": vol_name = utlv.new_disk_vol_name(src_pool_name) if vol_name is None: test.error("Fail to generate volume name") vol_arg['name'] = vol_name volxml = libvirt_xml.VolXML() newvol = volxml.new_vol(**vol_arg) if luks_encrypted: # For luks encrypted disk, add related xml in newvol luks_encryption_params = {} luks_encryption_params.update({"format": "luks"}) luks_secret_uuid = create_luks_secret( os.path.join(src_pool_target, vol_name)) secret_uuids.append(luks_secret_uuid) luks_encryption_params.update({ "secret": { "type": encryption_secret_type, "uuid": luks_secret_uuid } }) newvol.encryption = volxml.new_encryption( **luks_encryption_params) vol_xml = newvol['xml'] if params.get('setup_libvirt_polkit') == 'yes': process.run("chmod 666 %s" % vol_xml, ignore_status=True, shell=True) if luks_encrypted and libvirt_version.version_compare( 4, 5, 0): try: polkit = test_setup.LibvirtPolkitConfig(params) polkit_rules_path = polkit.polkit_rules_path with open(polkit_rules_path, 'r+') as f: rule = f.readlines() for index, v in enumerate(rule): if v.find("secret") >= 0: nextline = rule[index + 1] s = nextline.replace( "QEMU", "secret").replace( "pool_name", "secret_uuid").replace( "virt-dir-pool", "%s" % luks_secret_uuid) rule[index + 1] = s rule = ''.join(rule) with open(polkit_rules_path, 'w+') as f: f.write(rule) logging.debug(rule) polkit.polkitd.restart() except IOError as e: logging.error(e) # Run virsh_vol_create to create vol logging.debug("Create volume from XML: %s" % newvol.xmltreefile) cmd_result = virsh.vol_create( src_pool_name, vol_xml, extra_option, unprivileged_user=unprivileged_user, uri=uri, ignore_status=True, debug=True) else: # Run virsh_vol_create_as to create_vol pool_name = src_pool_name if params.get("create_vol_by_pool_uuid") == "yes": pool_name = src_pool_uuid cmd_result = virsh.vol_create_as( vol_name, pool_name, vol_capacity, vol_allocation, vol_format, extra_option, unprivileged_user=unprivileged_user, uri=uri, readonly=virsh_readonly_mode, ignore_status=True, debug=True) # Check result try: utlv.check_exit_status(cmd_result, status_error) check_vol(src_pool_name, vol_name, not status_error) if bad_vol_name: pattern = "volume name '%s' cannot contain '/'" % vol_name logging.debug("pattern: %s", pattern) if "\\" in pattern and by_xml: pattern = pattern.replace("\\", "\\\\") if re.search(pattern, cmd_result.stderr) is None: test.fail("vol-create failed with unexpected reason") if not status_error: vol_path = virsh.vol_path(vol_name, src_pool_name).stdout.strip() logging.debug("Full path of %s: %s", vol_name, vol_path) vol_path_list.append(vol_path) except exceptions.TestFail as detail: stderr = cmd_result.stderr if any(err in stderr for err in fmt_err_list): test.cancel(skip_msg) else: test.fail("Create volume fail:\n%s" % detail) # Post process vol by other programs process_vol_by = params.get("process_vol_by") process_vol_type = params.get("process_vol_type", "") expect_vol_exist = "yes" == params.get("expect_vol_exist", "yes") if process_vol_by and vol_path_list: process_vol = post_process_vol(vol_path_list[0]) if process_vol is not None: try: virsh.pool_refresh(src_pool_name, ignore_status=False) check_vol(src_pool_name, process_vol, expect_vol_exist) except (process.CmdError, exceptions.TestFail) as detail: if process_vol_type == "thin": logging.error(str(detail)) test.cancel("You may encounter bug BZ#1060287") else: test.fail("Fail to refresh pool:\n%s" % detail) else: test.fail("Post process volume failed") finally: # Cleanup # For old version lvm2(2.02.106 or early), deactivate volume group # (destroy libvirt logical pool) will fail if which has deactivated # lv snapshot, so before destroy the pool, we need activate it manually if src_pool_type == 'logical' and vol_path_list: vg_name = vol_path_list[0].split('/')[2] process.run("lvchange -ay %s" % vg_name, shell=True) try: pvt.cleanup_pool(src_pool_name, src_pool_type, src_pool_target, src_emulated_image) for secret_uuid in set(secret_uuids): virsh.secret_undefine(secret_uuid) except exceptions.TestFail as detail: logging.error(str(detail)) if multipathd_status: multipathd.start()
def run(test, params, env): """ Test virsh snapshot command when disk in all kinds of type. (1). Init the variables from params. (2). Create a image by specifice format. (3). Attach disk to vm. (4). Snapshot create. (5). Snapshot revert. (6). cleanup. """ # Init variables. vm_name = params.get("main_vm", "avocado-vt-vm1") vm = env.get_vm(vm_name) vm_state = params.get("vm_state", "running") image_format = params.get("snapshot_image_format", "qcow2") snapshot_del_test = "yes" == params.get("snapshot_del_test", "no") status_error = ("yes" == params.get("status_error", "no")) snapshot_from_xml = ("yes" == params.get("snapshot_from_xml", "no")) snapshot_current = ("yes" == params.get("snapshot_current", "no")) snapshot_revert_paused = ("yes" == params.get("snapshot_revert_paused", "no")) replace_vm_disk = "yes" == params.get("replace_vm_disk", "no") disk_source_protocol = params.get("disk_source_protocol") 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) multi_gluster_disks = "yes" == params.get("multi_gluster_disks", "no") # Pool variables. snapshot_with_pool = "yes" == params.get("snapshot_with_pool", "no") pool_name = params.get("pool_name") pool_type = params.get("pool_type") pool_target = params.get("pool_target") emulated_image = params.get("emulated_image", "emulated-image") vol_format = params.get("vol_format") lazy_refcounts = "yes" == params.get("lazy_refcounts") options = params.get("snapshot_options", "") export_options = params.get("export_options", "rw,no_root_squash,fsid=0") # Set volume xml attribute dictionary, extract all params start with 'vol_' # which are for setting volume xml, except 'lazy_refcounts'. vol_arg = {} for key in params.keys(): if key.startswith('vol_'): if key[4:] in ['capacity', 'allocation', 'owner', 'group']: vol_arg[key[4:]] = int(params[key]) else: vol_arg[key[4:]] = params[key] vol_arg['lazy_refcounts'] = lazy_refcounts supported_pool_list = [ "dir", "fs", "netfs", "logical", "iscsi", "disk", "gluster" ] if snapshot_with_pool: if pool_type not in supported_pool_list: raise error.TestNAError("%s not in support list %s" % (pool_target, supported_pool_list)) # Do xml backup for final recovery vmxml_backup = libvirt_xml.VMXML.new_from_inactive_dumpxml(vm_name) # Some variable for xmlfile of snapshot. snapshot_memory = params.get("snapshot_memory", "internal") snapshot_disk = params.get("snapshot_disk", "internal") no_memory_snap = "yes" == params.get("no_memory_snap", "no") # Skip 'qed' cases for libvirt version greater than 1.1.0 if libvirt_version.version_compare(1, 1, 0): if vol_format == "qed" or image_format == "qed": raise error.TestNAError("QED support changed, check bug: " "https://bugzilla.redhat.com/show_bug.cgi" "?id=731570") 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_source_protocol == 'gluster': raise error.TestNAError("Snapshot on glusterfs not support in " "current version. Check more info with " "https://bugzilla.redhat.com/buglist.cgi?" "bug_id=1017289,1032370") # Init snapshot_name snapshot_name = None snapshot_external_disk = [] snapshot_xml_path = None del_status = None image = None pvt = None # Get a tmp dir snap_cfg_path = "/var/lib/libvirt/qemu/snapshot/%s/" % vm_name try: if replace_vm_disk: utlv.set_vm_disk(vm, params, tmp_dir) if multi_gluster_disks: new_params = params.copy() new_params["pool_name"] = "gluster-pool2" new_params["vol_name"] = "gluster-vol2" new_params["disk_target"] = "vdf" new_params["image_convert"] = 'no' utlv.set_vm_disk(vm, new_params, tmp_dir) if snapshot_with_pool: # Create dst pool for create attach vol img pvt = utlv.PoolVolumeTest(test, params) pvt.pre_pool(pool_name, pool_type, pool_target, emulated_image, image_size="1G", pre_disk_vol=["20M"], source_name=vol_name, export_options=export_options) if pool_type in ["iscsi", "disk"]: # iscsi and disk pool did not support create volume in libvirt, # logical pool could use libvirt to create volume but volume # format is not supported and will be 'raw' as default. pv = libvirt_storage.PoolVolume(pool_name) vols = pv.list_volumes().keys() if vols: vol_name = vols[0] else: raise error.TestNAError("No volume in pool: %s" % pool_name) else: # Set volume xml file volxml = libvirt_xml.VolXML() newvol = volxml.new_vol(**vol_arg) vol_xml = newvol['xml'] # Run virsh_vol_create to create vol logging.debug("create volume from xml: %s" % newvol.xmltreefile) cmd_result = virsh.vol_create(pool_name, vol_xml, ignore_status=True, debug=True) if cmd_result.exit_status: raise error.TestNAError("Failed to create attach volume.") cmd_result = virsh.vol_path(vol_name, pool_name, debug=True) if cmd_result.exit_status: raise error.TestNAError("Failed to get volume path from pool.") img_path = cmd_result.stdout.strip() if pool_type in ["logical", "iscsi", "disk"]: # Use qemu-img to format logical, iscsi and disk block device if vol_format != "raw": cmd = "qemu-img create -f %s %s 10M" % (vol_format, img_path) cmd_result = utils.run(cmd, ignore_status=True) if cmd_result.exit_status: raise error.TestNAError("Failed to format volume, %s" % cmd_result.stdout.strip()) extra = "--persistent --subdriver %s" % vol_format else: # Create a image. params['image_name'] = "snapshot_test" params['image_format'] = image_format params['image_size'] = "1M" image = qemu_storage.QemuImg(params, tmp_dir, "snapshot_test") img_path, _ = image.create(params) extra = "--persistent --subdriver %s" % image_format if not multi_gluster_disks: # Do the attach action. out = utils.run("qemu-img info %s" % img_path) logging.debug("The img info is:\n%s" % out.stdout.strip()) result = virsh.attach_disk(vm_name, source=img_path, target="vdf", extra=extra, debug=True) if result.exit_status: raise error.TestNAError("Failed to attach disk %s to VM." "Detail: %s." % (img_path, result.stderr)) # Create snapshot. if snapshot_from_xml: snap_xml = libvirt_xml.SnapshotXML() snapshot_name = "snapshot_test" snap_xml.snap_name = snapshot_name snap_xml.description = "Snapshot Test" if not no_memory_snap: if "--disk-only" not in options: if snapshot_memory == "external": memory_external = os.path.join(tmp_dir, "snapshot_memory") snap_xml.mem_snap_type = snapshot_memory snap_xml.mem_file = memory_external snapshot_external_disk.append(memory_external) else: snap_xml.mem_snap_type = snapshot_memory # Add all disks into xml file. vmxml = libvirt_xml.VMXML.new_from_inactive_dumpxml(vm_name) disks = vmxml.devices.by_device_tag('disk') new_disks = [] for src_disk_xml in disks: disk_xml = snap_xml.SnapDiskXML() disk_xml.xmltreefile = src_disk_xml.xmltreefile del disk_xml.device del disk_xml.address disk_xml.snapshot = snapshot_disk disk_xml.disk_name = disk_xml.target['dev'] # Only qcow2 works as external snapshot file format, update it # here driver_attr = disk_xml.driver driver_attr.update({'type': 'qcow2'}) disk_xml.driver = driver_attr if snapshot_disk == 'external': new_attrs = disk_xml.source.attrs if disk_xml.source.attrs.has_key('file'): new_file = "%s.snap" % disk_xml.source.attrs['file'] snapshot_external_disk.append(new_file) new_attrs.update({'file': new_file}) hosts = None elif disk_xml.source.attrs.has_key('name'): new_name = "%s.snap" % disk_xml.source.attrs['name'] new_attrs.update({'name': new_name}) hosts = disk_xml.source.hosts elif (disk_xml.source.attrs.has_key('dev') and disk_xml.type_name == 'block'): # Use local file as external snapshot target for block type. # As block device will be treat as raw format by default, # it's not fit for external disk snapshot target. A work # around solution is use qemu-img again with the target. disk_xml.type_name = 'file' del new_attrs['dev'] new_file = "%s/blk_src_file.snap" % tmp_dir snapshot_external_disk.append(new_file) new_attrs.update({'file': new_file}) hosts = None new_src_dict = {"attrs": new_attrs} if hosts: new_src_dict.update({"hosts": hosts}) disk_xml.source = disk_xml.new_disk_source(**new_src_dict) else: del disk_xml.source new_disks.append(disk_xml) snap_xml.set_disks(new_disks) snapshot_xml_path = snap_xml.xml logging.debug("The snapshot xml is: %s" % snap_xml.xmltreefile) options += " --xmlfile %s " % snapshot_xml_path if vm_state == "shut off": vm.destroy(gracefully=False) snapshot_result = virsh.snapshot_create(vm_name, options, debug=True) out_err = snapshot_result.stderr.strip() if snapshot_result.exit_status: if status_error: return else: if re.search( "live disk snapshot not supported with this " "QEMU binary", out_err): raise error.TestNAError(out_err) if libvirt_version.version_compare(1, 2, 5): # As commit d2e668e in 1.2.5, internal active snapshot # without memory state is rejected. Handle it as SKIP # for now. This could be supportted in future by bug: # https://bugzilla.redhat.com/show_bug.cgi?id=1103063 if re.search( "internal snapshot of a running VM" + " must include the memory state", out_err): raise error.TestNAError("Check Bug #1083345, %s" % out_err) raise error.TestFail( "Failed to create snapshot. Error:%s." % out_err) else: snapshot_result = virsh.snapshot_create(vm_name, options, debug=True) if snapshot_result.exit_status: if status_error: return else: raise error.TestFail( "Failed to create snapshot. Error:%s." % snapshot_result.stderr.strip()) snapshot_name = re.search("\d+", snapshot_result.stdout.strip()).group(0) if snapshot_current: snap_xml = libvirt_xml.SnapshotXML() new_snap = snap_xml.new_from_snapshot_dumpxml( vm_name, snapshot_name) # update an element new_snap.creation_time = snapshot_name snapshot_xml_path = new_snap.xml options += "--redefine %s --current" % snapshot_xml_path snapshot_result = virsh.snapshot_create(vm_name, options, debug=True) if snapshot_result.exit_status: raise error.TestFail("Failed to create snapshot --current." "Error:%s." % snapshot_result.stderr.strip()) if status_error: if not snapshot_del_test: raise error.TestFail("Success to create snapshot in negative" " case\nDetail: %s" % snapshot_result) # Touch a file in VM. if vm.is_dead(): vm.start() session = vm.wait_for_login() # Init a unique name for tmp_file. tmp_file = tempfile.NamedTemporaryFile(prefix=("snapshot_test_"), dir="/tmp") tmp_file_path = tmp_file.name tmp_file.close() echo_cmd = "echo SNAPSHOT_DISK_TEST >> %s" % tmp_file_path status, output = session.cmd_status_output(echo_cmd) logging.debug("The echo output in domain is: '%s'", output) if status: raise error.TestFail("'%s' run failed with '%s'" % (tmp_file_path, output)) status, output = session.cmd_status_output("cat %s" % tmp_file_path) logging.debug("File created with content: '%s'", output) session.close() # As only internal snapshot revert works now, let's only do revert # with internal, and move the all skip external cases back to pass. # After external also supported, just move the following code back. if snapshot_disk == 'internal': # Destroy vm for snapshot revert. if not libvirt_version.version_compare(1, 2, 3): virsh.destroy(vm_name) # Revert snapshot. revert_options = "" if snapshot_revert_paused: revert_options += " --paused" revert_result = virsh.snapshot_revert(vm_name, snapshot_name, revert_options, debug=True) if revert_result.exit_status: # Attempts to revert external snapshots will FAIL with an error # "revert to external disk snapshot not supported yet" or "revert # to external snapshot not supported yet" since d410e6f. Thus, # let's check for that and handle as a SKIP for now. Check bug: # https://bugzilla.redhat.com/show_bug.cgi?id=1071264 if re.search( "revert to external \w* ?snapshot not supported yet", revert_result.stderr): raise error.TestNAError(revert_result.stderr.strip()) else: raise error.TestFail("Revert snapshot failed. %s" % revert_result.stderr.strip()) if vm.is_dead(): raise error.TestFail("Revert snapshot failed.") if snapshot_revert_paused: if vm.is_paused(): vm.resume() else: raise error.TestFail( "Revert command successed, but VM is not " "paused after reverting with --paused" " option.") # login vm. session = vm.wait_for_login() # Check the result of revert. status, output = session.cmd_status_output("cat %s" % tmp_file_path) logging.debug("After revert cat file output='%s'", output) if not status: raise error.TestFail("Tmp file exists, revert failed.") # Close the session. session.close() # Test delete snapshot without "--metadata", delete external disk # snapshot will fail for now. # Only do this when snapshot creat succeed which filtered in cfg file. if snapshot_del_test: if snapshot_name: del_result = virsh.snapshot_delete(vm_name, snapshot_name, debug=True, ignore_status=True) del_status = del_result.exit_status snap_xml_path = snap_cfg_path + "%s.xml" % snapshot_name if del_status: if not status_error: raise error.TestFail("Failed to delete snapshot.") else: if not os.path.exists(snap_xml_path): raise error.TestFail( "Snapshot xml file %s missing" % snap_xml_path) else: if status_error: err_msg = "Snapshot delete succeed but expect fail." raise error.TestFail(err_msg) else: if os.path.exists(snap_xml_path): raise error.TestFail("Snapshot xml file %s still" % snap_xml_path + " exist") finally: if vm.is_alive(): vm.destroy(gracefully=False) virsh.detach_disk(vm_name, target="vdf", extra="--persistent") if image: image.remove() if del_status and snapshot_name: virsh.snapshot_delete(vm_name, snapshot_name, "--metadata") for disk in snapshot_external_disk: if os.path.exists(disk): os.remove(disk) vmxml_backup.sync("--snapshots-metadata") libvirtd = utils_libvirtd.Libvirtd() if disk_source_protocol == 'gluster': utlv.setup_or_cleanup_gluster(False, vol_name, brick_path) if multi_gluster_disks: brick_path = os.path.join(tmp_dir, "gluster-pool2") utlv.setup_or_cleanup_gluster(False, "gluster-vol2", brick_path) libvirtd.restart() if snapshot_xml_path: if os.path.exists(snapshot_xml_path): os.unlink(snapshot_xml_path) if pvt: try: pvt.cleanup_pool(pool_name, pool_type, pool_target, emulated_image, source_name=vol_name) except error.TestFail, detail: libvirtd.restart() logging.error(str(detail))
def run(test, params, env): """ Test svirt in adding disk to VM. (1).Init variables for test. (2).Create a image to attached to VM. (3).Attach disk. (4).Start VM and check result. """ # Get general variables. status_error = ('yes' == params.get("status_error", 'no')) host_sestatus = params.get("svirt_attach_disk_host_selinux", "enforcing") # Get variables about seclabel for VM. sec_type = params.get("svirt_attach_disk_vm_sec_type", "dynamic") sec_model = params.get("svirt_attach_disk_vm_sec_model", "selinux") sec_label = params.get("svirt_attach_disk_vm_sec_label", None) sec_relabel = params.get("svirt_attach_disk_vm_sec_relabel", "yes") sec_dict = { 'type': sec_type, 'model': sec_model, 'label': sec_label, 'relabel': sec_relabel } disk_seclabel = params.get("disk_seclabel", "no") # Get variables about pool vol with_pool_vol = 'yes' == params.get("with_pool_vol", "no") check_cap_rawio = "yes" == params.get("check_cap_rawio", "no") virt_use_nfs = params.get("virt_use_nfs", "off") pool_name = params.get("pool_name") pool_type = params.get("pool_type") pool_target = params.get("pool_target") emulated_image = params.get("emulated_image") vol_name = params.get("vol_name") vol_format = params.get("vol_format", "qcow2") device_target = params.get("disk_target") device_bus = params.get("disk_target_bus") device_type = params.get("device_type", "file") # Get variables about VM and get a VM object and VMXML instance. vm_name = params.get("main_vm") vm = env.get_vm(vm_name) vmxml = VMXML.new_from_inactive_dumpxml(vm_name) backup_xml = vmxml.copy() # Get varialbles about image. img_label = params.get('svirt_attach_disk_disk_label') sec_disk_dict = { 'model': sec_model, 'label': img_label, 'relabel': sec_relabel } enable_namespace = 'yes' == params.get('enable_namespace', 'no') img_name = "svirt_disk" # Default label for the other disks. # To ensure VM is able to access other disks. default_label = params.get('svirt_attach_disk_disk_default_label', None) # Set selinux of host. backup_sestatus = utils_selinux.get_status() utils_selinux.set_status(host_sestatus) # Set the default label to other disks of vm. disks = vm.get_disk_devices() for disk in list(disks.values()): utils_selinux.set_context_of_file(filename=disk['source'], context=default_label) pvt = None qemu_conf = utils_config.LibvirtQemuConfig() libvirtd = utils_libvirtd.Libvirtd() disk_xml = Disk(type_name=device_type) disk_xml.device = "disk" try: # set qemu conf if check_cap_rawio: qemu_conf.user = '******' qemu_conf.group = 'root' logging.debug("the qemu.conf content is: %s" % qemu_conf) libvirtd.restart() if with_pool_vol: # Create dst pool for create attach vol img pvt = utlv.PoolVolumeTest(test, params) logging.debug("pool_type %s" % pool_type) pvt.pre_pool(pool_name, pool_type, pool_target, emulated_image, image_size="1G", pre_disk_vol=["20M"]) if pool_type in ["iscsi", "disk"]: # iscsi and disk pool did not support create volume in libvirt, # logical pool could use libvirt to create volume but volume # format is not supported and will be 'raw' as default. pv = libvirt_storage.PoolVolume(pool_name) vols = list(pv.list_volumes().keys()) vol_format = "raw" if vols: vol_name = vols[0] else: test.cancel("No volume in pool: %s" % pool_name) else: vol_arg = { 'name': vol_name, 'format': vol_format, 'capacity': 1073741824, 'allocation': 1048576, } # Set volume xml file volxml = libvirt_xml.VolXML() newvol = volxml.new_vol(**vol_arg) vol_xml = newvol['xml'] # Run virsh_vol_create to create vol logging.debug("create volume from xml: %s" % newvol.xmltreefile) cmd_result = virsh.vol_create(pool_name, vol_xml, ignore_status=True, debug=True) if cmd_result.exit_status: test.cancel("Failed to create attach volume.") cmd_result = virsh.vol_path(vol_name, pool_name, debug=True) if cmd_result.exit_status: test.cancel("Failed to get volume path from pool.") img_path = cmd_result.stdout.strip() if pool_type in ["iscsi", "disk"]: source_type = "dev" if pool_type == "iscsi": disk_xml.device = "lun" disk_xml.rawio = "yes" else: if not enable_namespace: qemu_conf.namespaces = '' logging.debug("the qemu.conf content is: %s" % qemu_conf) libvirtd.restart() else: source_type = "file" # set host_sestatus as nfs pool will reset it utils_selinux.set_status(host_sestatus) # set virt_use_nfs result = process.run("setsebool virt_use_nfs %s" % virt_use_nfs, shell=True) if result.exit_status: test.cancel("Failed to set virt_use_nfs value") else: source_type = "file" # Init a QemuImg instance. params['image_name'] = img_name tmp_dir = data_dir.get_tmp_dir() image = qemu_storage.QemuImg(params, tmp_dir, img_name) # Create a image. img_path, result = image.create(params) # Set the context of the image. if sec_relabel == "no": utils_selinux.set_context_of_file(filename=img_path, context=img_label) disk_xml.target = {"dev": device_target, "bus": device_bus} disk_xml.driver = {"name": "qemu", "type": vol_format} if disk_seclabel == "yes": source_seclabel = [] sec_xml = seclabel.Seclabel() sec_xml.update(sec_disk_dict) source_seclabel.append(sec_xml) disk_source = disk_xml.new_disk_source(**{ "attrs": { source_type: img_path }, "seclabels": source_seclabel }) else: disk_source = disk_xml.new_disk_source( **{"attrs": { source_type: img_path }}) # Set the context of the VM. vmxml.set_seclabel([sec_dict]) vmxml.sync() disk_xml.source = disk_source logging.debug(disk_xml) # Do the attach action. cmd_result = virsh.attach_device(domainarg=vm_name, filearg=disk_xml.xml, flagstr='--persistent') libvirt.check_exit_status(cmd_result, expect_error=False) logging.debug("the domain xml is: %s" % vmxml.xmltreefile) # Start VM to check the VM is able to access the image or not. try: vm.start() # Start VM successfully. # VM with set seclabel can access the image with the # set context. if status_error: test.fail('Test succeeded in negative case.') if check_cap_rawio: cap_list = ['CapPrm', 'CapEff', 'CapBnd'] cap_dict = {} pid = vm.get_pid() pid_status_path = "/proc/%s/status" % pid with open(pid_status_path) as f: for line in f: val_list = line.split(":") if val_list[0] in cap_list: cap_dict[val_list[0]] = int( val_list[1].strip(), 16) # bit and with rawio capabilitiy value to check cap_sys_rawio # is set cap_rawio_val = 0x0000000000020000 for i in cap_list: if not cap_rawio_val & cap_dict[i]: err_msg = "vm process with %s: 0x%x" % (i, cap_dict[i]) err_msg += " lack cap_sys_rawio capabilities" test.fail(err_msg) else: inf_msg = "vm process with %s: 0x%x" % (i, cap_dict[i]) inf_msg += " have cap_sys_rawio capabilities" logging.debug(inf_msg) if pool_type == "disk": if libvirt_version.version_compare(3, 1, 0) and enable_namespace: vm_pid = vm.get_pid() output = process.system_output( "nsenter -t %d -m -- ls -Z %s" % (vm_pid, img_path)) else: output = process.system_output('ls -Z %s' % img_path) logging.debug("The default label is %s", default_label) logging.debug("The label after guest started is %s", to_text(output.strip().split()[-2])) if default_label not in to_text(output.strip().split()[-2]): test.fail("The label is wrong after guest started\n") except virt_vm.VMStartError as e: # Starting VM failed. # VM with set seclabel can not access the image with the # set context. if not status_error: test.fail("Test failed in positive case." "error: %s" % e) cmd_result = virsh.detach_device(domainarg=vm_name, filearg=disk_xml.xml) libvirt.check_exit_status(cmd_result, status_error) finally: # clean up vm.destroy() if not with_pool_vol: image.remove() if pvt: try: pvt.cleanup_pool(pool_name, pool_type, pool_target, emulated_image) except exceptions.TestFail as detail: logging.error(str(detail)) backup_xml.sync() utils_selinux.set_status(backup_sestatus) if check_cap_rawio: qemu_conf.restore() libvirtd.restart()
def run(test, params, env): """ Test svirt in adding disk to VM. (1).Init variables for test. (2).Create a image to attached to VM. (3).Attach disk. (4).Start VM and check result. """ # Get general variables. status_error = ('yes' == params.get("status_error", 'no')) host_sestatus = params.get("svirt_attach_disk_host_selinux", "enforcing") # Get variables about seclabel for VM. sec_type = params.get("svirt_attach_disk_vm_sec_type", "dynamic") sec_model = params.get("svirt_attach_disk_vm_sec_model", "selinux") sec_label = params.get("svirt_attach_disk_vm_sec_label", None) sec_relabel = params.get("svirt_attach_disk_vm_sec_relabel", "yes") sec_dict = {'type': sec_type, 'model': sec_model, 'label': sec_label, 'relabel': sec_relabel} # Get variables about pool vol with_pool_vol = 'yes' == params.get("with_pool_vol", "no") check_cap_rawio = "yes" == params.get("check_cap_rawio", "no") virt_use_nfs = params.get("virt_use_nfs", "off") pool_name = params.get("pool_name") pool_type = params.get("pool_type") pool_target = params.get("pool_target") emulated_image = params.get("emulated_image") vol_name = params.get("vol_name") vol_format = params.get("vol_format") # Get variables about VM and get a VM object and VMXML instance. vm_name = params.get("main_vm") vm = env.get_vm(vm_name) vmxml = VMXML.new_from_inactive_dumpxml(vm_name) backup_xml = vmxml.copy() # Get varialbles about image. img_label = params.get('svirt_attach_disk_disk_label') img_name = "svirt_disk" # Default label for the other disks. # To ensure VM is able to access other disks. default_label = params.get('svirt_attach_disk_disk_default_label', None) # Set selinux of host. backup_sestatus = utils_selinux.get_status() utils_selinux.set_status(host_sestatus) # Set the default label to other disks of vm. disks = vm.get_disk_devices() for disk in disks.values(): utils_selinux.set_context_of_file(filename=disk['source'], context=default_label) pvt = None qemu_conf = utils_config.LibvirtQemuConfig() libvirtd = utils_libvirtd.Libvirtd() try: # set qemu conf if check_cap_rawio: qemu_conf.user = '******' qemu_conf.group = 'root' logging.debug("the qemu.conf content is: %s" % qemu_conf) libvirtd.restart() # Set the context of the VM. vmxml.set_seclabel([sec_dict]) vmxml.sync() logging.debug("the domain xml is: %s" % vmxml.xmltreefile) if with_pool_vol: # Create dst pool for create attach vol img pvt = utlv.PoolVolumeTest(test, params) logging.debug("pool_type %s" % pool_type) pvt.pre_pool(pool_name, pool_type, pool_target, emulated_image, image_size="1G", pre_disk_vol=["20M"]) if pool_type in ["iscsi", "disk"]: # iscsi and disk pool did not support create volume in libvirt, # logical pool could use libvirt to create volume but volume # format is not supported and will be 'raw' as default. pv = libvirt_storage.PoolVolume(pool_name) vols = pv.list_volumes().keys() if vols: vol_name = vols[0] else: raise error.TestNAError("No volume in pool: %s" % pool_name) else: vol_arg = {'name': vol_name, 'format': vol_format, 'capacity': 1073741824, 'allocation': 1048576, } # Set volume xml file volxml = libvirt_xml.VolXML() newvol = volxml.new_vol(**vol_arg) vol_xml = newvol['xml'] # Run virsh_vol_create to create vol logging.debug("create volume from xml: %s" % newvol.xmltreefile) cmd_result = virsh.vol_create(pool_name, vol_xml, ignore_status=True, debug=True) if cmd_result.exit_status: raise error.TestNAError("Failed to create attach volume.") cmd_result = virsh.vol_path(vol_name, pool_name, debug=True) if cmd_result.exit_status: raise error.TestNAError("Failed to get volume path from pool.") img_path = cmd_result.stdout.strip() if pool_type in ["iscsi", "disk"]: extra = "--driver qemu --type lun --rawio --persistent" else: extra = "--persistent --subdriver qcow2" # set host_sestatus as nfs pool will reset it utils_selinux.set_status(host_sestatus) # set virt_use_nfs result = utils.run("setsebool virt_use_nfs %s" % virt_use_nfs) if result.exit_status: raise error.TestNAError("Failed to set virt_use_nfs value") else: # Init a QemuImg instance. params['image_name'] = img_name tmp_dir = data_dir.get_tmp_dir() image = qemu_storage.QemuImg(params, tmp_dir, img_name) # Create a image. img_path, result = image.create(params) # Set the context of the image. utils_selinux.set_context_of_file(filename=img_path, context=img_label) extra = "--persistent" # Do the attach action. result = virsh.attach_disk(vm_name, source=img_path, target="vdf", extra=extra, debug=True) if result.exit_status: raise error.TestFail("Failed to attach disk %s to VM." "Detail: %s." % (img_path, result.stderr)) # Start VM to check the VM is able to access the image or not. try: vm.start() # Start VM successfully. # VM with set seclabel can access the image with the # set context. if status_error: raise error.TestFail('Test succeeded in negative case.') if check_cap_rawio: cap_list = ['CapPrm', 'CapEff', 'CapBnd'] cap_dict = {} pid = vm.get_pid() pid_status_path = "/proc/%s/status" % pid with open(pid_status_path) as f: for line in f: val_list = line.split(":") if val_list[0] in cap_list: cap_dict[val_list[0]] = int(val_list[1].strip(), 16) # bit and with rawio capabilitiy value to check cap_sys_rawio # is set cap_rawio_val = 0x0000000000020000 for i in cap_list: if not cap_rawio_val & cap_dict[i]: err_msg = "vm process with %s: 0x%x" % (i, cap_dict[i]) err_msg += " lack cap_sys_rawio capabilities" raise error.TestFail(err_msg) else: inf_msg = "vm process with %s: 0x%x" % (i, cap_dict[i]) inf_msg += " have cap_sys_rawio capabilities" logging.debug(inf_msg) except virt_vm.VMStartError, e: # Starting VM failed. # VM with set seclabel can not access the image with the # set context. if not status_error: raise error.TestFail("Test failed in positive case." "error: %s" % e) try: virsh.detach_disk(vm_name, target="vdf", extra="--persistent", debug=True) except error.CmdError: raise error.TestFail("Detach disk 'vdf' from VM %s failed." % vm.name)
def run(test, params, env): """ Test virsh vol-create command to cover the following matrix: pool_type = [dir, fs, netfs] volume_format = [raw, bochs, cloop, cow, dmg, iso, qcow, qcow2, qed, vmdk, vpc] pool_type = [disk] volume_format = [none, linux, fat16, fat32, linux-swap, linux-lvm, linux-raid, extended] pool_type = [logical] volume_format = [none] pool_type = [iscsi, scsi] Not supported with format type TODO: pool_type = [rbd, glusterfs] Reference: http://www.libvirt.org/storage.html """ src_pool_type = params.get("src_pool_type") src_pool_target = params.get("src_pool_target") src_emulated_image = params.get("src_emulated_image") extra_option = params.get("extra_option", "") vol_name = params.get("vol_name", "vol_create_test") vol_format = params.get("vol_format") lazy_refcounts = "yes" == params.get("lazy_refcounts") status_error = "yes" == params.get("status_error", "no") # Set volume xml attribute dictionary, extract all params start with 'vol_' # which are for setting volume xml, except 'lazy_refcounts'. vol_arg = {} for key in params.keys(): if key.startswith('vol_'): if key[4:] in ['capacity', 'allocation', 'owner', 'group']: vol_arg[key[4:]] = int(params[key]) else: vol_arg[key[4:]] = params[key] vol_arg['lazy_refcounts'] = lazy_refcounts pool_type = ['dir', 'disk', 'fs', 'logical', 'netfs', 'iscsi', 'scsi'] if src_pool_type not in pool_type: raise error.TestNAError("pool type %s not in supported type list: %s" % (src_pool_type, pool_type)) if not libvirt_version.version_compare(1, 0, 0): if "--prealloc-metadata" in extra_option: raise error.TestNAError("metadata preallocation not supported in" + " current libvirt version.") try: # Create the src pool src_pool_name = "virt-%s-pool" % src_pool_type pvt = utlv.PoolVolumeTest(test, params) pvt.pre_pool(src_pool_name, src_pool_type, src_pool_target, src_emulated_image, image_size="2G", pre_disk_vol=["1M"]) # Print current pools for debugging logging.debug("Current pools:%s", libvirt_storage.StoragePool().list_pools()) # Set volume xml file volxml = libvirt_xml.VolXML() newvol = volxml.new_vol(**vol_arg) vol_xml = newvol['xml'] # Run virsh_vol_create to create vol logging.debug("create volume from xml: %s" % newvol.xmltreefile) cmd_result = virsh.vol_create(src_pool_name, vol_xml, extra_option, ignore_status=True, debug=True) status = cmd_result.exit_status # Check result if not status_error: if not status: src_pv = libvirt_storage.PoolVolume(src_pool_name) src_volumes = src_pv.list_volumes().keys() logging.debug("Current volumes in %s: %s", src_pool_name, src_volumes) if vol_name not in src_volumes: raise error.TestFail( "Can't find volume: %s from pool: %s" % (vol_name, src_pool_name)) # check format in volume xml post_xml = volxml.new_from_vol_dumpxml(vol_name, src_pool_name) logging.debug("the created volume xml is: %s" % post_xml.xmltreefile) if 'format' in post_xml.keys(): if post_xml.format != vol_format: raise error.TestFail( "Volume format %s is not expected" % vol_format + " as defined.") else: # Skip the format not supported by qemu-img error if vol_format: fmt_err = "Unknown file format '%s'" % vol_format fmt_err1 = "Formatting or formatting option not " fmt_err1 += "supported for file format '%s'" % vol_format fmt_err2 = "Driver '%s' does not support " % vol_format fmt_err2 += "image creation" if "qemu-img" in cmd_result.stderr: er = cmd_result.stderr if fmt_err in er or fmt_err1 in er or fmt_err2 in er: err_msg = "Volume format '%s' is not" % vol_format err_msg += " supported by qemu-img." raise error.TestNAError(err_msg) else: raise error.TestFail("Run failed with right command.") else: raise error.TestFail("Run failed with right command.") else: if status: logging.debug("Expect error: %s", cmd_result.stderr) else: raise error.TestFail("Expect fail, but run successfully!") finally: # Cleanup try: pvt.cleanup_pool(src_pool_name, src_pool_type, src_pool_target, src_emulated_image) except error.TestFail, detail: logging.error(str(detail))
def run(test, params, env): """ Test virsh vol-create command to cover the following matrix: pool_type = [dir, fs, netfs] volume_format = [raw, bochs, cloop, cow, dmg, iso, qcow, qcow2, qed, vmdk, vpc] pool_type = [disk] volume_format = [none, linux, fat16, fat32, linux-swap, linux-lvm, linux-raid, extended] pool_type = [logical] volume_format = [none] pool_type = [iscsi, scsi] Not supported with format type TODO: pool_type = [rbd, glusterfs] Reference: http://www.libvirt.org/storage.html """ src_pool_type = params.get("src_pool_type") src_pool_target = params.get("src_pool_target") src_pool_format = params.get("src_pool_format", "") pool_vol_num = int(params.get("src_pool_vol_num", '1')) src_emulated_image = params.get("src_emulated_image") extra_option = params.get("extra_option", "") prefix_vol_name = params.get("vol_name", "vol_create_test") vol_format = params.get("vol_format", "raw") vol_capacity = params.get("vol_capacity", 1048576) vol_allocation = params.get("vol_allocation", 1048576) image_size = params.get("emulate_image_size", "1G") lazy_refcounts = "yes" == params.get("lazy_refcounts") status_error = "yes" == params.get("status_error", "no") by_xml = "yes" == params.get("create_vol_by_xml", "yes") incomplete_target = "yes" == params.get("incomplete_target", "no") if not libvirt_version.version_compare(1, 0, 0): if "--prealloc-metadata" in extra_option: raise error.TestNAError("metadata preallocation not supported in" " current libvirt version.") if incomplete_target: raise error.TestNAError("It does not support generate target " "path in thi libvirt version.") pool_type = ['dir', 'disk', 'fs', 'logical', 'netfs', 'iscsi', 'scsi'] if src_pool_type not in pool_type: raise error.TestNAError("pool type %s not in supported type list: %s" % (src_pool_type, pool_type)) # libvirt acl polkit related params if not libvirt_version.version_compare(1, 1, 1): if params.get('setup_libvirt_polkit') == 'yes': raise error.TestNAError("API acl test not supported in current" " libvirt version.") uri = params.get("virsh_uri") unprivileged_user = params.get('unprivileged_user') if unprivileged_user: if unprivileged_user.count('EXAMPLE'): unprivileged_user = '******' # Stop multipathd to avoid start pool fail(For fs like pool, the new add # disk may in use by device-mapper, so start pool will report disk already # mounted error). multipathd = service.Factory.create_service("multipathd") multipathd_status = multipathd.status() if multipathd_status: multipathd.stop() # Set volume xml attribute dictionary, extract all params start with 'vol_' # which are for setting volume xml, except 'lazy_refcounts'. vol_arg = {} for key in params.keys(): if key.startswith('vol_'): if key[4:] in ['capacity', 'allocation', 'owner', 'group']: vol_arg[key[4:]] = int(params[key]) else: vol_arg[key[4:]] = params[key] vol_arg['lazy_refcounts'] = lazy_refcounts def post_process_vol(ori_vol_path): """ Create or disactive a volume without libvirt :param ori_vol_path: Full path of an original volume :retur: Volume name for checking """ process_vol_name = params.get("process_vol_name", "process_vol") process_vol_options = params.get("process_vol_options", "") process_vol_capacity = params.get("process_vol_capacity", vol_capacity) process_vol_cmd = "" unsupport_err = "Unsupport do '%s %s' in this test" % ( process_vol_by, process_vol_type) if process_vol_by == "lvcreate": process_vol_cmd = "lvcreate -L %s " % process_vol_capacity if process_vol_type == "thin": if not process_vol_options: process_vol_options = "-T " process_vol_cmd += "%s " % process_vol_options processthin_pool_name = params.get("processthin_pool_name", "thinpool") processthin_vol_name = params.get("processthin_vol_name", "thinvol") process_vol_capacity = params.get("process_vol_capacity", "1G") os.path.dirname(ori_vol_path) process_vol_cmd += "%s/%s " % (os.path.dirname(ori_vol_path), processthin_pool_name) process_vol_cmd += "-V %s " % process_vol_capacity process_vol_cmd += "-n %s " % processthin_vol_name process_vol_name = processthin_vol_name elif process_vol_type == "snapshot": if not process_vol_options: process_vol_options = "-s " process_vol_cmd += "%s " % process_vol_options process_vol_cmd += "-n %s " % process_vol_name process_vol_cmd += "%s " % (ori_vol_path) else: logging.error(unsupport_err) return elif process_vol_by == "qemu-img" and process_vol_type == "create": process_vol_cmd = "qemu-img create " process_vol_path = os.path.dirname(ori_vol_path) + "/" process_vol_path += process_vol_name process_vol_cmd += "%s " % process_vol_options process_vol_cmd += "%s " % process_vol_path process_vol_cmd += "%s " % process_vol_capacity elif process_vol_by == "lvchange" and process_vol_type == "deactivate": process_vol_cmd = "lvchange %s " % ori_vol_path if not process_vol_options: process_vol_options = "-an" process_vol_cmd += process_vol_options else: logging.error(unsupport_err) return rst = utils.run(process_vol_cmd, ignore_status=True) if rst.exit_status: if "Snapshots of snapshots are not supported" in rst.stderr: logging.debug("%s is already a snapshot volume", ori_vol_path) process_vol_name = os.path.basename(ori_vol_path) else: logging.error(rst.stderr) return return process_vol_name def check_vol(pool_name, vol_name, expect_exist=True): """ Check volume vol_name in pool pool_name """ src_volumes = src_pv.list_volumes().keys() logging.debug("Current volumes in %s: %s", pool_name, src_volumes) if expect_exist: if vol_name not in src_volumes: raise error.TestFail("Can't find volume %s in pool %s" % (vol_name, pool_name)) # check format in volume xml post_xml = volxml.new_from_vol_dumpxml(vol_name, pool_name) logging.debug("Volume %s XML: %s" % (vol_name, post_xml.xmltreefile)) if 'format' in post_xml.keys() and vol_format is not None: if post_xml.format != vol_format: raise error.TestFail("Volume format %s is not expected" % vol_format + " as defined.") else: if vol_name in src_volumes: raise error.TestFail( "Find volume %s in pool %s, but expect not" % (vol_name, pool_name)) fmt_err0 = "Unknown file format '%s'" % vol_format fmt_err1 = "Formatting or formatting option not " fmt_err1 += "supported for file format '%s'" % vol_format fmt_err2 = "Driver '%s' does not support " % vol_format fmt_err2 += "image creation" fmt_err_list = [fmt_err0, fmt_err1, fmt_err2] skip_msg = "Volume format '%s' is not supported by qemu-img" % vol_format vol_path_list = [] try: # Create the src pool src_pool_name = "virt-%s-pool" % src_pool_type pvt = utlv.PoolVolumeTest(test, params) pvt.pre_pool(src_pool_name, src_pool_type, src_pool_target, src_emulated_image, image_size=image_size, source_format=src_pool_format) src_pv = libvirt_storage.PoolVolume(src_pool_name) # Print current pools for debugging logging.debug("Current pools:%s", libvirt_storage.StoragePool().list_pools()) # Create volumes by virsh in a loop while pool_vol_num > 0: # Set volume xml file vol_name = prefix_vol_name + "_%s" % pool_vol_num pool_vol_num -= 1 if by_xml: # According to BZ#1138523, we need inpect the right name # (disk partition) for new volume if src_pool_type == "disk": vol_name = utlv.new_disk_vol_name(src_pool_name) if vol_name is None: raise error.TestError("Fail to generate volume name") vol_arg['name'] = vol_name volxml = libvirt_xml.VolXML() newvol = volxml.new_vol(**vol_arg) vol_xml = newvol['xml'] if params.get('setup_libvirt_polkit') == 'yes': utils.run("chmod 666 %s" % vol_xml, ignore_status=True) # Run virsh_vol_create to create vol logging.debug("Create volume from XML: %s" % newvol.xmltreefile) cmd_result = virsh.vol_create( src_pool_name, vol_xml, extra_option, unprivileged_user=unprivileged_user, uri=uri, ignore_status=True, debug=True) else: # Run virsh_vol_create_as to create_vol cmd_result = virsh.vol_create_as( vol_name, src_pool_name, vol_capacity, vol_allocation, vol_format, unprivileged_user=unprivileged_user, uri=uri, ignore_status=True, debug=True) # Check result try: utlv.check_exit_status(cmd_result, status_error) check_vol(src_pool_name, vol_name, not status_error) if not status_error: vol_path = virsh.vol_path(vol_name, src_pool_name).stdout.strip() logging.debug("Full path of %s: %s", vol_name, vol_path) vol_path_list.append(vol_path) except error.TestFail, e: stderr = cmd_result.stderr if any(err in stderr for err in fmt_err_list): raise error.TestNAError(skip_msg) else: raise e # Post process vol by other programs process_vol_by = params.get("process_vol_by") process_vol_type = params.get("process_vol_type", "") expect_vol_exist = "yes" == params.get("expect_vol_exist", "yes") if process_vol_by and vol_path_list: process_vol = post_process_vol(vol_path_list[0]) if process_vol is not None: try: virsh.pool_refresh(src_pool_name, ignore_status=False) check_vol(src_pool_name, process_vol, expect_vol_exist) except (error.CmdError, error.TestFail), e: if process_vol_type == "thin": logging.error(e) raise error.TestNAError( "You may encounter bug BZ#1060287") else: raise e else: raise error.TestFail("Post process volume failed")
libvirt_storage.StoragePool().list_pools()) # Create volumes by virsh in a loop while pool_vol_num > 0: # Set volume xml file vol_name = prefix_vol_name + "_%s" % pool_vol_num pool_vol_num -= 1 if by_xml: # According to BZ#1138523, we need inpect the right name # (disk partition) for new volume if src_pool_type == "disk": vol_name = utlv.new_disk_vol_name(src_pool_name) if vol_name is None: raise error.TestError("Fail to generate volume name") vol_arg['name'] = vol_name volxml = libvirt_xml.VolXML() newvol = volxml.new_vol(**vol_arg) if luks_encrypted: # For luks encrypted disk, add related xml in newvol luks_encryption_params = {} luks_encryption_params.update({"format": "luks"}) luks_secret_uuid = create_luks_secret(os.path.join(src_pool_target, vol_name)) secret_uuids.append(luks_secret_uuid) luks_encryption_params.update({"secret": {"type": encryption_secret_type, "uuid": luks_secret_uuid}}) newvol.encryption = volxml.new_encryption(**luks_encryption_params) vol_xml = newvol['xml'] if params.get('setup_libvirt_polkit') == 'yes': process.run("chmod 666 %s" % vol_xml, ignore_status=True,
def run(test, params, env): """ Test virsh snapshot command when disk in all kinds of type. (1). Init the variables from params. (2). Create a image by specifice format. (3). Attach disk to vm. (4). Snapshot create. (5). Snapshot revert. (6). cleanup. """ # Init variables. vm_name = params.get("main_vm", "virt-tests-vm1") vm = env.get_vm(vm_name) image_format = params.get("snapshot_image_format", "qcow2") snapshot_del_test = "yes" == params.get("snapshot_del_test", "no") status_error = ("yes" == params.get("status_error", "no")) snapshot_from_xml = ("yes" == params.get("snapshot_from_xml", "no")) snapshot_current = ("yes" == params.get("snapshot_current", "no")) snapshot_revert_paused = ("yes" == params.get("snapshot_revert_paused", "no")) # Pool variables. snapshot_with_pool = "yes" == params.get("snapshot_with_pool", "no") pool_name = params.get("pool_name") pool_type = params.get("pool_type") pool_target = params.get("pool_target") emulated_image = params.get("emulated_image") vol_name = params.get("vol_name") vol_format = params.get("vol_format") lazy_refcounts = "yes" == params.get("lazy_refcounts") options = params.get("snapshot_options", "") # Set volume xml attribute dictionary, extract all params start with 'vol_' # which are for setting volume xml, except 'lazy_refcounts'. vol_arg = {} for key in params.keys(): if key.startswith('vol_'): if key[4:] in ['capacity', 'allocation', 'owner', 'group']: vol_arg[key[4:]] = int(params[key]) else: vol_arg[key[4:]] = params[key] vol_arg['lazy_refcounts'] = lazy_refcounts supported_pool_list = [ "dir", "fs", "netfs", "logical", "iscsi", "disk", "gluster" ] if snapshot_with_pool: if pool_type not in supported_pool_list: raise error.TestNAError("%s not in support list %s" % (pool_target, supported_pool_list)) # Do xml backup for final recovery vmxml_backup = libvirt_xml.VMXML.new_from_inactive_dumpxml(vm_name) # Some variable for xmlfile of snapshot. snapshot_memory = params.get("snapshot_memory", "internal") snapshot_disk = params.get("snapshot_disk", "internal") # Skip 'qed' cases for libvirt version greater than 1.1.0 if libvirt_version.version_compare(1, 1, 0): if vol_format == "qed": raise error.TestNAError("QED support changed, check bug: " "https://bugzilla.redhat.com/show_bug.cgi" "?id=731570") # Init snapshot_name snapshot_name = None snapshot_external_disk = [] snapshot_xml_path = None del_status = None image = None pvt = None # Get a tmp dir tmp_dir = data_dir.get_tmp_dir() snap_cfg_path = "/var/lib/libvirt/qemu/snapshot/%s/" % vm_name try: if snapshot_with_pool: # Create dst pool for create attach vol img pvt = utlv.PoolVolumeTest(test, params) pvt.pre_pool(pool_name, pool_type, pool_target, emulated_image, image_size="1G", pre_disk_vol=["20M"]) if pool_type in ["iscsi", "disk"]: # iscsi and disk pool did not support create volume in libvirt, # logical pool could use libvirt to create volume but volume # format is not supported and will be 'raw' as default. pv = libvirt_storage.PoolVolume(pool_name) vols = pv.list_volumes().keys() if vols: vol_name = vols[0] else: raise error.TestNAError("No volume in pool: %s", pool_name) else: # Set volume xml file volxml = libvirt_xml.VolXML() newvol = volxml.new_vol(**vol_arg) vol_xml = newvol['xml'] # Run virsh_vol_create to create vol logging.debug("create volume from xml: %s" % newvol.xmltreefile) cmd_result = virsh.vol_create(pool_name, vol_xml, ignore_status=True, debug=True) if cmd_result.exit_status: raise error.TestNAError("Failed to create attach volume.") cmd_result = virsh.vol_path(vol_name, pool_name, debug=True) if cmd_result.exit_status: raise error.TestNAError("Failed to get volume path from pool.") img_path = cmd_result.stdout.strip() if pool_type in ["logical", "iscsi", "disk"]: # Use qemu-img to format logical, iscsi and disk block device if vol_format != "raw": cmd = "qemu-img create -f %s %s 10M" % (vol_format, img_path) cmd_result = utils.run(cmd, ignore_status=True) if cmd_result.exit_status: raise error.TestNAError("Failed to format volume, %s" % cmd_result.stdout.strip()) extra = "--persistent --subdriver %s" % vol_format else: # Create a image. params['image_name'] = "snapshot_test" params['image_format'] = image_format params['image_size'] = "1M" image = qemu_storage.QemuImg(params, tmp_dir, "snapshot_test") img_path, _ = image.create(params) extra = "--persistent --subdriver %s" % image_format # Do the attach action. out = utils.run("qemu-img info %s" % img_path) logging.debug("The img info is:\n%s" % out.stdout.strip()) result = virsh.attach_disk(vm_name, source=img_path, target="vdf", extra=extra, debug=True) if result.exit_status: raise error.TestNAError("Failed to attach disk %s to VM." "Detail: %s." % (img_path, result.stderr)) # Create snapshot. if snapshot_from_xml: snapshot_name = "snapshot_test" lines = [ "<domainsnapshot>\n", "<name>%s</name>\n" % snapshot_name, "<description>Snapshot Test</description>\n" ] if snapshot_memory == "external": memory_external = os.path.join(tmp_dir, "snapshot_memory") snapshot_external_disk.append(memory_external) lines.append("<memory snapshot=\'%s\' file='%s'/>\n" % (snapshot_memory, memory_external)) else: lines.append("<memory snapshot='%s'/>\n" % snapshot_memory) # Add all disks into xml file. disks = vm.get_disk_devices().values() lines.append("<disks>\n") for disk in disks: lines.append("<disk name='%s' snapshot='%s'>\n" % (disk['source'], snapshot_disk)) if snapshot_disk == "external": snap_path = "%s.snap" % os.path.basename(disk['source']) disk_external = os.path.join(tmp_dir, snap_path) snapshot_external_disk.append(disk_external) lines.append("<source file='%s'/>\n" % disk_external) lines.append("</disk>\n") lines.append("</disks>\n") lines.append("</domainsnapshot>") snapshot_xml_path = "%s/snapshot_xml" % tmp_dir snapshot_xml_file = open(snapshot_xml_path, "w") snapshot_xml_file.writelines(lines) snapshot_xml_file.close() logging.debug("The xml content for snapshot create is:") with open(snapshot_xml_path, 'r') as fin: logging.debug(fin.read()) options += " --xmlfile %s " % snapshot_xml_path snapshot_result = virsh.snapshot_create(vm_name, options, debug=True) out_err = snapshot_result.stderr.strip() if snapshot_result.exit_status: if status_error: return else: if re.search( "live disk snapshot not supported with this QEMU binary", out_err): raise error.TestNAError(out_err) if libvirt_version.version_compare(1, 2, 5): # As commit d2e668e in 1.2.5, internal active snapshot # without memory state is rejected. Handle it as SKIP # for now. This could be supportted in future by bug: # https://bugzilla.redhat.com/show_bug.cgi?id=1103063 if re.search( "internal snapshot of a running VM" + " must include the memory state", out_err): raise error.TestNAError("Check Bug #1083345, %s" % out_err) raise error.TestFail( "Failed to create snapshot. Error:%s." % out_err) else: snapshot_result = virsh.snapshot_create(vm_name, options) if snapshot_result.exit_status: if status_error: return else: raise error.TestFail( "Failed to create snapshot. Error:%s." % snapshot_result.stderr.strip()) snapshot_name = re.search("\d+", snapshot_result.stdout.strip()).group(0) if snapshot_current: lines = [ "<domainsnapshot>\n", "<description>Snapshot Test</description>\n", "<state>running</state>\n", "<creationTime>%s</creationTime>" % snapshot_name, "</domainsnapshot>" ] snapshot_xml_path = "%s/snapshot_xml" % tmp_dir snapshot_xml_file = open(snapshot_xml_path, "w") snapshot_xml_file.writelines(lines) snapshot_xml_file.close() logging.debug("The xml content for snapshot create is:") with open(snapshot_xml_path, 'r') as fin: logging.debug(fin.read()) options += "--redefine %s --current" % snapshot_xml_path if snapshot_result.exit_status: raise error.TestFail("Failed to create snapshot --current." "Error:%s." % snapshot_result.stderr.strip()) if status_error: if not snapshot_del_test: raise error.TestFail("Success to create snapshot in negative" " case\nDetail: %s" % snapshot_result) # Touch a file in VM. if vm.is_dead(): vm.start() session = vm.wait_for_login() # Init a unique name for tmp_file. tmp_file = tempfile.NamedTemporaryFile(prefix=("snapshot_test_"), dir="/tmp") tmp_file_path = tmp_file.name tmp_file.close() echo_cmd = "echo SNAPSHOT_DISK_TEST >> %s" % tmp_file_path status, output = session.cmd_status_output(echo_cmd) logging.debug("The echo output in domain is: '%s'", output) if status: raise error.TestFail("'%s' run failed with '%s'" % (tmp_file_path, output)) status, output = session.cmd_status_output("cat %s" % tmp_file_path) logging.debug("File created with content: '%s'", output) session.close() # Destroy vm for snapshot revert. if not libvirt_version.version_compare(1, 2, 3): virsh.destroy(vm_name) # Revert snapshot. revert_options = "" if snapshot_revert_paused: revert_options += " --paused" revert_result = virsh.snapshot_revert(vm_name, snapshot_name, revert_options, debug=True) if revert_result.exit_status: # As commit d410e6f for libvirt 1.2.3, attempts to revert external # snapshots will FAIL with an error "revert to external snapshot # not supported yet". Thus, let's check for that and handle as a # SKIP for now. Check bug: # https://bugzilla.redhat.com/show_bug.cgi?id=1071264 if libvirt_version.version_compare(1, 2, 3): if re.search("revert to external snapshot not supported yet", revert_result.stderr): raise error.TestNAError(revert_result.stderr.strip()) else: raise error.TestFail("Revert snapshot failed. %s" % revert_result.stderr.strip()) if vm.is_dead(): raise error.TestFail("Revert snapshot failed.") if snapshot_revert_paused: if vm.is_paused(): vm.resume() else: raise error.TestFail("Revert command successed, but VM is not " "paused after reverting with --paused" " option.") # login vm. session = vm.wait_for_login() # Check the result of revert. status, output = session.cmd_status_output("cat %s" % tmp_file_path) logging.debug("After revert cat file output='%s'", output) if not status: raise error.TestFail("Tmp file exists, revert failed.") # Close the session. session.close() # Test delete snapshot without "--metadata", delete external disk # snapshot will fail for now. # Only do this when snapshot creat succeed which filtered in cfg file. if snapshot_del_test: if snapshot_name: del_result = virsh.snapshot_delete(vm_name, snapshot_name, debug=True, ignore_status=True) del_status = del_result.exit_status snap_xml_path = snap_cfg_path + "%s.xml" % snapshot_name if del_status: if not status_error: raise error.TestFail("Failed to delete snapshot.") else: if not os.path.exists(snap_xml_path): raise error.TestFail( "Snapshot xml file %s missing" % snap_xml_path) else: if status_error: err_msg = "Snapshot delete succeed but expect fail." raise error.TestFail(err_msg) else: if os.path.exists(snap_xml_path): raise error.TestFail("Snapshot xml file %s still" % snap_xml_path + " exist") finally: virsh.detach_disk(vm_name, target="vdf", extra="--persistent") if image: image.remove() if del_status and snapshot_name: virsh.snapshot_delete(vm_name, snapshot_name, "--metadata") for disk in snapshot_external_disk: if os.path.exists(disk): os.remove(disk) vmxml_backup.sync("--snapshots-metadata") if snapshot_xml_path: if os.path.exists(snapshot_xml_path): os.unlink(snapshot_xml_path) if pvt: try: pvt.cleanup_pool(pool_name, pool_type, pool_target, emulated_image) except error.TestFail, detail: logging.error(str(detail))