@Test public void testExtendingDiskWithQuota() { Guid quotaId = Guid.newGuid(); DiskImage oldDiskImage = createDiskImage(); oldDiskImage.setQuotaId(quotaId); oldDiskImage.setSize( SizeConverter.convert(3, SizeConverter.SizeUnit.GiB, SizeConverter.SizeUnit.BYTES) .longValue()); DiskImage newDiskImage = createDiskImage(); newDiskImage.setQuotaId(quotaId); newDiskImage.setSize( SizeConverter.convert(5, SizeConverter.SizeUnit.GiB, SizeConverter.SizeUnit.BYTES) .longValue()); UpdateVmDiskParameters parameters = new UpdateVmDiskParameters(vmId, diskImageGuid, newDiskImage); long diskExtendingDiffInGB = newDiskImage.getSizeInGigabytes() - oldDiskImage.getSizeInGigabytes(); when(diskDao.get(diskImageGuid)).thenReturn(oldDiskImage); initializeCommand(parameters); QuotaStorageConsumptionParameter consumptionParameter = (QuotaStorageConsumptionParameter) command.getQuotaStorageConsumptionParameters().get(0); assertEquals(consumptionParameter.getRequestedStorageGB().longValue(), diskExtendingDiffInGB); }
/** The following method will create a new DiskImage */ private DiskImage createDiskImage() { DiskImage disk = new DiskImage(); disk.setId(diskImageGuid); disk.setSize(100000L); disk.setDiskInterface(DiskInterface.VirtIO); disk.setStorageIds(new ArrayList<>(Collections.singleton(sdId))); disk.setStoragePoolId(spId); disk.setDescription(RandomUtils.instance().nextString(10)); return disk; }
/** * 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); } } }
@Override public void buildDisk() { XmlNodeList list = selectNodes(_document, "//*/Section/Disk"); for (XmlNode node : list) { final Guid guid = new Guid(node.attributes.get("ovf:diskId").getValue()); DiskImage image = _images.stream().filter(d -> d.getImageId().equals(guid)).findFirst().orElse(null); DiskVmElement dve = image.getDiskVmElementForVm(vmBase.getId()); if (node.attributes.get("ovf:vm_snapshot_id") != null) { image.setVmSnapshotId(new Guid(node.attributes.get("ovf:vm_snapshot_id").getValue())); } if (!StringUtils.isEmpty(node.attributes.get("ovf:size").getValue())) { image.setSize( convertGigabyteToBytes(Long.parseLong(node.attributes.get("ovf:size").getValue()))); } if (!StringUtils.isEmpty(node.attributes.get("ovf:actual_size").getValue())) { image.setActualSizeInBytes( convertGigabyteToBytes( Long.parseLong(node.attributes.get("ovf:actual_size").getValue()))); } if (node.attributes.get("ovf:volume-format") != null) { if (!StringUtils.isEmpty(node.attributes.get("ovf:volume-format").getValue())) { image.setVolumeFormat( VolumeFormat.valueOf(node.attributes.get("ovf:volume-format").getValue())); } else { image.setVolumeFormat(VolumeFormat.Unassigned); } } else { image.setVolumeFormat(VolumeFormat.Unassigned); } if (image.isQcowFormat()) { if (node.attributes.get("ovf:qcow-compat") != null && StringUtils.isNotEmpty(node.attributes.get("ovf:qcow-compat").getValue())) { image.setQcowCompat( QcowCompat.valueOf(node.attributes.get("ovf:qcow-compat").getValue())); } else { image.setQcowCompat(QcowCompat.QCOW2_V2); } } if (node.attributes.get("ovf:volume-type") != null) { if (!StringUtils.isEmpty(node.attributes.get("ovf:volume-type").getValue())) { image.setVolumeType( VolumeType.valueOf(node.attributes.get("ovf:volume-type").getValue())); } else { image.setVolumeType(VolumeType.Unassigned); } } else { image.setVolumeType(VolumeType.Unassigned); } if (node.attributes.get("ovf:disk-interface") != null) { if (!StringUtils.isEmpty(node.attributes.get("ovf:disk-interface").getValue())) { dve.setDiskInterface( DiskInterface.valueOf(node.attributes.get("ovf:disk-interface").getValue())); } } else { dve.setDiskInterface(DiskInterface.IDE); } if (node.attributes.get("ovf:boot") != null) { if (!StringUtils.isEmpty(node.attributes.get("ovf:boot").getValue())) { dve.setBoot(Boolean.parseBoolean(node.attributes.get("ovf:boot").getValue())); } } if (node.attributes.get("ovf:pass-discard") != null) { if (!StringUtils.isEmpty(node.attributes.get("ovf:pass-discard").getValue())) { dve.setPassDiscard( Boolean.parseBoolean(node.attributes.get("ovf:pass-discard").getValue())); } } if (node.attributes.get("ovf:wipe-after-delete") != null) { if (!StringUtils.isEmpty(node.attributes.get("ovf:wipe-after-delete").getValue())) { image.setWipeAfterDelete( Boolean.parseBoolean(node.attributes.get("ovf:wipe-after-delete").getValue())); } } if (node.attributes.get("ovf:disk-alias") != null) { if (!StringUtils.isEmpty(node.attributes.get("ovf:disk-alias").getValue())) { image.setDiskAlias(String.valueOf(node.attributes.get("ovf:disk-alias").getValue())); } } if (node.attributes.get("ovf:disk-description") != null) { if (!StringUtils.isEmpty(node.attributes.get("ovf:disk-description").getValue())) { image.setDiskDescription( String.valueOf(node.attributes.get("ovf:disk-description").getValue())); } } } }