Exemple #1
0
def createVolume(parent, parent_format, volume, size, format, prealloc):
    """
     --- Create new volume.
        'parent' - backing volume name
        'parent_format' - backing volume format
        'volume' - new volume name
        'format' - volume format [ 'COW' or 'RAW' ]
        'size' - in sectors, always multiple of the grain size (64KB)
        'preallocate' - flag PREALLOCATED_VOL/SPARSE_VOL,
                        defines actual storage device type.
                        PREALLOCATED_VOL = preallocated storage using
                        non-sparse format (+ DD for file, use raw LV for SAN)

    # SAN

      Prealloc/RAW = Normal LV (if snapshot => create copy of LV)
      Sparse/RAW = if snapshot create LVM snapshot
                (in the future, use storage backend thin provisioning),
                else create Normal LV <== Not supported
      Prealloc/COW = build qcow2 image within a preallocated space -
                     used only for COPY
      Sparse/COW = QCOW2 over LV

    # File

      Prealloc/RAW = Normal file + DD (implicit pre-zero)
      Sparse/RAW = Normal file (touch)
      Prealloc/COW = QCOW2 + DD <== Not supported
      Sparse/COW = QCOW2

    """
    # TODO: accept size only in bytes and convert before call to qemu-img
    cmd = [constants.EXT_QEMUIMG, "create", "-f", fmt2str(format)]
    cwd = None
    if format == COW_FORMAT and parent:
        # cmd += ["-b", parent, volume]
        # cwd = os.path.split(os.path.split(volume)[0])[0]

        # Temporary fix for qemu-img creation problem
        cmd += ["-F", parent_format, "-b", os.path.join("..", parent), volume]
        cwd = os.path.split(volume)[0]
    else:
        size = int(size)
        if size < 1:
            raise se.createVolumeSizeError()

        # qemu-img expects size to be in kilobytes by default,
        # can also accept size in M or G with appropriate suffix
        # +1 is so that odd numbers will round upwards.
        cmd += [volume, "%uK" % ((size + 1) / 2)]

    (rc, out, err) = misc.execCmd(cmd, sudo=False, cwd=cwd)
    if rc:
        raise se.VolumeCreationError(out)
    return True
