package org.ovirt.engine.core.bll;
import java.util.List;
import org.ovirt.engine.core.bll.command.utils.StorageDomainSpaceChecker;
import org.ovirt.engine.core.common.AuditLogType;
import org.ovirt.engine.core.common.action.MoveMultipleImageGroupsParameters;
import org.ovirt.engine.core.common.action.MoveVmParameters;
import org.ovirt.engine.core.common.action.VdcActionType;
import org.ovirt.engine.core.common.action.VdcReturnValueBase;
import org.ovirt.engine.core.common.businessentities.DiskImage;
import org.ovirt.engine.core.common.businessentities.ImageOperation;
import org.ovirt.engine.core.common.businessentities.StorageDomainStatus;
import org.ovirt.engine.core.common.businessentities.StoragePoolIsoMapId;
import org.ovirt.engine.core.common.businessentities.VM;
import org.ovirt.engine.core.common.businessentities.VMStatus;
import org.ovirt.engine.core.common.businessentities.VmDynamic;
import org.ovirt.engine.core.common.businessentities.storage_domains;
import org.ovirt.engine.core.common.errors.VdcBLLException;
import org.ovirt.engine.core.common.errors.VdcBllErrors;
import org.ovirt.engine.core.common.queries.GetStorageDomainsByVmTemplateIdQueryParameters;
import org.ovirt.engine.core.common.queries.VdcQueryType;
import org.ovirt.engine.core.common.vdscommands.IsVmDuringInitiatingVDSCommandParameters;
import org.ovirt.engine.core.common.vdscommands.VDSCommandType;
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.dal.VdcBllMessages;
import org.ovirt.engine.core.dal.dbbroker.DbFacade;
import org.ovirt.engine.core.utils.Helper;
import org.ovirt.engine.core.utils.linq.Function;
import org.ovirt.engine.core.utils.linq.LinqUtils;
@NonTransactiveCommandAttribute(forceCompensation = true)
public class MoveVmCommand<T extends MoveVmParameters> extends MoveOrCopyTemplateCommand<T> {
/**
* Constructor for command creation when compensation is applied on startup
*
* @param commandId
*/
protected MoveVmCommand(Guid commandId) {
super(commandId);
}
public MoveVmCommand(T parameters) {
super(parameters);
setVmId(parameters.getContainerId());
parameters.setEntityId(getVmId());
setStoragePoolId(getVm().getstorage_pool_id());
}
@Override
protected ImageOperation getMoveOrCopyImageOperation() {
return ImageOperation.Move;
}
@Override
protected boolean canDoAction() {
boolean retValue = true;
if (getVm() == null) {
retValue = false;
addCanDoActionMessage(VdcBllMessages.ACTION_TYPE_FAILED_VM_NOT_FOUND);
} else {
setDescription(getVmName());
}
// check that vm is down and images are ok
// not checking storage domain, there is a check in
// CheckTemplateInStorageDomain later
retValue = retValue
&& ImagesHandler.PerformImagesChecks(getVmId(), getReturnValue().getCanDoActionMessages(), getVm()
.getstorage_pool_id(), Guid.Empty, false, true, true, true, true, true, false);
setStoragePoolId(getVm().getstorage_pool_id());
VmHandler.updateDisksFromDb(getVm());
retValue = retValue && CheckTemplateInStorageDomain();
if (retValue
&& DbFacade.getInstance()
.getStoragePoolIsoMapDAO()
.get(new StoragePoolIsoMapId(getStorageDomain().getid(),
getVm().getstorage_pool_id())) == null) {
retValue = false;
addCanDoActionMessage(VdcBllMessages.ACTION_TYPE_FAILED_STORAGE_POOL_NOT_MATCH);
}
if (retValue && getVm().getDiskMap().size() <= 0) {
addCanDoActionMessage(VdcBllMessages.ACTION_TYPE_FAILED_VM_HAS_NO_DISKS);
retValue = false;
}
// update vm snapshots for storage free space check
for (DiskImage diskImage : getVm().getDiskMap().values()) {
diskImage.getSnapshots().addAll(
ImagesHandler.getAllImageSnapshots(diskImage.getId(), diskImage.getit_guid()));
}
retValue = retValue && destinationHasSpace();
if (!retValue) {
addCanDoActionMessage(VdcBllMessages.VAR__ACTION__MOVE);
addCanDoActionMessage(VdcBllMessages.VAR__TYPE__VM);
}
return retValue;
}
private boolean destinationHasSpace() {
if (!StorageDomainSpaceChecker.hasSpaceForRequest(getStorageDomain(),
(int) getVm().getActualDiskWithSnapshotsSize())) {
addCanDoActionMessage(VdcBllMessages.ACTION_TYPE_FAILED_DISK_SPACE_LOW);
return false;
}
return true;
}
protected boolean CheckTemplateInStorageDomain() {
boolean retValue = CheckStorageDomain() && checkStorageDomainStatus(StorageDomainStatus.Active)
// LINQ 32934 && CheckIfDisksExist(Vm.DiskMap.Values.ToList());
&& CheckIfDisksExist(getVm().getDiskMap().values());
if (retValue && !VmTemplateHandler.BlankVmTemplateId.equals(getVm().getvmt_guid())) {
List<storage_domains> domains = (List) Backend
.getInstance()
.runInternalQuery(VdcQueryType.GetStorageDomainsByVmTemplateId,
new GetStorageDomainsByVmTemplateIdQueryParameters(getVm().getvmt_guid())).getReturnValue();
// LINQ 32934 if (!domains.Select(a =>
// a.id).Contains(MoveParameters.StorageDomainId))
List<Guid> list = LinqUtils.foreach(domains, new Function<storage_domains, Guid>() {
@Override
public Guid eval(storage_domains a) {
return a.getid();
}
});
if (!list.contains(getParameters().getStorageDomainId())) {
retValue = false;
addCanDoActionMessage(VdcBllMessages.ACTION_TYPE_FAILED_TEMPLATE_NOT_FOUND_ON_DESTINATION_DOMAIN);
}
}
return retValue;
}
@Override
protected void executeCommand() {
VmDynamic vmDynamic = DbFacade.getInstance().getVmDynamicDAO().get(getVm().getvm_guid());
if (vmDynamic.getstatus() != VMStatus.Down) {
throw new VdcBLLException(VdcBllErrors.IRS_IMAGE_STATUS_ILLEGAL);
}
VM vm = getVm();
// Check if vm is initializing to run or already running - if it is in
// such state,
// we cannot move the vm
boolean isVmDuringInit = ((Boolean) Backend
.getInstance()
.getResourceManager()
.RunVdsCommand(VDSCommandType.IsVmDuringInitiating,
new IsVmDuringInitiatingVDSCommandParameters(vm.getvm_guid())).getReturnValue()).booleanValue();
if (isVmDuringInit) {
log.errorFormat("VM {0} must be down for Move VM to be successfuly executed", vm.getvm_name());
setActionReturnValue(vm.getstatus());
setSucceeded(false);
return;
}
VmHandler.LockVm(vmDynamic, getCompensationContext());
MoveOrCopyAllImageGroups();
setSucceeded(true);
}
protected boolean UpdateVmImSpm() {
return VmCommand.UpdateVmInSpm(getVm().getstorage_pool_id(),
new java.util.ArrayList<VM>(java.util.Arrays.asList(new VM[] { getVm() })));
}
@Override
protected void MoveOrCopyAllImageGroups() {
MoveMultipleImageGroupsParameters tempVar = new MoveMultipleImageGroupsParameters(getVm().getvm_guid(),
Helper.ToList(getVm().getDiskMap().values()), getParameters().getStorageDomainId());
tempVar.setParentCommand(getActionType());
tempVar.setEntityId(getParameters().getEntityId());
MoveMultipleImageGroupsParameters p = tempVar;
VdcReturnValueBase vdcRetValue = Backend.getInstance().runInternalAction(VdcActionType.MoveMultipleImageGroups,
p);
getParameters().getImagesParameters().add(p);
getReturnValue().getTaskIdList().addAll(vdcRetValue.getInternalTaskIdList());
}
@Override
public AuditLogType getAuditLogTypeValue() {
switch (getActionState()) {
case EXECUTE:
return getSucceeded() ? AuditLogType.USER_MOVED_VM : AuditLogType.USER_FAILED_MOVE_VM;
case END_SUCCESS:
return getSucceeded() ? AuditLogType.USER_MOVED_VM_FINISHED_SUCCESS
: AuditLogType.USER_MOVED_VM_FINISHED_FAILURE;
default:
return AuditLogType.USER_MOVED_VM_FINISHED_FAILURE;
}
}
protected void EndMoveVmCommand() {
EndActionOnAllImageGroups();
if (getVm() != null) {
VmHandler.UnLockVm(getVm().getvm_guid());
VmHandler.updateDisksFromDb(getVm());
UpdateVmImSpm();
}
else {
setCommandShouldBeLogged(false);
log.warn("MoveVmCommand::EndMoveVmCommand: Vm is null - not performing full EndAction");
}
setSucceeded(true);
}
@Override
protected void EndSuccessfully() {
EndMoveVmCommand();
}
@Override
protected void EndWithFailure() {
EndMoveVmCommand();
}
@Override
protected VdcActionType getImagesActionType() {
return VdcActionType.MoveMultipleImageGroups;
}
private static LogCompat log = LogFactoryCompat.getLog(MoveVmCommand.class);
}