package org.ovirt.engine.core.bll;
import java.util.ArrayList;
import java.util.LinkedList;
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.job.ExecutionContext;
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.utils.PermissionSubject;
import org.ovirt.engine.core.common.VdcObjectType;
import org.ovirt.engine.core.common.action.LockProperties;
import org.ovirt.engine.core.common.action.LockProperties.Scope;
import org.ovirt.engine.core.common.action.RunVmOnceParams;
import org.ovirt.engine.core.common.action.SysPrepParams;
import org.ovirt.engine.core.common.businessentities.ActionGroup;
import org.ovirt.engine.core.common.businessentities.GraphicsInfo;
import org.ovirt.engine.core.common.businessentities.GraphicsType;
import org.ovirt.engine.core.common.businessentities.VMStatus;
import org.ovirt.engine.core.common.businessentities.VmBase;
import org.ovirt.engine.core.common.businessentities.VmDevice;
import org.ovirt.engine.core.common.businessentities.VmDeviceGeneralType;
import org.ovirt.engine.core.common.businessentities.VmPayload;
import org.ovirt.engine.core.common.businessentities.storage.DiskImage;
import org.ovirt.engine.core.common.errors.EngineMessage;
import org.ovirt.engine.core.common.vdscommands.CreateVDSCommandParameters;
import org.ovirt.engine.core.compat.Guid;
import org.ovirt.engine.core.dao.VmDeviceDao;
import org.ovirt.engine.core.dao.VmDynamicDao;
@NonTransactiveCommandAttribute
public class RunVmOnceCommand<T extends RunVmOnceParams> extends RunVmCommand<T> implements QuotaStorageDependent {
@Inject
private VmDeviceDao vmDeviceDao;
@Inject
private VmDynamicDao vmDynamicDao;
public RunVmOnceCommand(T runVmParams, CommandContext commandContext) {
super(runVmParams, commandContext);
}
@Override
protected void init() {
if (getVm() == null) {
return;
}
super.init();
if (getParameters().getCustomCpuName() != null) {
getVm().setCpuName(getParameters().getCustomCpuName());
}
if (getParameters().getCustomEmulatedMachine() != null) {
getVm().setEmulatedMachine(getParameters().getCustomEmulatedMachine());
}
if (getParameters().getBootMenuEnabled() != null) {
getVm().setBootMenuEnabled(getParameters().getBootMenuEnabled());
}
if (getParameters().getSpiceFileTransferEnabled() != null) {
getVm().setSpiceFileTransferEnabled(getParameters().getSpiceFileTransferEnabled());
}
if (getParameters().getSpiceCopyPasteEnabled() != null) {
getVm().setSpiceCopyPasteEnabled(getParameters().getSpiceCopyPasteEnabled());
}
if (getParameters().getBootSequence() != null) {
getVm().setBootSequence(getParameters().getBootSequence());
}
getVm().setInitrdUrl(getParameters().getInitrdUrl());
getVm().setKernelUrl(getParameters().getKernelUrl());
getVm().setKernelParams(getParameters().getKernelParams());
getVm().setCustomProperties(getParameters().getCustomProperties());
getVm().setRunOnce(true);
}
@Override
protected LockProperties applyLockProperties(LockProperties lockProperties) {
return lockProperties.withScope(Scope.Execution);
}
@Override
protected boolean validate() {
if (!super.validate()) {
return false;
}
// the condition allows to get only user and password which are both set (even with empty string) or both aren't
// set (null), the action will fail if only one of those parameters is null.
if (getParameters().getSysPrepUserName() == null ^ getParameters().getSysPrepPassword() == null) {
return failValidation(EngineMessage.VM_CANNOT_RUN_ONCE_WITH_ILLEGAL_SYSPREP_PARAM);
}
if (getParameters().getVmInit() != null && getParameters().getVmInit().isPasswordAlreadyStored()) {
VmBase temp = new VmBase();
temp.setId(getParameters().getVmId());
vmHandler.updateVmInitFromDB(temp, false);
getParameters().getVmInit().setRootPassword(temp.getVmInit().getRootPassword());
}
return true;
}
@Override
protected void loadPayload() {
List<VmDevice> disks = vmDeviceDao.getVmDeviceByVmIdAndType(getParameters().getVmId(), VmDeviceGeneralType.DISK);
for (VmDevice disk : disks) {
if (VmPayload.isPayload(disk.getSpecParams())) {
vmPayload = new VmPayload(disk);
break;
}
}
}
@Override
protected List<Guid> getPredefinedVdsIdListToRunOn() {
// destination VDS ID has priority over the dedicated VDS
if (getParameters().getDestinationVdsId() != null){
List<Guid> destIdList = new LinkedList<>();
destIdList.add(getParameters().getDestinationVdsId());
return destIdList;
}
return super.getPredefinedVdsIdListToRunOn();
}
@Override
protected CreateVDSCommandParameters buildCreateVmParameters() {
CreateVDSCommandParameters createVmParams = super.buildCreateVmParameters();
SysPrepParams sysPrepParams = new SysPrepParams();
sysPrepParams.setSysPrepDomainName(getParameters().getSysPrepDomainName());
sysPrepParams.setSysPrepUserName(getParameters().getSysPrepUserName());
sysPrepParams.setSysPrepPassword(getParameters().getSysPrepPassword());
createVmParams.setSysPrepParams(sysPrepParams);
if (getParameters().getVmInit() != null) {
createVmParams.getVm().setVmInit(getParameters().getVmInit());
}
return createVmParams;
}
/**
* This method sets graphics & video devices info of a VM to correspond to graphics set & display type in Run Once.
*/
@Override
protected void updateGraphicsAndDisplayInfos() {
// graphics devices
if (getParameters().getRunOnceGraphics().isEmpty() && getParameters().getRunOnceDisplayType() == null) {
// configure from DB
super.updateGraphicsAndDisplayInfos();
} else {
// configure from params
for (GraphicsType graphicsType : getParameters().getRunOnceGraphics()) {
getVm().getGraphicsInfos().put(graphicsType, new GraphicsInfo());
}
}
// video devices
getVm().setDefaultDisplayType(getParameters().getRunOnceDisplayType());
}
@Override
protected void endExecutionMonitoring() {
ExecutionContext executionContext = getExecutionContext();
executionContext.setShouldEndJob(true);
boolean runAndPausedSucceeded =
Boolean.TRUE.equals(getParameters().getRunAndPause())
&& vmDynamicDao.get(getVmId()).getStatus() == VMStatus.Paused;
executionHandler.endJob(executionContext, runAndPausedSucceeded);
}
@Override
public List<QuotaConsumptionParameter> getQuotaStorageConsumptionParameters() {
List<QuotaConsumptionParameter> list = new ArrayList<>();
//if runAsStateless
if (isRunAsStateless()) {
for (DiskImage image : getVm().getDiskList()) {
list.add(new QuotaStorageConsumptionParameter(image.getQuotaId(), null,
QuotaConsumptionParameter.QuotaAction.CONSUME,
image.getStorageIds().get(0), image.getActualSize()));
}
}
return list;
}
@Override
protected List<Guid> getVdsWhiteList() {
if (getPredefinedVdsIdListToRunOn().size() > 0){
return getPredefinedVdsIdListToRunOn();
}
return super.getVdsWhiteList();
}
@Override
protected void initVm() {
super.initVm();
if (getParameters().getVncKeyboardLayout() == null) {
getVm().getDynamicData().setVncKeyboardLayout(getVm().getDefaultVncKeyboardLayout());
} else {
// if is not null it means runVM was launch from the run once command, thus
// the VM can run with keyboard layout type which is different from its default display type
getVm().getDynamicData().setVncKeyboardLayout(getParameters().getVncKeyboardLayout());
}
if (getParameters().getVmInit() != null) {
getVm().setVmInit(getParameters().getVmInit());
}
}
@Override
protected boolean isVmRunningOnNonDefaultVds() {
return getParameters().getDestinationVdsId() == null
&& super.isVmRunningOnNonDefaultVds();
}
@Override
public List<PermissionSubject> getPermissionCheckSubjects() {
final List<PermissionSubject> permissionList = super.getPermissionCheckSubjects();
// special permission is needed to change custom properties
if (!StringUtils.isEmpty(getParameters().getCustomProperties())) {
permissionList.add(new PermissionSubject(getParameters().getVmId(),
VdcObjectType.VM,
ActionGroup.CHANGE_VM_CUSTOM_PROPERTIES));
}
// check, if user can override default target host for VM
if (getVm() != null) {
final Guid destinationVdsId = getParameters().getDestinationVdsId();
if (destinationVdsId != null && !getVm().getDedicatedVmForVdsList().contains(destinationVdsId)) {
permissionList.add(new PermissionSubject(getParameters().getVmId(),
VdcObjectType.VM,
ActionGroup.EDIT_ADMIN_VM_PROPERTIES));
}
}
return permissionList;
}
}