package org.ovirt.engine.core.bll;
import java.util.List;
import java.util.Set;
import javax.inject.Inject;
import org.apache.commons.lang.StringUtils;
import org.ovirt.engine.core.bll.context.CommandContext;
import org.ovirt.engine.core.bll.numa.vm.NumaValidator;
import org.ovirt.engine.core.bll.profiles.CpuProfileHelper;
import org.ovirt.engine.core.common.FeatureSupported;
import org.ovirt.engine.core.common.action.VmManagementParametersBase;
import org.ovirt.engine.core.common.businessentities.ArchitectureType;
import org.ovirt.engine.core.common.businessentities.InstanceType;
import org.ovirt.engine.core.common.businessentities.MigrationSupport;
import org.ovirt.engine.core.common.businessentities.VDS;
import org.ovirt.engine.core.common.businessentities.VM;
import org.ovirt.engine.core.common.businessentities.VmDevice;
import org.ovirt.engine.core.common.businessentities.VmStatic;
import org.ovirt.engine.core.common.config.Config;
import org.ovirt.engine.core.common.config.ConfigValues;
import org.ovirt.engine.core.common.errors.EngineMessage;
import org.ovirt.engine.core.common.utils.CompatibilityVersionUtils;
import org.ovirt.engine.core.common.utils.customprop.VmPropertiesUtils;
import org.ovirt.engine.core.compat.Guid;
import org.ovirt.engine.core.compat.Version;
import org.ovirt.engine.core.dao.VdsDao;
import org.ovirt.engine.core.dao.VmTemplateDao;
public class VmManagementCommandBase<T extends VmManagementParametersBase> extends VmCommand<T> {
/**
* This is the maximum value we can pass to cpuShares according to
* the virsh man page.
*/
public static final int MAXIMUM_CPU_SHARES = 262144;
@Inject
private NumaValidator numaValidator;
@Inject
private CpuProfileHelper cpuProfileHelper;
@Inject
protected VmTemplateDao vmTemplateDao;
@Inject
private VdsDao vdsDao;
private InstanceType instanceType;
private Version effectiveCompatibilityVersion;
protected VmManagementCommandBase(Guid commandId) {
super(commandId);
}
public VmManagementCommandBase(T parameters, CommandContext commandContext) {
super(parameters, commandContext);
if (parameters.getVmStaticData() != null) {
setVmId(parameters.getVmStaticData().getId());
setClusterId(parameters.getVmStaticData().getClusterId());
}
}
@Override
protected void init() {
super.init();
initEffectiveCompatibilityVersion();
}
protected void initEffectiveCompatibilityVersion() {
setEffectiveCompatibilityVersion(
CompatibilityVersionUtils.getEffective(getParameters().getVmStaticData(), this::getCluster));
}
protected Guid getInstanceTypeId() {
if (getParameters().getVmStaticData() != null) {
return getParameters().getVmStaticData().getInstanceTypeId();
}
return null;
}
protected InstanceType getInstanceType() {
if (instanceType == null && getInstanceTypeId() != null) {
instanceType = vmTemplateDao.getInstanceType(getInstanceTypeId());
}
return instanceType;
}
protected Version getEffectiveCompatibilityVersion() {
return effectiveCompatibilityVersion;
}
protected void setEffectiveCompatibilityVersion(Version effectiveCompatibilityVersion) {
this.effectiveCompatibilityVersion = effectiveCompatibilityVersion;
}
protected VDS getVds(Guid id) {
return vdsDao.get(id);
}
protected boolean validateCustomProperties(VmStatic vmStaticFromParams, List<String> reasons) {
return VmPropertiesUtils.getInstance().validateVmProperties(
getEffectiveCompatibilityVersion(),
vmStaticFromParams.getCustomProperties(),
reasons);
}
static boolean validatePinningAndMigration(List<String> reasons, VmStatic vmStaticData, String cpuPinning) {
final boolean cpuPinMigrationEnabled = Boolean.TRUE.equals(Config.<Boolean> getValue(ConfigValues.CpuPinMigrationEnabled));
if (!cpuPinMigrationEnabled
&& (vmStaticData.getMigrationSupport() == MigrationSupport.MIGRATABLE
|| vmStaticData.getMigrationSupport() == MigrationSupport.IMPLICITLY_NON_MIGRATABLE)
&& StringUtils.isNotEmpty(cpuPinning)) {
reasons.add(EngineMessage.ACTION_TYPE_FAILED_VM_CANNOT_BE_PINNED_TO_CPU_AND_MIGRATABLE.toString());
return false;
}
if (vmStaticData.isAutoStartup()
// VM has to be either migratable
&& (vmStaticData.getMigrationSupport() != MigrationSupport.MIGRATABLE
// or have multiple hosts (no host means any host) in the pinning list
&& vmStaticData.getDedicatedVmForVdsList().size() == 1)) {
reasons.add(EngineMessage.ACTION_TYPE_FAILED_VM_CANNOT_BE_HIGHLY_AVAILABLE_AND_PINNED_TO_HOST.toString());
return false;
}
return true;
}
protected boolean isVmWithSameNameExists(String name, Guid storagePoolId) {
return VmHandler.isVmWithSameNameExistStatic(name, storagePoolId);
}
protected boolean isCpuSharesValid(VM vmData) {
return vmData.getCpuShares() >= 0 && vmData.getCpuShares() <= MAXIMUM_CPU_SHARES;
}
protected boolean setAndValidateCpuProfile() {
return validate(cpuProfileHelper.setAndValidateCpuProfile(
getParameters().getVm().getStaticData(),
getUserIdIfExternal().orElse(null)));
}
protected boolean validateCPUHotplug(VmStatic vmStaticData) {
if (getVm().isRunningOrPaused()) {
// Can't set more CPUs than available on the host where VM is running.
// Potential overcommit (interference with other running VMs) will be resolved by scheduler.
// In alignment with the CPUPolicyUnit, VM's hyperthreading is not considered.
if (getVds() != null && vmStaticData.getNumOfCpus(false) > getVds().getCpuThreads()) {
return false;
}
}
return true;
}
protected boolean validateMemoryAlignment(VmStatic vmStaticData) {
if (getCluster().getArchitecture().getFamily() == ArchitectureType.ppc && vmStaticData.getMemSizeMb() % 256 != 0) {
return failValidation(EngineMessage.MEMORY_SIZE_NOT_MULTIPLE_OF_256_ON_PPC,
String.format("$%s %s", "clusterArch", getCluster().getArchitecture()));
}
return true;
}
protected void updateParametersVmFromInstanceType() {
InstanceType instanceType = getInstanceType();
VmStatic vmStatic = getParameters().getVmStaticData();
if (instanceType != null) {
vmStatic.setMemSizeMb(instanceType.getMemSizeMb());
vmStatic.setNumOfSockets(instanceType.getNumOfSockets());
vmStatic.setCpuPerSocket(instanceType.getCpuPerSocket());
vmStatic.setThreadsPerCpu(instanceType.getThreadsPerCpu());
vmStatic.setAutoStartup(instanceType.isAutoStartup());
if (FeatureSupported.isMigrationSupported(getCluster().getArchitecture(), getEffectiveCompatibilityVersion())) {
vmStatic.setMigrationSupport(instanceType.getMigrationSupport());
}
vmStatic.setNumOfIoThreads(instanceType.getNumOfIoThreads());
vmStatic.setMigrationDowntime(instanceType.getMigrationDowntime());
vmStatic.setPriority(instanceType.getPriority());
vmStatic.setTunnelMigration(instanceType.getTunnelMigration());
List<VmDevice> vmDevices = getVmDeviceUtils().getMemoryBalloons(instanceType.getId());
vmStatic.setMinAllocatedMem(instanceType.getMinAllocatedMem());
if (vmDevices.isEmpty()) {
getParameters().setBalloonEnabled(false);
} else if (osRepository.isBalloonEnabled(getParameters().getVmStaticData().getOsId(), getEffectiveCompatibilityVersion())) {
getParameters().setBalloonEnabled(true);
}
vmStatic.setMigrationPolicyId(instanceType.getMigrationPolicyId());
}
}
protected NumaValidator getNumaValidator() {
return numaValidator;
}
protected static boolean isCompatibilityVersionSupportedByCluster(Version customCompatibilityVersion) {
return Config.<Set<Version>> getValue(ConfigValues.SupportedClusterLevels).contains(customCompatibilityVersion);
}
}