@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);
      }
    }
  }
Exemple #4
0
  @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()));
        }
      }
    }
  }