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)
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)
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)
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
def validate_version(cls, version): if version not in cls.supported_versions: raise se.UnsupportedDomainVersion(version)
def validateDomainVersion(version): if version not in sc.SUPPORTED_DOMAIN_VERSIONS: raise se.UnsupportedDomainVersion(version)