package org.ovirt.engine.core.bll; import org.ovirt.engine.core.common.action.ImagesContainterParametersBase; import org.ovirt.engine.core.common.action.VdcActionParametersBase; import org.ovirt.engine.core.common.action.VdcActionType; import org.ovirt.engine.core.common.asynctasks.AsyncTaskCreationInfo; import org.ovirt.engine.core.common.asynctasks.AsyncTaskParameters; import org.ovirt.engine.core.common.asynctasks.AsyncTaskType; import org.ovirt.engine.core.common.businessentities.AsyncTaskResultEnum; import org.ovirt.engine.core.common.businessentities.AsyncTaskStatusEnum; import org.ovirt.engine.core.common.businessentities.DiskImage; import org.ovirt.engine.core.common.businessentities.async_tasks; import org.ovirt.engine.core.common.businessentities.image_vm_map; import org.ovirt.engine.core.common.businessentities.image_vm_map_id; import org.ovirt.engine.core.common.errors.VdcBLLException; import org.ovirt.engine.core.common.errors.VdcFault; import org.ovirt.engine.core.common.vdscommands.DestroyImageVDSCommandParameters; import org.ovirt.engine.core.common.vdscommands.VDSCommandType; import org.ovirt.engine.core.common.vdscommands.VDSReturnValue; import org.ovirt.engine.core.compat.Guid; import org.ovirt.engine.core.compat.LogCompat; import org.ovirt.engine.core.compat.LogFactoryCompat; import org.ovirt.engine.core.compat.RefObject; import org.ovirt.engine.core.dal.dbbroker.DbFacade; /** * This command responcible to make snapshot of some Vm mapped to some drive be * active snapshot. All children snapshots and other snapshot mapped to same * drive will be removed. */ // VB & C# TO JAVA CONVERTER TODO TASK: Java annotations will not correspond to // .NET attributes: @InternalCommandAttribute public class RestoreFromSnapshotCommand<T extends ImagesContainterParametersBase> extends BaseImagesCommand<T> { /** * patch */ private Guid mImageIdToRestore; private Guid mOtherImageId; private final java.util.ArrayList<Guid> _imagesToDelete = new java.util.ArrayList<Guid>(); public RestoreFromSnapshotCommand(T parameters) { super(parameters); mImageIdToRestore = mImageIdToRestore == null ? Guid.Empty : mImageIdToRestore; mOtherImageId = mOtherImageId == null ? Guid.Empty : mOtherImageId; } @Override protected void executeCommand() { super.executeCommand(); if (RemoveImages()) { SaveImageVmMapToDb(); setSucceeded(true); } } private void RemoveOtherMappedImages() { DiskImage image; while ((image = GetOtherImageMappedToSameDrive()) != null) { DbFacade.getInstance() .getImageVmMapDAO() .remove(new image_vm_map_id(image.getId(), getDiskImage().getvm_guid())); /** * Vitaly //_imagesToDelete.Insert(_imagesToDelete.Count, * image.image_guid); */ RemoveSnapshot(image); } } private boolean RemoveImages() { (getParameters()).setImageGroupID(getDiskImage().getimage_group_id().getValue()); if (!mOtherImageId.equals(Guid.Empty)) { // Restoring done to trieng image. - active. // all other child images of trieng image's parent should be removed // They are: other mapped image and all its parents until trying // image parent DbFacade.getInstance() .getImageVmMapDAO() .remove(new image_vm_map_id(mOtherImageId, getDiskImage().getvm_guid())); RemoveOtherImageAndParents(mOtherImageId, getDiskImage().getParentId()); } else { if (getDiskImage().getactive() != null && getDiskImage().getactive().equals(false)) { RemoveOtherMappedImages(); } RemoveChildren(getImage().getId()); } return RemoveImagesInIrs(); } /** * This function encapsulated processing of removing image in Irs. If image * not exists - no exception re throwing. This functionality aids to remove * Vm/Vmtemplate even if one or more its images not exists in Irs. */ private boolean RemoveImagesInIrs() { try { Guid storagePoolId = getDiskImage().getstorage_pool_id() != null ? getDiskImage().getstorage_pool_id() .getValue() : Guid.Empty; Guid storageDomainId = getDiskImage().getstorage_id() != null ? getDiskImage().getstorage_id().getValue() : Guid.Empty; Guid imageGroupId = getDiskImage().getimage_group_id() != null ? getDiskImage().getimage_group_id() .getValue() : Guid.Empty; VDSReturnValue vdsReturnValue = runVdsCommand( VDSCommandType.DestroyImage, new DestroyImageVDSCommandParameters(storagePoolId, storageDomainId, imageGroupId, _imagesToDelete, getDiskImage().getwipe_after_delete(), true, getStoragePool() .getcompatibility_version().toString())); if (vdsReturnValue.getSucceeded()) { getReturnValue().getInternalTaskIdList().add( CreateTask(vdsReturnValue.getCreationInfo(), VdcActionType.RestoreAllSnapshots)); } else { return false; } } // Don't throw an exception when cannot destroy image in the VDSM. catch (VdcBLLException e) { // Set fault for parent command RestoreAllSnapshotCommand to use, if decided to fail the command. getReturnValue().setFault(new VdcFault(e, e.getVdsError().getCode())); log.info(String.format("%1$s Image not exist in Irs", getDiskImage().getId())); } return true; } @Override protected Guid ConcreteCreateTask(AsyncTaskCreationInfo asyncTaskCreationInfo, VdcActionType parentCommand) { VdcActionParametersBase commandParams = getParametersForTask(parentCommand, getParameters()); AsyncTaskParameters p = new AsyncTaskParameters(asyncTaskCreationInfo, new async_tasks(parentCommand, AsyncTaskResultEnum.success, AsyncTaskStatusEnum.running, asyncTaskCreationInfo.getTaskID(), commandParams)); p.setEntityId(getParameters().getEntityId()); Guid ret = AsyncTaskManager.getInstance().CreateTask(AsyncTaskType.deleteVolume, p, false); return ret; } @Override protected void AdditionalImageRemoveTreatment(DiskImage snapshot) { // Vitaly _imagesToDelete.add(_imagesToDelete.size(), snapshot.getId()); } private void RemoveOtherImageAndParents(Guid imageId, Guid lastParent) { DiskImage image = DbFacade.getInstance().getDiskImageDAO().getSnapshotById(imageId); // store other mapped image's parent Id Guid currentParent = image.getParentId(); // Remove other mapped image from Irs and db /** * Vitaly //_imagesToDelete.Add(image.image_guid); */ RemoveSnapshot(image); while (!lastParent.equals(currentParent)) { image = DbFacade.getInstance().getDiskImageDAO().getSnapshotById(currentParent); // store current image's parent Id currentParent = image.getParentId(); /** * Vitaly * //_imagesToDelete.Insert(_imagesToDelete.Count,image.image_guid); */ RemoveSnapshot(image); } } private void SaveImageVmMapToDb() { DiskImage image = DbFacade.getInstance().getDiskImageDAO().get(getImage().getId()); if (image != null) { // //Restoring inactive image DbFacade.getInstance().getImageVmMapDAO().update( new image_vm_map(true, image.getId(), image.getcontainer_guid())); } else { DbFacade.getInstance().getImageVmMapDAO().save( new image_vm_map(true, getImage().getId(), getImage().getcontainer_guid())); } } /** * During trying image new snapshot created to image, user wish to try. If * user wish to work with image, he tried - he will work with snapshot * instead of the original image. In this case ImageId will be not the * original image Id, But the snapshots. We assuming that this case can * occure only during Trying image. So there are two images map to same * drive will appiare in db and active is the one - user will work with. * Inactive will be removed */ @Override protected Guid getImageId() { if (mImageIdToRestore == null || mImageIdToRestore.equals(Guid.Empty)) { mImageIdToRestore = super.getImageId(); DiskImage activeImage = null; DiskImage inactiveImage = null; RefObject<DiskImage> tempRefObject = new RefObject<DiskImage>(activeImage); RefObject<DiskImage> tempRefObject2 = new RefObject<DiskImage>(inactiveImage); int count = ImagesHandler.getImagesMappedToDrive(getImageContainerId(), getDrive(), tempRefObject, tempRefObject2); activeImage = tempRefObject.argvalue; inactiveImage = tempRefObject2.argvalue; if (count == 2) { if (activeImage != null && inactiveImage != null) { if (super.getImageId().equals(activeImage.getParentId())) { mImageIdToRestore = activeImage.getId(); mOtherImageId = inactiveImage.getId(); } } } } return mImageIdToRestore; } private static LogCompat log = LogFactoryCompat.getLog(RestoreFromSnapshotCommand.class); }