package org.ovirt.engine.core.bll;
import java.util.Collections;
import java.util.List;
import org.ovirt.engine.core.bll.storage.StorageDomainCommandBase;
import org.ovirt.engine.core.common.action.ImagesActionsParametersBase;
import org.ovirt.engine.core.common.action.ImagesContainterParametersBase;
import org.ovirt.engine.core.common.businessentities.DiskImage;
import org.ovirt.engine.core.common.businessentities.DiskImageDynamic;
import org.ovirt.engine.core.common.businessentities.IImage;
import org.ovirt.engine.core.common.businessentities.ImageStatus;
import org.ovirt.engine.core.common.businessentities.VM;
import org.ovirt.engine.core.common.businessentities.image_vm_map;
import org.ovirt.engine.core.common.errors.VdcBLLException;
import org.ovirt.engine.core.common.errors.VdcBllErrors;
import org.ovirt.engine.core.common.vdscommands.GetImageInfoVDSCommandParameters;
import org.ovirt.engine.core.common.vdscommands.VDSCommandType;
import org.ovirt.engine.core.compat.Guid;
import org.ovirt.engine.core.compat.RefObject;
import org.ovirt.engine.core.compat.StringHelper;
import org.ovirt.engine.core.dal.dbbroker.DbFacade;
/**
* Base class for all image handling commands
*
*
*/
public abstract class BaseImagesCommand<T extends ImagesActionsParametersBase> extends StorageDomainCommandBase<T> {
private DiskImage _destinationImage;
private IImage mImage;
private Guid mImageId = new Guid();
private Guid mImageContainerId = Guid.Empty;
/**
* Default mapping - drive 1
*/
private String mDrive = ImagesHandler.DefaultDriveName;
public BaseImagesCommand(T parameters) {
super(parameters);
mImageId = parameters.getImageId();
if (parameters instanceof ImagesContainterParametersBase) {
ImagesContainterParametersBase tempVar = (ImagesContainterParametersBase) parameters;
mImageContainerId = tempVar.getContainerId();
mDrive = tempVar.getDrive();
super.setVmId(mImageContainerId);
setStoragePoolId(getDiskImage() != null && getDiskImage().getstorage_pool_id() != null ? getDiskImage()
.getstorage_pool_id().getValue() : Guid.Empty);
}
}
protected IImage getImage() {
if (mImage == null) {
DiskImage image = DbFacade.getInstance().getDiskImageDAO().get(getImageId());
if (image != null) {
mImage = image;
} else {
image = DbFacade.getInstance().getDiskImageDAO().getSnapshotById(getImageId());
if (image != null) {
image.setvm_guid(getImageContainerId());
mImage = image;
}
}
}
return mImage;
}
protected Guid getImageId() {
return mImageId;
}
protected Guid getImageContainerId() {
return mImageContainerId;
}
protected void setImageContainerId(Guid value) {
mImageContainerId = value;
}
private DiskImage _diskImage;
protected DiskImage getDiskImage() {
if (_diskImage == null) {
IImage tempVar = getImage();
_diskImage = (DiskImage) ((tempVar instanceof DiskImage) ? tempVar : null);
}
return _diskImage;
}
protected void setDiskImage(DiskImage value) {
_diskImage = value;
}
protected String getDrive() {
return mDrive;
}
private Guid _destinationImageId = Guid.Empty;
protected Guid getDestinationImageId() {
return getParameters() != null ? getParameters().getDestinationImageId() : _destinationImageId;
}
protected void setDestinationImageId(Guid value) {
if (getParameters() != null) {
getParameters().setDestinationImageId(value);
} else {
_destinationImageId = value;
}
}
protected DiskImage getDestinationDiskImage() {
if (_destinationImage == null) {
DiskImage image = DbFacade.getInstance().getDiskImageDAO().get(getDestinationImageId());
if (image != null) {
_destinationImage = image;
} else {
image = DbFacade.getInstance().getDiskImageDAO().getSnapshotById(getDestinationImageId());
if (image != null) {
_destinationImage = image;
}
}
}
return _destinationImage;
}
private Guid _imageGroupId = Guid.Empty;
protected Guid getImageGroupId() {
if (_imageGroupId.equals(Guid.Empty)) {
_imageGroupId = getDiskImage().getimage_group_id() != null ? getDiskImage().getimage_group_id().getValue()
: Guid.Empty;
}
return _imageGroupId;
}
protected void setImageGroupId(Guid value) {
_imageGroupId = value;
}
@Override
protected void executeCommand() {
InitImageContainer();
CheckImageValidity();
}
/**
* Initialize identity of object, contains image(VM or VmTemplate)
*/
protected void InitImageContainer() {
if (mImageContainerId.equals(Guid.Empty)) {
mImageContainerId = getImage().getcontainer_guid();
}
}
/**
* Check if image is valid snapshot of vm
*/
protected void CheckImageValidity() {
try {
IImage tempVar = getImage();
DiskImage diskImage = (DiskImage) ((tempVar instanceof DiskImage) ? tempVar : null);
/**
* Vitaly change. Prevent operating image with illegal status TODO:
* insert it in new CanDoAction mechanizm
*/
if (diskImage == null) {
diskImage = DbFacade.getInstance().getDiskImageDAO().getSnapshotById(getImage().getId());
}
Guid storagePoolId = diskImage.getstorage_pool_id() != null ? diskImage.getstorage_pool_id().getValue()
: Guid.Empty;
Guid storageDomainId =
getStorageDomainId() != null && !getStorageDomainId().getValue().equals(Guid.Empty) ? getStorageDomainId()
.getValue()
: diskImage.getstorage_id() != null ? diskImage.getstorage_id().getValue() : Guid.Empty;
Guid imageGroupId = diskImage.getimage_group_id() != null ? diskImage.getimage_group_id().getValue()
: Guid.Empty;
DiskImage image = (DiskImage) Backend
.getInstance()
.getResourceManager()
.RunVdsCommand(
VDSCommandType.GetImageInfo,
new GetImageInfoVDSCommandParameters(storagePoolId, storageDomainId, imageGroupId,
getImage().getId())).getReturnValue();
if (image.getimageStatus() != ImageStatus.OK) {
if (diskImage != null) {
diskImage.setimageStatus(image.getimageStatus());
DbFacade.getInstance().getDiskImageDAO().update(diskImage);
throw new VdcBLLException(VdcBllErrors.IRS_IMAGE_STATUS_ILLEGAL);
}
}
if (diskImage != null) {
diskImage.setlastModified(image.getlast_modified_date());
}
} catch (RuntimeException ex) {
if (ex instanceof VdcBLLException) {
throw ex;
}
throw new VdcBLLException(VdcBllErrors.RESOURCE_MANAGER_VM_SNAPSHOT_MISSMATCH, ex);
}
}
/**
* Snapshot can be created only when there is no other images maped to same
* drive in vm.
*
* @return TODO: Vitaly. Remove coupling between this and
* CanCreateAllSnapshotsFromVm
*/
protected boolean CanCreateSnapshot() {
List<DiskImage> images = DbFacade.getInstance().getDiskImageDAO().getAllForVm(getImageContainerId());
int count = 0;
for (DiskImage image : images) {
if (StringHelper.EqOp(image.getinternal_drive_mapping(), getImage().getinternal_drive_mapping())) {
count++;
if (count > 1) {
log.error("Cannot create snapshot. Vm is in preview status");
return false;
}
}
}
return true;
}
/**
* Returns first found image in database that assigned to Image's parent Vm
* and mapped to same drive
*
* @return m
*/
protected DiskImage GetOtherImageMappedToSameDrive() {
List<DiskImage> images = DbFacade.getInstance().getDiskImageDAO().getAllForVm(getImageContainerId());
if (getImage() != null) {
for (DiskImage image : images) {
if (StringHelper.EqOp(image.getinternal_drive_mapping(), getImage().getinternal_drive_mapping())
&& !getImage().getId().equals(image.getId())) {
return image;
}
}
}
return null;
}
/**
* Creates a copy of the source disk image ('DiskImage').
*
* @param newImageGuid
* the image id of the cloned disk image.
* @return the cloned disk image. Note that the cloned image's status is
* 'Locked'.
*/
protected DiskImage CloneDiskImage(Guid newImageGuid) {
DiskImage retDiskImage = DiskImage.copyOf(getDiskImage());
retDiskImage.setId(newImageGuid);
retDiskImage.setdescription(CalculateImageDescription());
retDiskImage.setParentId(getDiskImage().getId());
retDiskImage.setvm_snapshot_id(getParameters().getVmSnapshotId());
retDiskImage.setvm_guid(getImageContainerId());
retDiskImage.setimage_group_id(getImageGroupId());
retDiskImage.setlast_modified_date(getNow());
return retDiskImage;
}
/**
* Overrides the relevant fields of the destination disk image
* ('DestinationDiskImage') with some values of the IRS disk image.
*
* @param fromIRS
* the IRS disk image.
*/
protected void CompleteImageData(DiskImage fromIRS) {
getDestinationDiskImage().setcreation_date(fromIRS.getcreation_date());
getDestinationDiskImage().setlast_modified_date(fromIRS.getlast_modified_date());
getDestinationDiskImage().setlastModified(getDestinationDiskImage().getlast_modified_date());
DiskImageDynamic destinationDiskDynamic = DbFacade.getInstance().getDiskImageDynamicDAO().get(
getDestinationDiskImage().getId());
if (destinationDiskDynamic != null) {
destinationDiskDynamic.setactual_size(fromIRS.getactual_size());
DbFacade.getInstance().getDiskImageDynamicDAO().update(destinationDiskDynamic);
}
// DestinationDiskImage.description = CalculateImageDescription();
}
/**
* Building the label name for volume.
*
* @return - Calculated label name.
*/
protected String CalculateImageDescription() {
VM vm = DbFacade.getInstance().getVmDAO().getById(getImageContainerId());
// If vm is null (could be because the getImageContainerId() is a Blank
// template) , use the vm id.
if (vm == null) {
vm = DbFacade.getInstance().getVmDAO().getById(getVmId());
}
/**
* Vitaly: added description per QA request
*/
StringBuilder vmLabel = new StringBuilder("ActiveImage");
vmLabel = (vm == null) ? vmLabel : vmLabel.append("_").append(vm.getvm_name());
return String.format("_%1$s_%2$s", vmLabel, new java.util.Date());
}
protected static void CompleteAdvancedDiskData(DiskImage from, DiskImage to) {
to.setboot(from.getboot());
to.setdisk_interface(from.getdisk_interface());
to.setpropagate_errors(from.getpropagate_errors());
to.setwipe_after_delete(from.getwipe_after_delete());
}
protected void AddDiskImageToDb(DiskImage image) {
// TODO handle creation date & the difference between direct parent &
// image template
// TODO - transaction
// Adding new disk to the image table in the DB
try {
DbFacade.getInstance().getDiskImageDAO().save(image);
DbFacade.getInstance().getImageVmMapDAO().save(
new image_vm_map(image.getactive(), image.getId(), image.getvm_guid()));
DiskImageDynamic diskDynamic = new DiskImageDynamic();
diskDynamic.setId(image.getId());
diskDynamic.setactual_size(image.getactual_size());
DbFacade.getInstance().getDiskImageDynamicDAO().save(diskDynamic);
} catch (RuntimeException ex) {
log.error("AddDiskImageToDB::Failed adding new created snapshot into the db", ex);
throw new VdcBLLException(VdcBllErrors.DB, ex);
}
}
protected void LockImage() {
SetImageStatus(getDiskImage(), ImageStatus.LOCKED);
}
protected void UnLockImage() {
SetImageStatus(getDiskImage(), ImageStatus.OK);
}
protected void MarkImageAsIllegal() {
SetImageStatus(getDiskImage(), ImageStatus.ILLEGAL);
}
protected static void SetImageStatus(DiskImage diskImage, ImageStatus imageStatus) {
if (diskImage != null) {
diskImage.setimageStatus(imageStatus);
DbFacade.getInstance().getDiskImageDAO().update(diskImage);
}
}
@Override
protected void EndSuccessfully() {
if (getDestinationDiskImage() != null) {
Guid storagePoolId = getDestinationDiskImage().getstorage_pool_id() != null ? getDestinationDiskImage()
.getstorage_pool_id().getValue() : Guid.Empty;
Guid newImageGroupId = getDestinationDiskImage().getimage_group_id() != null ? getDestinationDiskImage()
.getimage_group_id().getValue() : Guid.Empty;
Guid newImageId = getDestinationDiskImage().getId();
Guid newStorageDomainID = getDestinationDiskImage().getstorage_id() != null ? getDestinationDiskImage()
.getstorage_id().getValue() : Guid.Empty;
// complete IRS data to DB disk image:
DiskImage newImageIRS = (DiskImage) Backend
.getInstance()
.getResourceManager()
.RunVdsCommand(
VDSCommandType.GetImageInfo,
new GetImageInfoVDSCommandParameters(storagePoolId, newStorageDomainID, newImageGroupId,
newImageId)).getReturnValue();
if (newImageIRS != null) {
CompleteImageData(newImageIRS);
}
// Unlock destination image:
getDestinationDiskImage().setimageStatus(ImageStatus.OK);
DbFacade.getInstance().getDiskImageDAO().update(getDestinationDiskImage());
}
if (getDiskImage() != null) {
// Unlock source image:
UnLockImage();
}
setSucceeded(true);
}
@Override
protected void EndWithFailure() {
UndoActionOnSourceAndDestination();
setSucceeded(true);
}
protected void UndoActionOnSourceAndDestination() {
if (getDestinationDiskImage() != null) {
RemoveSnapshotFromDB(getDestinationImageId());
}
if (getDiskImage() != null) {
// Unlock source image:
UnLockImage();
}
}
/**
* Vitaly TODO: move it other class in hierarch
*/
protected void RemoveSnapshot(DiskImage snapshot) {
RemoveSnapshotFromDB(snapshot.getId());
AdditionalImageRemoveTreatment(snapshot);
}
protected void AdditionalImageRemoveTreatment(DiskImage snapshot) {
}
protected void RemoveSnapshotFromDB(Guid snapshotGUID) {
DbFacade.getInstance().getDiskImageDAO().remove(snapshotGUID);
}
public static void GetImageChildren(Guid snapshot, RefObject<java.util.ArrayList<Guid>> children) {
java.util.ArrayList<Guid> list = new java.util.ArrayList<Guid>();
for (DiskImage image : DbFacade.getInstance().getDiskImageDAO().getAllSnapshotsForParent(snapshot)) {
list.add(image.getId());
}
children.argvalue.addAll(list);
for (Guid snapshotId : list) {
GetImageChildren(snapshotId, children);
}
}
protected void RemoveChildren(Guid snapshot) {
java.util.ArrayList<Guid> children = new java.util.ArrayList<Guid>();
RefObject<java.util.ArrayList<Guid>> tempRefObject = new RefObject<java.util.ArrayList<Guid>>(children);
GetImageChildren(snapshot, tempRefObject);
children = tempRefObject.argvalue;
// children.Reverse();
Collections.reverse(children);
for (Guid child : children) {
RemoveSnapshot(DbFacade.getInstance().getDiskImageDAO().getSnapshotById(child));
}
}
}