/** The following method will create a Shareable DiskImage with a specified format */ private DiskImage createShareableDisk(VolumeFormat volumeFormat) { DiskImage disk = createDiskImage(); disk.setvolumeFormat(volumeFormat); disk.setShareable(true); disk.setDiskInterface(DiskInterface.VirtIO); return disk; }
/** * This method is used for storage allocation validations, where the disks are the template's, * which could have another volume type/format than the target disk volume type/format, which is * not yet created. "Real" override for these values is done in CreateSnapshotCommand, when * creating the new DiskImages. */ public static List<DiskImage> getDisksDummiesForStorageAllocations( Collection<DiskImage> originalDisks) { List<DiskImage> diskDummies = new ArrayList<>(originalDisks.size()); for (DiskImage diskImage : originalDisks) { DiskImage clone = DiskImage.copyOf(diskImage); clone.setVolumeType(VolumeType.Sparse); clone.setvolumeFormat(VolumeFormat.COW); diskDummies.add(clone); } return diskDummies; }
@Test public void canDoActionFailsOnNullDiskInterface() throws Exception { Guid storageId = Guid.newGuid(); DiskImage image = new DiskImage(); image.setvolumeFormat(VolumeFormat.COW); image.setVolumeType(VolumeType.Preallocated); AddDiskParameters params = new AddDiskParameters(Guid.newGuid(), image); initializeCommand(storageId, params); assertFalse(command.validateInputs()); assertTrue( command .getReturnValue() .getCanDoActionMessages() .contains("VALIDATION_DISK_INTERFACE_NOT_NULL")); }
/** CanDoAction should succeed when creating a Shareable Disk with RAW volume format */ @Test public void canDoActionShareableDiskVolumeFormatSucceeds() { DiskImage image = createShareableDiskImage(); image.setvolumeFormat(VolumeFormat.RAW); AddDiskParameters parameters = createParameters(); parameters.setDiskInfo(image); Guid storageId = Guid.newGuid(); initializeCommand(storageId, parameters); mockVm(); mockStorageDomain(storageId, Version.v3_1); mockStoragePoolIsoMap(); mockInterfaceList(); mockMaxPciSlots(); runAndAssertCanDoActionSuccess(); }
public static DiskImage cloneDiskImage( Guid storageDomainId, Guid newImageGroupId, Guid newImageGuid, DiskImage srcDiskImage, Guid diskProfileId, Guid snapshotId, DiskImage diskImageFromClient) { DiskImage clonedDiskImage = DiskImage.copyOf(srcDiskImage); clonedDiskImage.setImageId(newImageGuid); clonedDiskImage.setParentId(Guid.Empty); clonedDiskImage.setImageTemplateId(Guid.Empty); clonedDiskImage.setVmSnapshotId(snapshotId); clonedDiskImage.setId(newImageGroupId); clonedDiskImage.setLastModifiedDate(new Date()); clonedDiskImage.setvolumeFormat(srcDiskImage.getVolumeFormat()); clonedDiskImage.setVolumeType(srcDiskImage.getVolumeType()); ArrayList<Guid> storageIds = new ArrayList<>(); storageIds.add(storageDomainId); clonedDiskImage.setStorageIds(storageIds); clonedDiskImage.setDiskProfileId(diskProfileId); // If volume information was changed at client , use its volume information. // If volume information was not changed at client - use the volume information of the ancestral // image if (diskImageFromClient != null) { if (volumeInfoChanged(diskImageFromClient, srcDiskImage)) { changeVolumeInfo(clonedDiskImage, diskImageFromClient); } else { DiskImage ancestorDiskImage = getDiskImageDao().getAncestor(srcDiskImage.getImageId()); changeVolumeInfo(clonedDiskImage, ancestorDiskImage); } } else { DiskImage ancestorDiskImage = getDiskImageDao().getAncestor(srcDiskImage.getImageId()); changeVolumeInfo(clonedDiskImage, ancestorDiskImage); } return clonedDiskImage; }
/** CanDoAction should fail when creating a Shareable Disk with COW volume format */ @Test public void canDoActionShareableDiskVolumeFormatFails() { DiskImage image = createShareableDiskImage(); image.setvolumeFormat(VolumeFormat.COW); AddDiskParameters parameters = createParameters(); parameters.setDiskInfo(image); Guid storageId = Guid.newGuid(); initializeCommand(storageId, parameters); mockVm(); mockStorageDomain(storageId, Version.v3_1); mockStoragePoolIsoMap(); mockMaxPciSlots(); assertFalse(command.canDoAction()); assertTrue( command .getReturnValue() .getCanDoActionMessages() .contains(EngineMessage.SHAREABLE_DISK_IS_NOT_SUPPORTED_BY_VOLUME_FORMAT.toString())); }
@Test public void canDoActionShareableDiskOnGlusterFails() { DiskImage image = createShareableDiskImage(); image.setvolumeFormat(VolumeFormat.RAW); AddDiskParameters parameters = createParameters(); parameters.setDiskInfo(image); Guid storageId = Guid.newGuid(); initializeCommand(storageId, parameters); mockVm(); mockStorageDomain(storageId, StorageType.GLUSTERFS, Version.v3_1); mockStoragePoolIsoMap(); mockMaxPciSlots(); assertFalse(command.canDoAction()); assertTrue( command .getReturnValue() .getCanDoActionMessages() .contains( EngineMessage.ACTION_TYPE_FAILED_SHAREABLE_DISKS_NOT_SUPPORTED_ON_GLUSTER_DOMAIN .toString())); }
protected static void changeVolumeInfo(DiskImage clonedDiskImage, DiskImage diskImageFromClient) { clonedDiskImage.setvolumeFormat(diskImageFromClient.getVolumeFormat()); clonedDiskImage.setVolumeType(diskImageFromClient.getVolumeType()); }
/** * After merging the snapshots, update the image and snapshot records in the database to reflect * the changes. This handles either forward or backwards merge (detected). It will either then * remove the images, or mark them illegal (to handle the case where image deletion failed). * * @param removeImages Remove the images from the database, or if false, only mark them illegal */ private void syncDbRecords(boolean removeImages) { // If deletion failed after a backwards merge, the snapshots' images need to be swapped // as they would upon success. Instead of removing them, mark them illegal. DiskImage baseImage = getDiskImage(); DiskImage topImage = getDestinationDiskImage(); // The vdsm merge verb may decide to perform a forward or backward merge. if (topImage == null) { log.debug("No merge destination image, not updating image/snapshot association"); } else if (getParameters().getMergeStatusReturnValue().getBlockJobType() == VmBlockJobType.PULL) { // For forward merge, the volume format and type may change. topImage.setvolumeFormat(baseImage.getVolumeFormat()); topImage.setVolumeType(baseImage.getVolumeType()); topImage.setParentId(baseImage.getParentId()); topImage.setImageStatus(ImageStatus.OK); getBaseDiskDao().update(topImage); getImageDao().update(topImage.getImage()); updateDiskImageDynamic(topImage); updateVmConfigurationForImageRemoval( baseImage.getImage().getSnapshotId(), baseImage.getImageId()); } else { // For backwards merge, the prior base image now has the data associated with the newer // snapshot we want to keep. Re-associate this older image with the newer snapshot. // The base snapshot is deleted if everything went well. In case it's not deleted, we // hijack it to preserve a link to the broken image. This makes the image discoverable // so that we can retry the deletion later, yet doesn't corrupt the VM image chain. List<DiskImage> children = DbFacade.getInstance().getDiskImageDao().getAllSnapshotsForParent(topImage.getImageId()); if (!children.isEmpty()) { DiskImage childImage = children.get(0); childImage.setParentId(baseImage.getImageId()); getImageDao().update(childImage.getImage()); } Image oldTopImage = topImage.getImage(); topImage.setImage(baseImage.getImage()); baseImage.setImage(oldTopImage); Guid oldTopSnapshotId = topImage.getImage().getSnapshotId(); topImage.getImage().setSnapshotId(baseImage.getImage().getSnapshotId()); baseImage.getImage().setSnapshotId(oldTopSnapshotId); boolean oldTopIsActive = topImage.getImage().isActive(); topImage.getImage().setActive(baseImage.getImage().isActive()); VolumeClassification baseImageVolumeClassification = VolumeClassification.getVolumeClassificationByActiveFlag(baseImage.getImage().isActive()); topImage.getImage().setVolumeClassification(baseImageVolumeClassification); baseImage.getImage().setActive(oldTopIsActive); VolumeClassification oldTopVolumeClassification = VolumeClassification.getVolumeClassificationByActiveFlag(oldTopIsActive); topImage.getImage().setVolumeClassification(oldTopVolumeClassification); topImage.setSize(baseImage.getSize()); topImage.setImageStatus(ImageStatus.OK); getBaseDiskDao().update(topImage); getImageDao().update(topImage.getImage()); updateDiskImageDynamic(topImage); getBaseDiskDao().update(baseImage); getImageDao().update(baseImage.getImage()); updateVmConfigurationForImageChange( topImage.getImage().getSnapshotId(), baseImage.getImageId(), topImage); updateVmConfigurationForImageRemoval( baseImage.getImage().getSnapshotId(), topImage.getImageId()); } Set<Guid> imagesToUpdate = getParameters().getMergeStatusReturnValue().getImagesToRemove(); if (imagesToUpdate == null) { log.error("Failed to update orphaned images in db: image list could not be retrieved"); return; } for (Guid imageId : imagesToUpdate) { if (removeImages) { getImageDao().remove(imageId); } else { // The (illegal && no-parent && no-children) status indicates an orphaned image. Image image = getImageDao().get(imageId); image.setStatus(ImageStatus.ILLEGAL); image.setParentId(Guid.Empty); getImageDao().update(image); } } }