package org.ovirt.engine.core.bll; import java.util.List; import org.ovirt.engine.core.common.AuditLogType; import org.ovirt.engine.core.common.action.RemoveAllVmImagesParameters; import org.ovirt.engine.core.common.action.RemoveVmParameters; 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.VM; import org.ovirt.engine.core.common.businessentities.VMStatus; import org.ovirt.engine.core.compat.Guid; import org.ovirt.engine.core.dal.VdcBllMessages; import org.ovirt.engine.core.dal.dbbroker.DbFacade; import org.ovirt.engine.core.utils.transaction.TransactionMethod; import org.ovirt.engine.core.utils.transaction.TransactionSupport; @LockIdNameAttribute(fieldName = "VmId") @NonTransactiveCommandAttribute(forceCompensation = true) public class RemoveVmCommand<T extends RemoveVmParameters> extends VmCommand<T> { /** * Constructor for command creation when compensation is applied on startup * * @param commandId */ protected RemoveVmCommand(Guid commandId) { super(commandId); } public RemoveVmCommand(T parameters) { super(parameters); super.setVmId(parameters.getVmId()); parameters.setEntityId(getVmId()); } private boolean hasImages; @Override protected void ExecuteVmCommand() { if (!CanRemoveVm(getVmId())) { return; } if (getVm().getstatus() != VMStatus.ImageLocked || !getParameters().getForce()) { VmHandler.checkStatusAndLockVm(getVmId(), getCompensationContext()); } freeLock(); setSucceeded(removeVm()); } private boolean removeVm() { VM vm = getVm(); Guid vmId = getVmId(); VmHandler.updateDisksFromDb(vm); hasImages = vm.getDiskMap().size() > 0; setVm(DbFacade.getInstance().getVmDAO().getById(vmId)); RemoveVmInSpm(vm.getstorage_pool_id(), vmId); if (!RemoveVmImages(null)) { return false; } if (!hasImages) { TransactionSupport.executeInNewTransaction(new TransactionMethod<Void>() { @Override public Void runInTransaction() { RemoveVmFromDb(); return null; } }); } return true; } @Override protected boolean canDoAction() { List<String> messages = getReturnValue().getCanDoActionMessages(); messages.add(VdcBllMessages.VAR__ACTION__REMOVE.toString()); messages.add(VdcBllMessages.VAR__TYPE__VM.toString()); return super.canDoAction() && isUnlockedOrForced(messages) && CanRemoveVm(getVmId(), messages); } private boolean isUnlockedOrForced(List<String> message) { boolean returnValue = true; if (getVm().getstatus() == VMStatus.ImageLocked && !getParameters().getForce()) { message.add(VdcBllMessages.ACTION_TYPE_FAILED_VM_IMAGE_IS_LOCKED.toString()); returnValue = false; } return returnValue; } public boolean CanRemoveVm(Guid vmId) { return !(IsVmRunning(vmId) || IsVmInPool(vmId)); } public static boolean IsVmRunning(Guid vmId) { VM vm = DbFacade.getInstance().getVmDAO().getById(vmId); if (vm != null) { return VM.isStatusUpOrPaused(vm.getstatus()) || vm.getstatus() == VMStatus.Unknown; } return false; } public static boolean IsVmInPool(Guid vmId) { VM vm = DbFacade.getInstance().getVmDAO().getById(vmId); return vm != null && vm.getVmPoolId() != null; } public boolean CanRemoveVm(Guid vmId, List<String> message) { boolean returnValue = true; VM vm = DbFacade.getInstance().getVmDAO().getById(vmId); java.util.ArrayList<String> imagesMessages = new java.util.ArrayList<String>(); if (vm == null) { message.add(VdcBllMessages.ACTION_TYPE_FAILED_VM_NOT_EXIST.toString()); returnValue = false; } else if (IsVmRunning(vmId) || (vm.getstatus() == VMStatus.NotResponding)) { message.add(VdcBllMessages.ACTION_TYPE_FAILED_VM_IS_RUNNING.toString()); returnValue = false; } else if (vm.getstatus() == VMStatus.Suspended) { message.add(VdcBllMessages.VM_CANNOT_REMOVE_VM_WHEN_STATUS_IS_NOT_DOWN.toString()); returnValue = false; } else if (IsVmInPool(vmId)) { message.add(VdcBllMessages.ACTION_TYPE_FAILED_VM_ATTACHED_TO_POOL.toString()); returnValue = false; } // enable to remove vms without images else { List<DiskImage> vmImages = DbFacade.getInstance().getDiskImageDAO().getAllForVm(vmId); if (vmImages.size() > 0 && !ImagesHandler.PerformImagesChecks(vmId, imagesMessages, vm.getstorage_pool_id(), vmImages .get(0).getstorage_id().getValue(), false, !getParameters().getForce(), false, false, getParameters().getForce(), false, true)) { message.addAll(imagesMessages); returnValue = false; } } if (returnValue && getParameters().getForce() && getVm().getstatus() == VMStatus.ImageLocked) { // we cannot force remove if there is running task if (AsyncTaskManager.getInstance().HasTasksByStoragePoolId(getVm().getstorage_pool_id())) { message.add(VdcBllMessages.VM_CANNOT_REMOVE_HAS_RUNNING_TASKS.toString()); returnValue = false; } } return returnValue; } protected boolean RemoveVmImages(java.util.ArrayList<DiskImage> images) { RemoveAllVmImagesParameters tempVar = new RemoveAllVmImagesParameters(getVmId(), images); tempVar.setParentCommand(getActionType()); tempVar.setEntityId(getParameters().getEntityId()); tempVar.setParentParemeters(getParameters()); VdcReturnValueBase vdcRetValue = Backend.getInstance().runInternalAction(VdcActionType.RemoveAllVmImages, tempVar); if (vdcRetValue.getSucceeded()) { getReturnValue().getTaskIdList().addAll(vdcRetValue.getInternalTaskIdList()); } return vdcRetValue.getSucceeded(); } @Override public AuditLogType getAuditLogTypeValue() { switch (getActionState()) { case EXECUTE: if (hasImages) { return getSucceeded() ? AuditLogType.USER_REMOVE_VM : AuditLogType.USER_FAILED_REMOVE_VM; } else { return getSucceeded() ? AuditLogType.USER_REMOVE_VM_FINISHED : AuditLogType.USER_FAILED_REMOVE_VM; } case END_FAILURE: case END_SUCCESS: default: return AuditLogType.USER_REMOVE_VM_FINISHED; } } protected void RemoveVmFromDb() { RemoveVmUsers(); RemoveVmNetwork(); // \\RemoveVmStatistics(); // \\RemoveVmDynamic(); RemoveVmStatic(); } @Override protected void EndVmCommand() { try { if (acquireLock()) { // Ensures the lock on the VM guid can be acquired. This prevents a race // between ExecuteVmCommand (for example, of a first multiple VMs removal that includes VM A, // and a second multiple VMs removal that include the same VM). setVm(DbFacade.getInstance().getVmDAO().getById(getVmId())); if (getVm() != null) { VmHandler.UnLockVm(getVmId()); RemoveVmFromDb(); } } setSucceeded(true); } finally { freeLock(); } } }