Exemplo n.º 1
0
Arquivo: sd.py Projeto: benipeled/vdsm
    def _makeDomainLock(self, domVersion=None):
        if not domVersion:
            domVersion = self.getVersion()

        try:
            lockClass = self._domainLockTable[domVersion]
        except KeyError:
            raise se.UnsupportedDomainVersion(domVersion)

        # Note: lease and leaseParams are needed only for legacy locks
        # supporting only single lease, and ignored by modern lock managers
        # like sanlock. On the contrary, kwargs are not needed by legacy locks
        # and are used by modern locks like sanlock.

        leaseParams = (
            DEFAULT_LEASE_PARAMS[DMDK_LOCK_RENEWAL_INTERVAL_SEC],
            DEFAULT_LEASE_PARAMS[DMDK_LEASE_TIME_SEC],
            DEFAULT_LEASE_PARAMS[DMDK_LEASE_RETRIES],
            DEFAULT_LEASE_PARAMS[DMDK_IO_OP_TIMEOUT_SEC],
        )

        kwargs = {
            "alignment": self._alignment,
            "block_size": self._block_size,
        }

        return lockClass(self.sdUUID, self.getIdsFilePath(),
                         self.getDomainLease(), *leaseParams, **kwargs)
Exemplo n.º 2
0
    def _makeDomainLock(self, domVersion=None):
        if not domVersion:
            domVersion = self.getVersion()

        leaseParams = (
            DEFAULT_LEASE_PARAMS[DMDK_LOCK_RENEWAL_INTERVAL_SEC],
            DEFAULT_LEASE_PARAMS[DMDK_LEASE_TIME_SEC],
            DEFAULT_LEASE_PARAMS[DMDK_LEASE_RETRIES],
            DEFAULT_LEASE_PARAMS[DMDK_IO_OP_TIMEOUT_SEC],
        )

        try:
            lockClass = self._domainLockTable[domVersion]
        except KeyError:
            raise se.UnsupportedDomainVersion(domVersion)

        return lockClass(self.sdUUID, self.getIdsFilePath(),
                         self.getLeasesFilePath(), *leaseParams)
Exemplo n.º 3
0
    def _makeDomainLock(self, domVersion=None):
        if not domVersion:
            domVersion = self.getVersion()

        leaseParams = (
            DEFAULT_LEASE_PARAMS[DMDK_LOCK_RENEWAL_INTERVAL_SEC],
            DEFAULT_LEASE_PARAMS[DMDK_LEASE_TIME_SEC],
            DEFAULT_LEASE_PARAMS[DMDK_LEASE_RETRIES],
            DEFAULT_LEASE_PARAMS[DMDK_IO_OP_TIMEOUT_SEC],
        )

        try:
            lockClass = self._domainLockTable[domVersion]
        except KeyError:
            raise se.UnsupportedDomainVersion(domVersion)

        # Note: lease and leaseParams are needed only for legacy locks
        # supporting only single lease, and ignored by modern lock managers
        # like sanlock.

        return lockClass(self.sdUUID, self.getIdsFilePath(),
                         self.getDomainLease(), *leaseParams)
