def syncData(self, sdUUID, imgUUID, dstSdUUID, syncType): srcChain = self.getChain(sdUUID, imgUUID) log_str = logutils.volume_chain_to_str(vol.volUUID for vol in srcChain) self.log.info("Source chain=%s ", log_str) dstChain = self.getChain(dstSdUUID, imgUUID) log_str = logutils.volume_chain_to_str(vol.volUUID for vol in dstChain) self.log.info("Dest chain=%s ", log_str) if syncType == SYNC_VOLUMES_INTERNAL: try: # Removing the leaf volumes del srcChain[-1], dstChain[-1] except IndexError: raise se.ImageIsNotLegalChain() elif syncType == SYNC_VOLUMES_LEAF: try: # Removing all the internal volumes del srcChain[:-1], dstChain[:-1] except IndexError: raise se.ImageIsNotLegalChain() elif syncType != SYNC_VOLUMES_ALL: raise se.MiscNotImplementedException() if len(srcChain) != len(dstChain): raise se.DestImageActionError(imgUUID, dstSdUUID) # Checking the volume uuids (after removing the leaves to allow # different uuids for the current top layer, see previous check). for i, v in enumerate(srcChain): if v.volUUID != dstChain[i].volUUID: raise se.DestImageActionError(imgUUID, dstSdUUID) dstDom = sdCache.produce(dstSdUUID) self._interImagesCopy(dstDom, sdUUID, imgUUID, { 'srcChain': srcChain, 'dstChain': dstChain }) self._finalizeDestinationImage(dstDom, imgUUID, { 'srcChain': srcChain, 'dstChain': dstChain }, False)
def _finalizeDestinationImage(self, destDom, imgUUID, chains, force): for srcVol in chains['srcChain']: try: dstVol = destDom.produceVolume(imgUUID=imgUUID, volUUID=srcVol.volUUID) # In case of copying template, we should set the destination # volume as SHARED (after copy because otherwise prepare as RW # would fail) if srcVol.isShared(): dstVol.setShared() elif srcVol.isInternal(): dstVol.setInternal() except se.StorageException: self.log.error("Unexpected error", exc_info=True) raise except Exception as e: self.log.error("Unexpected error", exc_info=True) raise se.DestImageActionError(imgUUID, destDom.sdUUID, str(e))
def _createTargetImage(self, destDom, srcSdUUID, imgUUID): # Before actual data copying we need perform several operation # such as: create all volumes, create fake template if needed, ... try: # Find all volumes of source image srcChain = self.getChain(srcSdUUID, imgUUID) log_str = logutils.volume_chain_to_str(vol.volUUID for vol in srcChain) self.log.info("Source chain=%s ", log_str) except se.StorageException: self.log.error("Unexpected error", exc_info=True) raise except Exception as e: self.log.error("Unexpected error", exc_info=True) raise se.SourceImageActionError(imgUUID, srcSdUUID, str(e)) fakeTemplate = False pimg = sc.BLANK_UUID # standalone chain # check if the chain is build above a template, or it is a standalone pvol = srcChain[0].getParentVolume() if pvol: # find out parent volume parameters volParams = pvol.getVolumeParams() pimg = volParams['imgUUID'] # pimg == template image if destDom.isBackup(): # FIXME: This workaround help as copy VM to the backup domain # without its template. We will create fake template # for future VM creation and mark it as FAKE volume. # This situation is relevant for backup domain only. fakeTemplate = True @contextmanager def justLogIt(img): self.log.debug("You don't really need lock parent of image %s", img) yield dstImageResourcesNamespace = rm.getNamespace(sc.IMAGE_NAMESPACE, destDom.sdUUID) # In destination domain we need to lock image's template if exists with rm.acquireResource(dstImageResourcesNamespace, pimg, rm.SHARED) \ if pimg != sc.BLANK_UUID else justLogIt(imgUUID): if fakeTemplate: self.createFakeTemplate(destDom.sdUUID, volParams) dstChain = [] for srcVol in srcChain: # Create the dst volume try: # find out src volume parameters volParams = srcVol.getVolumeParams() # To avoid prezeroing preallocated volumes on NFS domains # we create the target as a sparse volume (since it will be # soon filled with the data coming from the copy) and then # we change its metadata back to the original value. if (destDom.supportsSparseness or volParams['volFormat'] != sc.RAW_FORMAT): tmpVolPreallocation = sc.SPARSE_VOL else: tmpVolPreallocation = sc.PREALLOCATED_VOL destDom.createVolume(imgUUID=imgUUID, capacity=volParams['capacity'], volFormat=volParams['volFormat'], preallocate=tmpVolPreallocation, diskType=volParams['disktype'], volUUID=srcVol.volUUID, desc=volParams['descr'], srcImgUUID=pimg, srcVolUUID=volParams['parent']) dstVol = destDom.produceVolume(imgUUID=imgUUID, volUUID=srcVol.volUUID) # Extend volume (for LV only) size to the actual size dstVol.extend(volParams['apparentsize']) # Change destination volume metadata to preallocated in # case we've used a sparse volume to accelerate the # volume creation if volParams['prealloc'] == sc.PREALLOCATED_VOL \ and tmpVolPreallocation != sc.PREALLOCATED_VOL: dstVol.setType(sc.PREALLOCATED_VOL) dstChain.append(dstVol) except se.StorageException: self.log.error("Unexpected error", exc_info=True) raise except Exception as e: self.log.error("Unexpected error", exc_info=True) raise se.DestImageActionError(imgUUID, destDom.sdUUID, str(e)) # only base may have a different parent image pimg = imgUUID return {'srcChain': srcChain, 'dstChain': dstChain}