Exemple #2
0
    def create(cls,
               repoPath,
               sdUUID,
               imgUUID,
               size,
               volFormat,
               preallocate,
               diskType,
               volUUID,
               desc,
               srcImgUUID,
               srcVolUUID,
               initialSize=None):
        """
        Create a new volume with given size or snapshot
            'size' - in sectors
            'volFormat' - volume format COW / RAW
            'preallocate' - Preallocate / Sparse
            'diskType' - enum (API.Image.DiskTypes)
            'srcImgUUID' - source image UUID
            'srcVolUUID' - source volume UUID
            'initialSize' - initial volume size in sectors,
                            in case of thin provisioning
        """
        dom = sdCache.produce(sdUUID)
        dom.validateCreateVolumeParams(volFormat,
                                       srcVolUUID,
                                       preallocate=preallocate)

        imgPath = image.Image(repoPath).create(sdUUID, imgUUID)

        volPath = os.path.join(imgPath, volUUID)
        volParent = None
        volType = type2name(LEAF_VOL)

        # Get the specific class name and class module to be used in the
        # Recovery tasks.
        clsModule, clsName = cls._getModuleAndClass()

        try:
            if srcVolUUID != BLANK_UUID:
                # When the srcImgUUID isn't specified we assume it's the same
                # as the imgUUID
                if srcImgUUID == BLANK_UUID:
                    srcImgUUID = imgUUID

                volParent = cls(repoPath, sdUUID, srcImgUUID, srcVolUUID)

                if not volParent.isLegal():
                    raise se.createIllegalVolumeSnapshotError(
                        volParent.volUUID)

                if imgUUID != srcImgUUID:
                    volParent.share(imgPath)
                    volParent = cls(repoPath, sdUUID, imgUUID, srcVolUUID)

                # Override the size with the size of the parent
                size = volParent.getSize()

        except se.StorageException:
            cls.log.error("Unexpected error", exc_info=True)
            raise
        except Exception as e:
            cls.log.error("Unexpected error", exc_info=True)
            raise se.VolumeCannotGetParent(
                "Couldn't get parent %s for volume %s: %s" %
                (srcVolUUID, volUUID, e))

        try:
            cls.log.info("Creating volume %s", volUUID)

            # Rollback sentinel to mark the start of the task
            vars.task.pushRecovery(
                task.Recovery(task.ROLLBACK_SENTINEL, clsModule, clsName,
                              "startCreateVolumeRollback",
                              [sdUUID, imgUUID, volUUID]))

            # Create volume rollback
            vars.task.pushRecovery(
                task.Recovery("Halfbaked volume rollback", clsModule, clsName,
                              "halfbakedVolumeRollback",
                              [sdUUID, volUUID, volPath]))

            # Specific volume creation (block, file, etc...)
            try:
                metaId = cls._create(dom,
                                     imgUUID,
                                     volUUID,
                                     size,
                                     volFormat,
                                     preallocate,
                                     volParent,
                                     srcImgUUID,
                                     srcVolUUID,
                                     volPath,
                                     initialSize=initialSize)
            except (se.VolumeAlreadyExists, se.CannotCreateLogicalVolume,
                    se.VolumeCreationError, se.InvalidParameterException) as e:
                cls.log.error("Failed to create volume %s: %s", volPath, e)
                vars.task.popRecovery()
                raise
            # When the volume format is raw what the guest sees is the apparent
            # size of the file/device therefore if the requested size doesn't
            # match the apparent size (eg: physical extent granularity in LVM)
            # we need to update the size value so that the metadata reflects
            # the correct state.
            if volFormat == RAW_FORMAT:
                apparentSize = int(dom.getVSize(imgUUID, volUUID) / BLOCK_SIZE)
                if apparentSize < size:
                    cls.log.error(
                        "The volume %s apparent size %s is smaller "
                        "than the requested size %s", volUUID, apparentSize,
                        size)
                    raise se.VolumeCreationError()
                if apparentSize > size:
                    cls.log.info(
                        "The requested size for volume %s doesn't "
                        "match the granularity on domain %s, "
                        "updating the volume size from %s to %s", volUUID,
                        sdUUID, size, apparentSize)
                    size = apparentSize

            vars.task.pushRecovery(
                task.Recovery("Create volume metadata rollback", clsModule,
                              clsName, "createVolumeMetadataRollback",
                              map(str, metaId)))

            cls.newMetadata(metaId, sdUUID, imgUUID, srcVolUUID, size,
                            type2name(volFormat), type2name(preallocate),
                            volType, diskType, desc, LEGAL_VOL)

            if dom.hasVolumeLeases():
                cls.newVolumeLease(metaId, sdUUID, volUUID)

        except se.StorageException:
            cls.log.error("Unexpected error", exc_info=True)
            raise
        except Exception as e:
            cls.log.error("Unexpected error", exc_info=True)
            raise se.VolumeCreationError("Volume creation %s failed: %s" %
                                         (volUUID, e))

        # Remove the rollback for the halfbaked volume
        vars.task.replaceRecoveries(
            task.Recovery("Create volume rollback", clsModule, clsName,
                          "createVolumeRollback",
                          [repoPath, sdUUID, imgUUID, volUUID, imgPath]))

        return volUUID
Exemple #3
0
                # should stay %d and size should be int(size)
                volsize = "%s" % (size / 2 / 1024)
            vars.task.pushRecovery(
                task.Recovery("halfbaked volume rollback", "blockVolume",
                              "BlockVolume", "halfbakedVolumeRollback",
                              [sdUUID, volUUID, vol_path]))
            lvm.createLV(sdUUID, volUUID, volsize, activate=True)
            if os.path.exists(vol_path):
                os.unlink(vol_path)
            os.symlink(lvm.lvPath(sdUUID, volUUID), vol_path)
        except se.StorageException:
            cls.log.error("Unexpected error", exc_info=True)
            raise
        except Exception, e:
            cls.log.error("Unexpected error", exc_info=True)
            raise se.VolumeCreationError(
                "blockVolume create/link lv %s failed: %s" % (volUUID, str(e)))

        # By definition volume is now a leaf and should be writeable.
        # Default permission for lvcreate is read and write. No need to set permission.

        try:
            cls.log.info(
                "blockVolume: create: volUUID %s srcImg %s srvVol %s" %
                (volUUID, srcImgUUID, srcVolUUID))
            if not pvol:
                cls.log.info(
                    "Request to create %s volume %s with size = %s sectors",
                    volume.type2name(volFormat), vol_path, size)
                # Create 'raw' volume via qemu-img actually redundant
                if volFormat == volume.COW_FORMAT:
                    volume.createVolume(None, None, vol_path, size, volFormat,