package org.ovirt.engine.core.bll;
import java.util.ArrayList;
import java.util.List;
import javax.inject.Inject;
import org.apache.commons.lang.StringUtils;
import org.ovirt.engine.core.bll.context.CommandContext;
import org.ovirt.engine.core.bll.quota.QuotaClusterConsumptionParameter;
import org.ovirt.engine.core.bll.quota.QuotaConsumptionParameter;
import org.ovirt.engine.core.bll.quota.QuotaStorageConsumptionParameter;
import org.ovirt.engine.core.bll.quota.QuotaStorageDependent;
import org.ovirt.engine.core.bll.quota.QuotaVdsDependent;
import org.ovirt.engine.core.bll.utils.PermissionSubject;
import org.ovirt.engine.core.common.AuditLogType;
import org.ovirt.engine.core.common.VdcObjectType;
import org.ovirt.engine.core.common.action.StopVmParametersBase;
import org.ovirt.engine.core.common.asynctasks.EntityInfo;
import org.ovirt.engine.core.common.businessentities.VMStatus;
import org.ovirt.engine.core.common.businessentities.storage.DiskImage;
import org.ovirt.engine.core.common.errors.EngineMessage;
import org.ovirt.engine.core.common.vdscommands.DestroyVmVDSCommandParameters;
import org.ovirt.engine.core.common.vdscommands.VDSCommandType;
import org.ovirt.engine.core.compat.Guid;
import org.ovirt.engine.core.dao.SnapshotDao;
import org.ovirt.engine.core.dao.VmDynamicDao;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public abstract class StopVmCommandBase<T extends StopVmParametersBase> extends VmOperationCommandBase<T>
implements QuotaVdsDependent, QuotaStorageDependent {
private static final Logger log = LoggerFactory.getLogger(StopVmCommandBase.class);
@Inject
private VmDynamicDao vmDynamicDao;
@Inject
private SnapshotDao snapshotDao;
private boolean suspendedVm;
protected StopVmCommandBase(Guid guid) {
super(guid);
}
protected StopVmCommandBase(T parameters, CommandContext commandContext) {
super(parameters, commandContext);
}
protected boolean getSuspendedVm() {
return suspendedVm;
}
@Override
protected boolean validate() {
if (shouldSkipCommandExecutionCached()) {
return true;
}
if (getVm() == null) {
return failValidation(EngineMessage.ACTION_TYPE_FAILED_VM_NOT_FOUND);
}
if (!canRunActionOnNonManagedVm()) {
return false;
}
if (!getVm().isRunning() && getVm().getStatus() != VMStatus.Paused
&& getVm().getStatus() != VMStatus.NotResponding && getVm().getStatus() != VMStatus.Suspended) {
return failValidation(
(getVm().getStatus().isHibernating() || getVm().getStatus() == VMStatus.RestoringState) ?
EngineMessage.ACTION_TYPE_FAILED_VM_IS_SAVING_RESTORING
: EngineMessage.ACTION_TYPE_FAILED_VM_IS_NOT_RUNNING);
}
return true;
}
protected void destroyVm() {
if (getVm().getStatus() == VMStatus.MigratingFrom && getVm().getMigratingToVds() != null) {
runVdsCommand(
VDSCommandType.DestroyVm,
new DestroyVmVDSCommandParameters(getVm().getMigratingToVds(),
getVmId(), getParameters().getStopReason(), false, 0));
}
setActionReturnValue(runVdsCommand(
VDSCommandType.DestroyVm,
new DestroyVmVDSCommandParameters(getVdsId(), getVmId(),
getParameters().getStopReason(), false, 0)).getReturnValue());
}
@Override
protected void executeVmCommand() {
getParameters().setEntityInfo(new EntityInfo(VdcObjectType.VM, getVm().getId()));
String hiberVol = getActiveSnapshot().getMemoryVolume();
suspendedVm = getVm().getStatus() == VMStatus.Suspended;
if (suspendedVm) {
endVmCommand();
setCommandShouldBeLogged(true);
} else {
super.executeVmCommand();
}
removeMemoryDisksIfNeeded(hiberVol);
}
private void removeMemoryDisksIfNeeded(String hiberVol) {
if (StringUtils.isNotEmpty(hiberVol)) {
removeMemoryDisks(hiberVol);
}
}
@Override
protected void endVmCommand() {
setCommandShouldBeLogged(false);
if (getVm() == null) {
log.warn("VM is null, not performing full endAction");
setSucceeded(true);
return;
}
getVm().setStatus(VMStatus.Down);
snapshotDao.removeMemoryFromActiveSnapshot(getVmId());
vmDynamicDao.update(getVm().getDynamicData());
setSucceeded(true);
}
@Override
public List<QuotaConsumptionParameter> getQuotaVdsConsumptionParameters() {
List<QuotaConsumptionParameter> list = new ArrayList<>();
if (getVm().getQuotaId() != null && !Guid.Empty.equals(getVm().getQuotaId())
&& getQuotaManager().isVmStatusQuotaCountable(getVm().getStatus())) {
list.add(new QuotaClusterConsumptionParameter(getVm().getQuotaId(),
null,
QuotaConsumptionParameter.QuotaAction.RELEASE,
getVm().getClusterId(),
getVm().getCpuPerSocket() * getVm().getNumOfSockets(),
getVm().getMemSizeMb()));
}
return list;
}
@Override
public List<QuotaConsumptionParameter> getQuotaStorageConsumptionParameters() {
List<QuotaConsumptionParameter> list = new ArrayList<>();
if (!getVm().isStateless()) {
return list;
}
//if runAsStateless
for (DiskImage image : getVm().getDiskList()) {
if (image.getQuotaId() != null) {
list.add(new QuotaStorageConsumptionParameter(image.getQuotaId(), null,
QuotaConsumptionParameter.QuotaAction.RELEASE,
image.getStorageIds().get(0), image.getActualSize()));
}
}
return list;
}
@Override
public void addQuotaPermissionSubject(List<PermissionSubject> quotaPermissionList) {
//
}
@Override
protected boolean shouldSkipCommandExecution() {
return getVm() != null && getVm().getStatus() == VMStatus.Down;
}
protected AuditLogType logCommandExecutionSkipped(String actionName) {
addCustomValue("Action", actionName);
addCustomValue("VmStatus", getVm().getStatus().name());
return AuditLogType.VM_ALREADY_IN_REQUESTED_STATUS;
}
public String getOptionalReason() {
String reason = getParameters().getStopReason();
return reason != null && !reason.isEmpty() ? String.format(" (Reason: %s)", reason) : null;
}
}