Exemplo n.º 4
0
def v3DomainConverter(repoPath, hostId, domain, isMsd):
    targetVersion = 3
    currentVersion = domain.getVersion()

    log.debug("Starting conversion for domain %s from version %s "
              "to version %s", domain.sdUUID, currentVersion, targetVersion)

    # For block domains if we're upgrading from version 0 we need to first
    # upgrade to version 2 and then proceed to upgrade to version 3.
    if domain.getStorageType() in sd.BLOCK_DOMAIN_TYPES:
        if currentVersion != 2:
            log.debug("Unsupported conversion from version %s to version %s",
                      currentVersion, targetVersion)
            raise se.UnsupportedDomainVersion(currentVersion)

    if domain.getStorageType() in sd.FILE_DOMAIN_TYPES:
        log.debug("Setting permissions for domain %s", domain.sdUUID)
        domain.setMetadataPermissions()

    log.debug("Initializing the new cluster lock for domain %s", domain.sdUUID)
    newClusterLock = domain._makeClusterLock(targetVersion)
    newClusterLock.initLock(domain.getClusterLease())

    log.debug("Acquiring the host id %s for domain %s", hostId, domain.sdUUID)
    newClusterLock.acquireHostId(hostId, wait=True)

    def v3UpgradeVolumePermissions(vol):
        log.debug("Changing permissions (read-write) for the "
                  "volume %s", vol.volUUID)
        # Using the internal call to skip the domain V3 validation,
        # see volume.setrw for more details.
        vol._setrw(True)

    def v3ReallocateMetadataSlot(domain, allVolumes):
        if not domain.getStorageType() in sd.BLOCK_DOMAIN_TYPES:
            log.debug("The metadata reallocation check is not needed for "
                      "domain %s", domain.sdUUID)
            return

        leasesSize = domain.getLeasesFileSize() // MiB
        metaMaxSlot = leasesSize - blockSD.RESERVED_LEASES - 1

        log.debug("Starting metadata reallocation check for domain %s with "
                  "metaMaxSlot %s (leases volume size %s)", domain.sdUUID,
                  metaMaxSlot, leasesSize)

        # Updating the volumes one by one, doesn't require activation
        for volUUID, (imgUUIDs, parentUUID) in six.iteritems(allVolumes):
            # The first imgUUID is the imgUUID of the template or the only
            # imgUUID where the volUUID appears.
            vol = domain.produceVolume(imgUUIDs[0], volUUID)
            metaSlot = vol.getMetaSlot()

            if metaSlot < metaMaxSlot:
                continue

            log.debug("Reallocating metadata slot %s for volume %s",
                      metaSlot, vol.volUUID)
            metaContent = vol.getMetadata()

            with domain.acquireVolumeMetadataSlot(vol.volUUID) as newMetaSlot:
                if newMetaSlot > metaMaxSlot:
                    raise se.NoSpaceLeftOnDomain(domain.sdUUID)

                log.debug("Copying metadata for volume %s to the new slot %s",
                          vol.volUUID, newMetaSlot)
                vol.createMetadata((domain.sdUUID, newMetaSlot), metaContent)

                log.debug("Switching the metadata slot for volume %s to %s",
                          vol.volUUID, newMetaSlot)
                vol.changeVolumeTag(sc.TAG_PREFIX_MD, str(newMetaSlot))

    try:
        if isMsd:
            log.debug("Acquiring the cluster lock for domain %s with "
                      "host id: %s", domain.sdUUID, hostId)
            newClusterLock.acquire(hostId, domain.getClusterLease())

        allVolumes = domain.getAllVolumes()
        allImages = {}  # {images: parent_image}

        # Few vdsm releases (4.9 prior 496c0c3, BZ#732980) generated metadata
        # offsets higher than 1947 (LEASES_SIZE - RESERVED_LEASES - 1).
        # This function reallocates such slots to free ones in order to use the
        # same offsets for the volume resource leases.
        v3ReallocateMetadataSlot(domain, allVolumes)

        # Updating the volumes one by one, doesn't require activation
        for volUUID, (imgUUIDs, parentUUID) in six.iteritems(allVolumes):
            log.debug("Converting volume: %s", volUUID)

            # Maintaining a dict of {images: parent_image}
            allImages.update((i, None) for i in imgUUIDs)

            # The first imgUUID is the imgUUID of the template or the
            # only imgUUID where the volUUID appears.
            vol = domain.produceVolume(imgUUIDs[0], volUUID)
            v3UpgradeVolumePermissions(vol)

            log.debug("Creating the volume lease for %s", volUUID)
            metaId = vol.getMetadataId()
            vol.newVolumeLease(metaId, domain.sdUUID, volUUID)

            # If this volume is used as a template let's update the other
            # volume's permissions and share the volume lease (at the moment
            # of this writing this is strictly needed only on file domains).
            for imgUUID in imgUUIDs[1:]:
                allImages[imgUUID] = imgUUIDs[0]
                dstVol = domain.produceVolume(imgUUID, volUUID)

                v3UpgradeVolumePermissions(dstVol)

                # Sharing the original template volume lease file with the
                # same volume in the other images.
                vol._shareLease(dstVol.imagePath)

        # Updating the volumes to fix BZ#811880, here the activation is
        # required and to be more effective we do it by image (one shot).
        for imgUUID in allImages:
            log.debug("Converting image: %s", imgUUID)

            # XXX: The only reason to prepare the image is to verify the volume
            # virtual size configured in the qcow2 header (BZ#811880).
            # The activation and deactivation of the LVs might lead to a race
            # with the creation or destruction of a VM on the SPM.
            #
            # The analyzed scenarios are:
            #  1. A VM is currently running on the image we are preparing.
            #     This is safe because the prepare is superfluous and the
            #     teardown is going to fail (the LVs are in use by the VM)
            #  2. A VM using this image is started after the prepare.
            #     This is safe because the prepare issued by the VM is
            #     superfluous and our teardown is going to fail (the LVs are
            #     in use by the VM).
            #  3. A VM using this image is started and the teardown is
            #     executed before that the actual QEMU process is started.
            #     This is safe because the VM is going to fail (the engine
            #     should retry later) but there is no risk of corruption.
            #  4. A VM using this image is destroyed after the prepare and
            #     before reading the image size.
            #     This is safe because the upgrade process will fail (unable
            #     to read the image virtual size) and it can be restarted
            #     later.
            imgVolumes = sd.getVolsOfImage(allVolumes, imgUUID).keys()
            try:
                try:
                    domain.activateVolumes(imgUUID, imgVolumes)
                except (OSError, se.CannotActivateLogicalVolumes):
                    log.error("Image %s can't be activated.",
                              imgUUID, exc_info=True)

                for volUUID in imgVolumes:
                    try:
                        vol = domain.produceVolume(imgUUID, volUUID)
                        _v3_reset_meta_volsize(vol)  # BZ#811880
                    except cmdutils.Error:
                        log.error("It is not possible to read the volume %s "
                                  "using qemu-img, the content looks damaged",
                                  volUUID, exc_info=True)

            except se.VolumeDoesNotExist:
                log.error("It is not possible to prepare the image %s, the "
                          "volume chain looks damaged", imgUUID,
                          exc_info=True)

            except se.MetaDataKeyNotFoundError:
                log.error("It is not possible to prepare the image %s, the "
                          "volume metadata looks damaged", imgUUID,
                          exc_info=True)

            finally:
                try:
                    domain.deactivateImage(imgUUID)
                except se.CannotDeactivateLogicalVolume:
                    log.warning("Unable to teardown the image %s, this error "
                                "is not critical since the volume might be in"
                                " use", imgUUID, exc_info=True)

        log.debug("Finalizing the storage domain upgrade from version %s to "
                  "version %s for domain %s", currentVersion, targetVersion,
                  domain.sdUUID)
        domain.setMetaParam(sd.DMDK_VERSION, targetVersion)

    except:
        if isMsd:
            try:
                log.error("Releasing the cluster lock for domain %s with "
                          "host id: %s", domain.sdUUID, hostId)
                newClusterLock.release(domain.getClusterLease())
            except:
                log.error("Unable to release the cluster lock for domain "
                          "%s with host id: %s", domain.sdUUID, hostId,
                          exc_info=True)

        try:
            log.error("Releasing the host id %s for domain %s", hostId,
                      domain.sdUUID)
            newClusterLock.releaseHostId(hostId, wait=True, unused=True)
        except:
            log.error("Unable to release the host id %s for domain %s",
                      hostId, domain.sdUUID, exc_info=True)

        raise

    # Releasing the old cluster lock (safelease). This lock was acquired
    # by the regular startSpm flow and now must be replaced by the new one
    # (sanlock). Since we are already at the end of the process (no way to
    # safely rollback to version 0 or 2) we should ignore the cluster lock
    # release errors.
    if isMsd:
        try:
            domain._clusterLock.release(domain.getClusterLease())
        except:
            log.error("Unable to release the old cluster lock for domain "
                      "%s ", domain.sdUUID, exc_info=True)

    # This is not strictly required since the domain object is destroyed right
    # after the upgrade but let's not make assumptions about future behaviors
    log.debug("Switching the cluster lock for domain %s", domain.sdUUID)
    domain._clusterLock = newClusterLock
Exemplo n.º 5
0
Arquivo: sd.py Projeto: benipeled/vdsm
 def validate_version(cls, version):
     if version not in cls.supported_versions:
         raise se.UnsupportedDomainVersion(version)
Exemplo n.º 6
0
def validateDomainVersion(version):
    if version not in sc.SUPPORTED_DOMAIN_VERSIONS:
        raise se.UnsupportedDomainVersion(version)