UEFI Implementation: Enabled UEFI Support for Guest VM's on Hypervisor KVM,VMware. enabled boot modes [Legacy,Secure] support for UEFI boot with known caveats. (#3638)

Co-authored-by: Pavan Kumar Aravapalli <pavan_aravapalli@accelerite.com>
Co-authored-by: dahn <daan.hoogland@shapeblue.com>
This commit is contained in:
pavanaravapalli 2020-03-14 01:26:26 +05:30 committed by GitHub
parent b9492807fd
commit d4b537efa7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
38 changed files with 700 additions and 13 deletions

View File

@ -63,6 +63,8 @@ public class VirtualMachineTO {
String vncAddr;
Map<String, String> params;
String uuid;
String bootType;
String bootMode;
DiskTO[] disks;
NicTO[] nics;
@ -380,4 +382,15 @@ public class VirtualMachineTO {
public void setOvfProperties(Pair<String, List<OVFPropertyTO>> ovfProperties) {
this.ovfProperties = ovfProperties;
}
public String getBootType() {
return bootType;
}
public void setBootType(String bootType) {
this.bootType = bootType;
}
public String getBootMode() { return bootMode; }
public void setBootMode(String bootMode) { this.bootMode = bootMode; }
}

View File

@ -52,6 +52,7 @@ public interface Host extends StateObject<Status>, Identity, Partition, HAResour
return strs;
}
}
public static final String HOST_UEFI_ENABLE = "host.uefi.enable";
/**
* @return name of the machine.

View File

@ -60,6 +60,9 @@ public interface VirtualMachineProfile {
public static final Param PxeSeverType = new Param("PxeSeverType");
public static final Param HaTag = new Param("HaTag");
public static final Param HaOperation = new Param("HaOperation");
public static final Param UefiFlag = new Param("UefiFlag");
public static final Param BootMode = new Param("BootMode");
public static final Param BootType = new Param("BootType");
private String name;

View File

@ -20,6 +20,7 @@ public interface VmDetailConstants {
String KEYBOARD = "keyboard";
String CPU_CORE_PER_SOCKET = "cpu.corespersocket";
String ROOT_DISK_SIZE = "rootdisksize";
String BOOT_MODE = "boot.mode";
// VMware specific
String NIC_ADAPTER = "nicAdapter";

View File

@ -804,6 +804,27 @@ public class ApiConstants {
public static final String NODE_ROOT_DISK_SIZE = "noderootdisksize";
public static final String SUPPORTS_HA = "supportsha";
public static final String BOOT_TYPE ="boottype";
public static final String BOOT_MODE ="bootmode";
public enum BootType {
UEFI, BIOS;
@Override
public String toString() {
return this.name();
}
}
public enum BootMode {
LEGACY, SECURE;
@Override
public String toString() {
return this.name();
}
}
public enum HostDetails {
all, capacity, events, stats, min;
}

View File

@ -17,6 +17,7 @@
package org.apache.cloudstack.api.command.user.vm;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
@ -26,6 +27,8 @@ import java.util.Map;
import javax.annotation.Nonnull;
import com.cloud.utils.StringUtils;
import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.affinity.AffinityGroupResponse;
import org.apache.cloudstack.api.ACL;
@ -110,6 +113,12 @@ public class DeployVMCmd extends BaseAsyncCreateCustomIdCmd implements SecurityG
@Parameter(name = ApiConstants.NETWORK_IDS, type = CommandType.LIST, collectionType = CommandType.UUID, entityType = NetworkResponse.class, description = "list of network ids used by virtual machine. Can't be specified with ipToNetworkList parameter")
private List<Long> networkIds;
@Parameter(name = ApiConstants.BOOT_TYPE, type = CommandType.STRING, required = false, description = "Guest VM Boot option either custom[UEFI] or default boot [BIOS]")
private String bootType;
@Parameter(name = ApiConstants.BOOT_MODE, type = CommandType.STRING, required = false, description = "Boot Mode [Legacy] or [Secure] Applicable when Boot Type Selected is UEFI, otherwise Legacy By default for BIOS")
private String bootMode;
//DataDisk information
@ACL
@Parameter(name = ApiConstants.DISK_OFFERING_ID, type = CommandType.UUID, entityType = DiskOfferingResponse.class, description = "the ID of the disk offering for the virtual machine. If the template is of ISO format,"
@ -244,6 +253,22 @@ public class DeployVMCmd extends BaseAsyncCreateCustomIdCmd implements SecurityG
return domainId;
}
private ApiConstants.BootType getBootType() {
if (StringUtils.isNotBlank(bootType)) {
try {
String type = bootType.trim().toUpperCase();
return ApiConstants.BootType.valueOf(type);
} catch (IllegalArgumentException e) {
String errMesg = "Invalid bootType " + bootType + "Specified for vm " + getName()
+ " Valid values are: " + Arrays.toString(ApiConstants.BootType.values());
s_logger.warn(errMesg);
throw new InvalidParameterValueException(errMesg);
}
}
return null;
}
public Map<String, String> getDetails() {
Map<String, String> customparameterMap = new HashMap<String, String>();
if (details != null && details.size() != 0) {
@ -256,12 +281,35 @@ public class DeployVMCmd extends BaseAsyncCreateCustomIdCmd implements SecurityG
}
}
}
if(getBootType() != null){ // export to get
if(getBootType() == ApiConstants.BootType.UEFI) {
customparameterMap.put(getBootType().toString(), getBootMode().toString());
}
}
if (rootdisksize != null && !customparameterMap.containsKey("rootdisksize")) {
customparameterMap.put("rootdisksize", rootdisksize.toString());
}
return customparameterMap;
}
public ApiConstants.BootMode getBootMode() {
if (StringUtils.isNotBlank(bootMode)) {
try {
String mode = bootMode.trim().toUpperCase();
return ApiConstants.BootMode.valueOf(mode);
} catch (IllegalArgumentException e) {
String errMesg = "Invalid bootMode " + bootMode + "Specified for vm " + getName()
+ " Valid values are: "+ Arrays.toString(ApiConstants.BootMode.values());
s_logger.warn(errMesg);
throw new InvalidParameterValueException(errMesg);
}
}
return null;
}
public Map<String, String> getVmOVFProperties() {
Map<String, String> map = new HashMap<>();
if (MapUtils.isNotEmpty(vmOvfProperties)) {

View File

@ -244,6 +244,10 @@ public class HostResponse extends BaseResponse {
@Param(description = "the admin that annotated this host", since = "4.11")
private String username;
@SerializedName("ueficapability")
@Param(description = "true if the host has capability to support UEFI boot")
private Boolean uefiCapabilty;
@Override
public String getObjectId() {
return this.getId();
@ -499,6 +503,14 @@ public class HostResponse extends BaseResponse {
detailsCopy.remove("username");
detailsCopy.remove("password");
if(detailsCopy.containsKey(Host.HOST_UEFI_ENABLE)) {
this.setUefiCapabilty(Boolean.parseBoolean((String) detailsCopy.get(Host.HOST_UEFI_ENABLE)));
detailsCopy.remove(Host.HOST_UEFI_ENABLE);
} else {
this.setUefiCapabilty(new Boolean(false)); // in case of existing host which is not scanned for UEFI capability
}
this.details = detailsCopy;
}
@ -668,4 +680,8 @@ public class HostResponse extends BaseResponse {
public Boolean getHaHost() {
return haHost;
}
public void setUefiCapabilty(Boolean hostCapability) {
this.uefiCapabilty = hostCapability;
}
}

View File

@ -298,6 +298,14 @@ public class UserVmResponse extends BaseResponseWithTagInformation implements Co
@Param(description = "OS type id of the vm", since = "4.4")
private String osTypeId;
@SerializedName(ApiConstants.BOOT_MODE)
@Param(description = "Guest vm Boot Mode")
private String bootMode;
@SerializedName(ApiConstants.BOOT_TYPE)
@Param(description = "Guest vm Boot Type")
private String bootType;
public UserVmResponse() {
securityGroupList = new LinkedHashSet<SecurityGroupResponse>();
nics = new LinkedHashSet<NicResponse>();
@ -873,4 +881,13 @@ public class UserVmResponse extends BaseResponseWithTagInformation implements Co
public String getOsTypeId() {
return osTypeId;
}
public String getBootType() { return bootType; }
public void setBootType(String bootType) { this.bootType = bootType; }
public String getBootMode() { return bootMode; }
public void setBootMode(String bootMode) { this.bootMode = bootMode; }
}

View File

@ -171,4 +171,10 @@ public interface VirtualMachineEntity extends CloudStackEntity {
* @param netowrk network to disconnect from
*/
void disconnectFrom(NetworkEntity netowrk, short nicId);
/**
* passing additional params of deployment associated with the virtual machine
*/
void setParamsToEntity(Map<VirtualMachineProfile.Param, Object> params);
}

View File

@ -1064,6 +1064,10 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
}
final VirtualMachineProfileImpl vmProfile = new VirtualMachineProfileImpl(vm, template, offering, owner, params);
s_logger.info(" Uefi params " + "UefiFlag: " + params.get(VirtualMachineProfile.Param.UefiFlag)
+ " Boot Type: " + params.get(VirtualMachineProfile.Param.BootType)
+ " Boot Mode: " + params.get(VirtualMachineProfile.Param.BootMode)
);
DeployDestination dest = null;
try {
dest = _dpMgr.planDeployment(vmProfile, plan, avoids, planner);

View File

@ -29,6 +29,7 @@ import org.apache.cloudstack.engine.cloud.entity.api.db.dao.VMEntityDao;
import org.apache.cloudstack.engine.cloud.entity.api.db.dao.VMReservationDao;
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager;
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
import org.apache.commons.collections.MapUtils;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Component;
@ -148,6 +149,15 @@ public class VMEntityManagerImpl implements VMEntityManager {
VMInstanceVO vm = _vmDao.findByUuid(vmEntityVO.getUuid());
VirtualMachineProfileImpl vmProfile = new VirtualMachineProfileImpl(vm);
vmProfile.setServiceOffering(_serviceOfferingDao.findByIdIncludingRemoved(vm.getId(), vm.getServiceOfferingId()));
if (MapUtils.isNotEmpty(vmEntityVO.getDetails()) &&
vmEntityVO.getDetails().containsKey(VirtualMachineProfile.Param.UefiFlag.getName()) &&
"yes".equalsIgnoreCase(vmEntityVO.getDetails().get(VirtualMachineProfile.Param.UefiFlag.getName())))
{
Map<String, String> details = vmEntityVO.getDetails();
vmProfile.getParameters().put(VirtualMachineProfile.Param.BootType, details.get(VirtualMachineProfile.Param.BootType.getName()));
vmProfile.getParameters().put(VirtualMachineProfile.Param.BootMode, details.get(VirtualMachineProfile.Param.BootMode.getName()));
vmProfile.getParameters().put(VirtualMachineProfile.Param.UefiFlag, details.get(VirtualMachineProfile.Param.UefiFlag.getName()));
}
DataCenterDeployment plan = new DataCenterDeployment(vm.getDataCenterId(), vm.getPodIdToDeployIn(), null, null, null, null);
if (planToDeploy != null && planToDeploy.getDataCenterId() != 0) {
plan =

View File

@ -20,9 +20,11 @@ import java.lang.reflect.Method;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.HashMap;
import javax.inject.Inject;
import org.apache.commons.collections.MapUtils;
import org.springframework.stereotype.Component;
import org.apache.cloudstack.engine.cloud.entity.api.db.VMEntityVO;
@ -269,4 +271,22 @@ public class VirtualMachineEntityImpl implements VirtualMachineEntity {
}
@Override
public void setParamsToEntity(Map<VirtualMachineProfile.Param, Object> map) {
if (MapUtils.isNotEmpty(map)) {
if (this.vmEntityVO != null) {
Map<String, String> details = this.vmEntityVO.getDetails();
if (details == null) {
details = new HashMap<String, String>();
}
for (Map.Entry<VirtualMachineProfile.Param, Object> entry : map.entrySet()) {
if (null != entry && null != entry.getValue() && null != entry.getKey()) {
details.put(entry.getKey().getName(), entry.getValue().toString());
}
}
this.vmEntityVO.setDetails(details);
}
}
}
}

View File

@ -112,5 +112,7 @@ public interface HostDao extends GenericDao<HostVO, Long>, StateDao<Status, Stat
List<HostVO> listAllHostsUpByZoneAndHypervisor(long zoneId, HypervisorType hypervisorType);
List<HostVO> listByHostCapability(Host.Type type, Long clusterId, Long podId, long dcId, String hostCapabilty);
List<HostVO> listByClusterAndHypervisorType(long clusterId, HypervisorType hypervisorType);
}

View File

@ -43,6 +43,7 @@ import com.cloud.dc.dao.ClusterDao;
import com.cloud.gpu.dao.HostGpuGroupsDao;
import com.cloud.gpu.dao.VGPUTypesDao;
import com.cloud.host.Host;
import com.cloud.host.DetailVO;
import com.cloud.host.Host.Type;
import com.cloud.host.HostTagVO;
import com.cloud.host.HostVO;
@ -1222,6 +1223,39 @@ public class HostDaoImpl extends GenericDaoBase<HostVO, Long> implements HostDao
}
@Override
public List<HostVO> listByHostCapability(Type type, Long clusterId, Long podId, long dcId, String hostCapabilty) {
SearchBuilder<DetailVO> hostCapabilitySearch = _detailsDao.createSearchBuilder();
DetailVO tagEntity = hostCapabilitySearch.entity();
hostCapabilitySearch.and("capability", tagEntity.getName(), SearchCriteria.Op.EQ);
hostCapabilitySearch.and("value", tagEntity.getValue(), SearchCriteria.Op.EQ);
SearchBuilder<HostVO> hostSearch = createSearchBuilder();
HostVO entity = hostSearch.entity();
hostSearch.and("type", entity.getType(), SearchCriteria.Op.EQ);
hostSearch.and("pod", entity.getPodId(), SearchCriteria.Op.EQ);
hostSearch.and("dc", entity.getDataCenterId(), SearchCriteria.Op.EQ);
hostSearch.and("cluster", entity.getClusterId(), SearchCriteria.Op.EQ);
hostSearch.and("status", entity.getStatus(), SearchCriteria.Op.EQ);
hostSearch.and("resourceState", entity.getResourceState(), SearchCriteria.Op.EQ);
hostSearch.join("hostCapabilitySearch", hostCapabilitySearch, entity.getId(), tagEntity.getHostId(), JoinBuilder.JoinType.INNER);
SearchCriteria<HostVO> sc = hostSearch.create();
sc.setJoinParameters("hostCapabilitySearch", "value", Boolean.toString(true));
sc.setJoinParameters("hostCapabilitySearch", "capability", hostCapabilty);
sc.setParameters("type", type.toString());
if (podId != null) {
sc.setParameters("pod", podId);
}
if (clusterId != null) {
sc.setParameters("cluster", clusterId);
}
sc.setParameters("dc", dcId);
sc.setParameters("status", Status.Up.toString());
sc.setParameters("resourceState", ResourceState.Enabled.toString());
return listBy(sc);
}
public List<HostVO> listByClusterAndHypervisorType(long clusterId, HypervisorType hypervisorType) {
SearchCriteria<HostVO> sc = ClusterHypervisorSearch.create();
sc.setParameters("clusterId", clusterId);

View File

@ -73,6 +73,7 @@ import com.cloud.exception.InsufficientServerCapacityException;
import com.cloud.gpu.dao.HostGpuGroupsDao;
import com.cloud.host.HostVO;
import com.cloud.host.dao.HostDao;
import com.cloud.host.dao.HostDetailsDao;
import com.cloud.host.dao.HostTagsDao;
import com.cloud.resource.ResourceManager;
import com.cloud.service.ServiceOfferingVO;
@ -573,6 +574,10 @@ public class ImplicitPlannerTest {
return Mockito.mock(DataStoreManager.class);
}
@Bean
public HostDetailsDao hostDetailsDao() { return Mockito.mock(HostDetailsDao.class); }
@Bean
public ClusterDetailsDao clusterDetailsDao() {
return Mockito.mock(ClusterDetailsDao.class);

View File

@ -224,6 +224,7 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
private String _dcId;
private String _pod;
private String _clusterId;
private final Properties _uefiProperties = new Properties();
private long _hvVersion;
private Duration _timeout;
@ -497,7 +498,6 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
public StorageSubsystemCommandHandler getStorageHandler() {
return storageHandler;
}
private static final class KeyValueInterpreter extends OutputInterpreter {
private final Map<String, String> map = new HashMap<String, String>();
@ -628,6 +628,11 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
if (!success) {
return false;
}
try {
loadUefiProperties();
} catch (FileNotFoundException e) {
s_logger.error("uefi properties file not found due to: " + e.getLocalizedMessage());
}
_storage = new JavaStorageLayer();
_storage.configure("StorageLayer", params);
@ -1150,6 +1155,31 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
return true;
}
private void loadUefiProperties() throws FileNotFoundException {
if (_uefiProperties != null && _uefiProperties.getProperty("guest.loader.legacy") != null) {
return;
}
final File file = PropertiesUtil.findConfigFile("uefi.properties");
if (file == null) {
throw new FileNotFoundException("Unable to find file uefi.properties.");
}
s_logger.info("uefi.properties file found at " + file.getAbsolutePath());
try {
PropertiesUtil.loadFromFile(_uefiProperties, file);
s_logger.info("guest.nvram.template.legacy = " + _uefiProperties.getProperty("guest.nvram.template.legacy"));
s_logger.info("guest.loader.legacy = " + _uefiProperties.getProperty("guest.loader.legacy"));
s_logger.info("guest.nvram.template.secure = " + _uefiProperties.getProperty("guest.nvram.template.secure"));
s_logger.info("guest.loader.secure =" + _uefiProperties.getProperty("guest.loader.secure"));
s_logger.info("guest.nvram.path = " + _uefiProperties.getProperty("guest.nvram.path"));
} catch (final FileNotFoundException ex) {
throw new CloudRuntimeException("Cannot find the file: " + file.getAbsolutePath(), ex);
} catch (final IOException ex) {
throw new CloudRuntimeException("IOException in reading " + file.getAbsolutePath(), ex);
}
}
protected void configureDiskActivityChecks(final Map<String, Object> params) {
_diskActivityCheckEnabled = Boolean.parseBoolean((String)params.get("vm.diskactivity.checkenabled"));
if (_diskActivityCheckEnabled) {
@ -2106,6 +2136,18 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
vm.setDomDescription(vmTO.getOs());
vm.setPlatformEmulator(vmTO.getPlatformEmulator());
Map<String, String> customParams = vmTO.getDetails();
boolean isUefiEnabled = false;
boolean isSecureBoot = false;
String bootMode =null;
if (MapUtils.isNotEmpty(customParams) && customParams.containsKey(GuestDef.BootType.UEFI.toString())) {
isUefiEnabled = true;
bootMode = customParams.get(GuestDef.BootType.UEFI.toString());
if (StringUtils.isNotBlank(bootMode) && "secure".equalsIgnoreCase(bootMode)) {
isSecureBoot = true;
}
}
Map<String, String> extraConfig = vmTO.getExtraConfig();
if (dpdkSupport && (!extraConfig.containsKey(DpdkHelper.DPDK_NUMA) || !extraConfig.containsKey(DpdkHelper.DPDK_HUGE_PAGES))) {
s_logger.info("DPDK is enabled but it needs extra configurations for CPU NUMA and Huge Pages for VM deployment");
@ -2125,11 +2167,44 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
}
guest.setGuestArch(_guestCpuArch != null ? _guestCpuArch : vmTO.getArch());
guest.setMachineType(_guestCpuArch != null && _guestCpuArch.equals("aarch64") ? "virt" : "pc");
guest.setBootType(GuestDef.BootType.BIOS);
if (MapUtils.isNotEmpty(customParams) && customParams.containsKey(GuestDef.BootType.UEFI.toString())) {
guest.setBootType(GuestDef.BootType.UEFI);
guest.setBootMode(GuestDef.BootMode.LEGACY);
if (StringUtils.isNotBlank(customParams.get(GuestDef.BootType.UEFI.toString())) && "secure".equalsIgnoreCase(customParams.get(GuestDef.BootType.UEFI.toString()))) {
guest.setMachineType("q35");
guest.setBootMode(GuestDef.BootMode.SECURE); // setting to secure mode
}
}
guest.setUuid(uuid);
guest.setBootOrder(GuestDef.BootOrder.CDROM);
guest.setBootOrder(GuestDef.BootOrder.HARDISK);
vm.addComp(guest);
if (isUefiEnabled) {
if (_uefiProperties.getProperty(GuestDef.GUEST_LOADER_SECURE) != null && "secure".equalsIgnoreCase(bootMode)) {
guest.setLoader(_uefiProperties.getProperty(GuestDef.GUEST_LOADER_SECURE));
}
if (_uefiProperties.getProperty(GuestDef.GUEST_LOADER_LEGACY) != null && "legacy".equalsIgnoreCase(bootMode)) {
guest.setLoader(_uefiProperties.getProperty(GuestDef.GUEST_LOADER_LEGACY));
}
if (_uefiProperties.getProperty(GuestDef.GUEST_NVRAM_PATH) != null) {
guest.setNvram(_uefiProperties.getProperty(GuestDef.GUEST_NVRAM_PATH));
}
if (isSecureBoot) {
if (_uefiProperties.getProperty(GuestDef.GUEST_NVRAM_TEMPLATE_SECURE) != null && "secure".equalsIgnoreCase(bootMode)) {
guest.setNvramTemplate(_uefiProperties.getProperty(GuestDef.GUEST_NVRAM_TEMPLATE_SECURE));
}
} else {
if (_uefiProperties.getProperty(GuestDef.GUEST_NVRAM_TEMPLATE_LEGACY) != null) {
guest.setNvramTemplate(_uefiProperties.getProperty(GuestDef.GUEST_NVRAM_TEMPLATE_LEGACY));
}
}
}
vm.addComp(guest);
final GuestResourceDef grd = new GuestResourceDef();
@ -2189,6 +2264,9 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
features.addFeatures("pae");
features.addFeatures("apic");
features.addFeatures("acpi");
if (isUefiEnabled && isSecureMode(customParams.get(GuestDef.BootType.UEFI.toString()))) {
features.addFeatures("smm");
}
//KVM hyperv enlightenment features based on OS Type
enlightenWindowsVm(vmTO, features);
@ -2329,7 +2407,10 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
}
public void createVbd(final Connect conn, final VirtualMachineTO vmSpec, final String vmName, final LibvirtVMDef vm) throws InternalErrorException, LibvirtException, URISyntaxException {
final Map<String, String> details = vmSpec.getDetails();
final List<DiskTO> disks = Arrays.asList(vmSpec.getDisks());
boolean isSecureBoot = false;
boolean isWindowsTemplate = false;
Collections.sort(disks, new Comparator<DiskTO>() {
@Override
public int compare(final DiskTO arg0, final DiskTO arg1) {
@ -2337,6 +2418,12 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
}
});
if (MapUtils.isNotEmpty(details) && details.containsKey(GuestDef.BootType.UEFI.toString())) {
isSecureBoot = isSecureMode(details.get(GuestDef.BootType.UEFI.toString()));
}
if (vmSpec.getOs().toLowerCase().contains("window")) {
isWindowsTemplate =true;
}
for (final DiskTO volume : disks) {
KVMPhysicalDisk physicalDisk = null;
KVMStoragePool pool = null;
@ -2397,8 +2484,12 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
int devId = volume.getDiskSeq().intValue();
if (volume.getType() == Volume.Type.ISO) {
if (volPath == null) {
/* Add iso as placeholder */
disk.defISODisk(null, devId);
if (isSecureBoot) {
disk.defISODisk(null, devId,isSecureBoot,isWindowsTemplate);
} else {
/* Add iso as placeholder */
disk.defISODisk(null, devId);
}
} else {
disk.defISODisk(volPath, devId);
}
@ -2436,7 +2527,11 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
if (volume.getType() == Volume.Type.DATADISK) {
disk.defFileBasedDisk(physicalDisk.getPath(), devId, diskBusTypeData, DiskDef.DiskFmtType.QCOW2);
} else {
disk.defFileBasedDisk(physicalDisk.getPath(), devId, diskBusType, DiskDef.DiskFmtType.QCOW2);
if (isSecureBoot) {
disk.defFileBasedDisk(physicalDisk.getPath(), devId, DiskDef.DiskFmtType.QCOW2, isWindowsTemplate);
} else {
disk.defFileBasedDisk(physicalDisk.getPath(), devId, diskBusType, DiskDef.DiskFmtType.QCOW2);
}
}
}
@ -4052,4 +4147,12 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
}
return true;
}
public boolean isSecureMode(String bootMode) {
if (StringUtils.isNotBlank(bootMode) && "secure".equalsIgnoreCase(bootMode)) {
return true;
}
return false;
}
}

View File

@ -57,7 +57,39 @@ public class LibvirtVMDef {
}
}
enum BootType {
UEFI("UEFI"), BIOS("BIOS");
String _type;
BootType(String type) {
_type = type;
}
@Override
public String toString() {
return _type;
}
}
enum BootMode {
LEGACY("LEGACY"), SECURE("SECURE");
String _mode;
BootMode(String mode) {
_mode = mode;
}
@Override
public String toString() {
return _mode;
}
}
private GuestType _type;
private BootType _boottype;
private BootMode _bootmode;
private String _arch;
private String _loader;
private String _kernel;
@ -67,6 +99,14 @@ public class LibvirtVMDef {
private String _uuid;
private final List<BootOrder> _bootdevs = new ArrayList<BootOrder>();
private String _machine;
private String _nvram;
private String _nvramTemplate;
public static final String GUEST_LOADER_SECURE = "guest.loader.secure";
public static final String GUEST_LOADER_LEGACY = "guest.loader.legacy";
public static final String GUEST_NVRAM_PATH = "guest.nvram.path";
public static final String GUEST_NVRAM_TEMPLATE_SECURE = "guest.nvram.template.secure";
public static final String GUEST_NVRAM_TEMPLATE_LEGACY = "guest.nvram.template.legacy";
public void setGuestType(GuestType type) {
_type = type;
@ -76,6 +116,10 @@ public class LibvirtVMDef {
return _type;
}
public void setNvram(String nvram) { _nvram = nvram; }
public void setNvramTemplate(String nvramTemplate) { _nvramTemplate = nvramTemplate; }
public void setGuestArch(String arch) {
_arch = arch;
}
@ -103,6 +147,22 @@ public class LibvirtVMDef {
_uuid = uuid;
}
public BootType getBootType() {
return _boottype;
}
public void setBootType(BootType boottype) {
this._boottype = boottype;
}
public BootMode getBootMode() {
return _bootmode;
}
public void setBootMode(BootMode bootmode) {
this._bootmode = bootmode;
}
@Override
public String toString() {
if (_type == GuestType.KVM) {
@ -128,6 +188,24 @@ public class LibvirtVMDef {
if (_arch != null && _arch.equals("aarch64")) {
guestDef.append("<loader readonly='yes' type='pflash'>/usr/share/AAVMF/AAVMF_CODE.fd</loader>\n");
}
if (_loader != null) {
if (_bootmode == BootMode.LEGACY) {
guestDef.append("<loader readonly='yes' secure='no' type='pflash'>" + _loader + "</loader>\n");
} else if (_bootmode == BootMode.SECURE) {
guestDef.append("<loader readonly='yes' secure='yes' type='pflash'>" + _loader + "</loader>\n");
}
}
if (_nvram != null) {
guestDef.append("<nvram ");
if (_nvramTemplate != null) {
guestDef.append("template='" + _nvramTemplate + "'>");
} else {
guestDef.append(">");
}
guestDef.append(_nvram);
guestDef.append(_uuid + ".fd</nvram>");
}
if (!_bootdevs.isEmpty()) {
for (BootOrder bo : _bootdevs) {
guestDef.append("<boot dev='" + bo + "'/>\n");
@ -276,7 +354,11 @@ public class LibvirtVMDef {
StringBuilder feaBuilder = new StringBuilder();
feaBuilder.append("<features>\n");
for (String feature : _features) {
feaBuilder.append("<" + feature + "/>\n");
if (feature.equalsIgnoreCase("smm")) {
feaBuilder.append("<" + feature + " state=\'on\' " + "/>\n");
} else {
feaBuilder.append("<" + feature + "/>\n");
}
}
if (hyperVEnlightenmentFeatureDef != null) {
String hpervF = hyperVEnlightenmentFeatureDef.toString();
@ -508,7 +590,7 @@ public class LibvirtVMDef {
}
public enum DiskBus {
IDE("ide"), SCSI("scsi"), VIRTIO("virtio"), XEN("xen"), USB("usb"), UML("uml"), FDC("fdc");
IDE("ide"), SCSI("scsi"), VIRTIO("virtio"), XEN("xen"), USB("usb"), UML("uml"), FDC("fdc"), SATA("sata");
String _bus;
DiskBus(String bus) {
@ -633,13 +715,17 @@ public class LibvirtVMDef {
return "sd" + getDevLabelSuffix(devId);
} else if (bus == DiskBus.VIRTIO) {
return "vd" + getDevLabelSuffix(devId);
} else if (bus == DiskBus.SATA){
if (!forIso) {
return "sda";
}
}
if (forIso) {
devId --;
} else if(devId >= 2) {
devId += 2;
}
return "hd" + getDevLabelSuffix(devId);
return (DiskBus.SATA == bus) ? "sdb" : "hd" + getDevLabelSuffix(devId);
}
@ -671,6 +757,23 @@ public class LibvirtVMDef {
}
public void defFileBasedDisk(String filePath, int devId, DiskFmtType diskFmtType,boolean isWindowsOS) {
_diskType = DiskType.FILE;
_deviceType = DeviceType.DISK;
_diskCacheMode = DiskCacheMode.NONE;
_sourcePath = filePath;
_diskFmtType = diskFmtType;
if (isWindowsOS) {
_diskLabel = getDevLabel(devId, DiskBus.SATA, false); // Windows Secure VM
_bus = DiskBus.SATA;
} else {
_diskLabel = getDevLabel(devId, DiskBus.VIRTIO, false); // Linux Secure VM
_bus = DiskBus.VIRTIO;
}
}
public void defISODisk(String volPath) {
_diskType = DiskType.FILE;
_deviceType = DeviceType.CDROM;
@ -695,6 +798,26 @@ public class LibvirtVMDef {
}
}
public void defISODisk(String volPath, Integer devId,boolean isSecure, boolean isWindowOs) {
if (!isSecure) {
defISODisk(volPath, devId);
} else {
_diskType = DiskType.FILE;
_deviceType = DeviceType.CDROM;
_sourcePath = volPath;
if (isWindowOs) {
_diskLabel = getDevLabel(devId, DiskBus.SATA, true);
_bus = DiskBus.SATA;
} else {
_diskLabel = getDevLabel(devId, DiskBus.SCSI, true);
_bus = DiskBus.SCSI;
}
_diskFmtType = DiskFmtType.RAW;
_diskCacheMode = DiskCacheMode.NONE;
}
}
public void defBlockBasedDisk(String diskName, int devId, DiskBus bus) {
_diskType = DiskType.BLOCK;
_deviceType = DeviceType.DISK;

View File

@ -294,6 +294,7 @@ public class VMwareGuru extends HypervisorGuruBase implements HypervisorGuru, Co
}
}
details.put(VmDetailConstants.BOOT_MODE, to.getBootType());
String diskDeviceType = details.get(VmDetailConstants.ROOT_DISK_CONTROLLER);
if (userVm) {
if (diskDeviceType == null) {

View File

@ -45,6 +45,7 @@ import com.cloud.exception.DiscoveredWithErrorException;
import com.cloud.exception.DiscoveryException;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.exception.ResourceInUseException;
import com.cloud.host.Host;
import com.cloud.host.HostVO;
import com.cloud.hypervisor.Hypervisor;
import com.cloud.hypervisor.Hypervisor.HypervisorType;
@ -367,6 +368,10 @@ public class VmwareServerDiscoverer extends DiscovererBase implements Discoverer
details.put("url", hostMo.getHostName());
details.put("username", username);
details.put("password", password);
boolean uefiLegacySupported = hostMo.isUefiLegacySupported();
if (uefiLegacySupported) {
details.put(Host.HOST_UEFI_ENABLE, "true");
}
String guid = morHost.getType() + ":" + morHost.getValue() + "@" + url.getHost();
details.put("guid", guid);

View File

@ -318,6 +318,7 @@ import com.vmware.vim25.VirtualEthernetCardNetworkBackingInfo;
import com.vmware.vim25.VirtualEthernetCardOpaqueNetworkBackingInfo;
import com.vmware.vim25.VirtualIDEController;
import com.vmware.vim25.VirtualMachineConfigSpec;
import com.vmware.vim25.VirtualMachineBootOptions;
import com.vmware.vim25.VirtualMachineFileInfo;
import com.vmware.vim25.VirtualMachineFileLayoutEx;
import com.vmware.vim25.VirtualMachineFileLayoutExFileInfo;
@ -1723,6 +1724,11 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
String dataDiskController = vmSpec.getDetails().get(VmDetailConstants.DATA_DISK_CONTROLLER);
String rootDiskController = vmSpec.getDetails().get(VmDetailConstants.ROOT_DISK_CONTROLLER);
DiskTO rootDiskTO = null;
String bootMode = ApiConstants.BootType.BIOS.toString();
if (vmSpec.getDetails().containsKey(VmDetailConstants.BOOT_MODE)) {
bootMode = vmSpec.getDetails().get(VmDetailConstants.BOOT_MODE);
}
// If root disk controller is scsi, then data disk controller would also be scsi instead of using 'osdefault'
// This helps avoid mix of different scsi subtype controllers in instance.
if (DiskControllerType.osdefault == DiskControllerType.getType(dataDiskController) && DiskControllerType.lsilogic == DiskControllerType.getType(rootDiskController)) {
@ -2280,6 +2286,16 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
}
}
if (!bootMode.equalsIgnoreCase(ApiConstants.BootType.BIOS.toString())) {
vmConfigSpec.setFirmware("efi");
if (vmSpec.getDetails().containsKey(ApiConstants.BootType.UEFI.toString()) && "secure".equalsIgnoreCase(vmSpec.getDetails().get(ApiConstants.BootType.UEFI.toString()))) {
VirtualMachineBootOptions bootOptions = new VirtualMachineBootOptions();
bootOptions.setEfiSecureBootEnabled(true);
vmConfigSpec.setBootOptions(bootOptions);
}
}
//
// Configure VM
//
@ -2772,6 +2788,9 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
private static void configCustomExtraOption(List<OptionValue> extraOptions, VirtualMachineTO vmSpec) {
// we no longer to validation anymore
for (Map.Entry<String, String> entry : vmSpec.getDetails().entrySet()) {
if (entry.getKey().equalsIgnoreCase(VmDetailConstants.BOOT_MODE)) {
continue;
}
OptionValue newVal = new OptionValue();
newVal.setKey(entry.getKey());
newVal.setValue(entry.getValue());

View File

@ -61,6 +61,9 @@ import com.cloud.utils.component.AdapterBase;
import com.cloud.vm.VirtualMachine;
import com.cloud.vm.VirtualMachineProfile;
import com.cloud.vm.dao.VMInstanceDao;
import com.cloud.vm.UserVmDetailVO;
import com.cloud.vm.dao.UserVmDetailsDao;
/**
* An allocator that tries to find a fit on a computing host. This allocator does not care whether or not the host supports routing.
@ -92,6 +95,8 @@ public class FirstFitAllocator extends AdapterBase implements HostAllocator {
CapacityManager _capacityMgr;
@Inject
CapacityDao _capacityDao;
@Inject
UserVmDetailsDao _userVmDetailsDao;
boolean _checkHvm = true;
protected String _allocationAlgorithm = "random";
@ -112,6 +117,16 @@ public class FirstFitAllocator extends AdapterBase implements HostAllocator {
VMTemplateVO template = (VMTemplateVO)vmProfile.getTemplate();
Account account = vmProfile.getOwner();
boolean isVMDeployedWithUefi = false;
UserVmDetailVO userVmDetailVO = _userVmDetailsDao.findDetail(vmProfile.getId(), "UEFI");
if(userVmDetailVO != null){
if ("secure".equalsIgnoreCase(userVmDetailVO.getValue()) || "legacy".equalsIgnoreCase(userVmDetailVO.getValue())) {
isVMDeployedWithUefi = true;
}
}
s_logger.info(" Guest VM is requested with Cusotm[UEFI] Boot Type "+ isVMDeployedWithUefi);
if (type == Host.Type.Storage) {
// FirstFitAllocator should be used for user VMs only since it won't care whether the host is capable of routing or not
return new ArrayList<Host>();
@ -123,11 +138,20 @@ public class FirstFitAllocator extends AdapterBase implements HostAllocator {
String hostTagOnOffering = offering.getHostTag();
String hostTagOnTemplate = template.getTemplateTag();
String hostTagUefi = "UEFI";
boolean hasSvcOfferingTag = hostTagOnOffering != null ? true : false;
boolean hasTemplateTag = hostTagOnTemplate != null ? true : false;
List<HostVO> clusterHosts = new ArrayList<HostVO>();
List<HostVO> hostsMatchingUefiTag = new ArrayList<HostVO>();
if(isVMDeployedWithUefi){
hostsMatchingUefiTag = _hostDao.listByHostCapability(type, clusterId, podId, dcId, Host.HOST_UEFI_ENABLE);
if (s_logger.isDebugEnabled()) {
s_logger.debug("Hosts with tag '" + hostTagUefi + "' are:" + hostsMatchingUefiTag);
}
}
String haVmTag = (String)vmProfile.getParameter(VirtualMachineProfile.Param.HaTag);
if (haVmTag != null) {
@ -175,6 +199,10 @@ public class FirstFitAllocator extends AdapterBase implements HostAllocator {
}
}
if (isVMDeployedWithUefi) {
clusterHosts.retainAll(hostsMatchingUefiTag);
}
// add all hosts that we are not considering to the avoid list
List<HostVO> allhostsInCluster = _hostDao.listAllUpAndEnabledNonHAHosts(type, clusterId, podId, dcId, null);
allhostsInCluster.removeAll(clusterHosts);

View File

@ -321,6 +321,15 @@ public class UserVmJoinDaoImpl extends GenericDaoBaseWithTagInformation<UserVmJo
(UserVmManager.DisplayVMOVFProperties.value() && userVmDetailVO.getName().startsWith(ApiConstants.OVF_PROPERTIES))) {
resourceDetails.put(userVmDetailVO.getName(), userVmDetailVO.getValue());
}
if ((ApiConstants.BootType.UEFI.toString()).equalsIgnoreCase(userVmDetailVO.getName())) {
userVmResponse.setBootType("Uefi");
userVmResponse.setBootMode(userVmDetailVO.getValue().toLowerCase());
}
}
if (vmDetails.size() == 0) {
userVmResponse.setBootType("Bios");
userVmResponse.setBootMode("legacy");
}
// Remove blacklisted settings if user is not admin
if (caller.getType() != Account.ACCOUNT_TYPE_ADMIN) {

View File

@ -30,10 +30,12 @@ import java.util.TreeSet;
import javax.inject.Inject;
import javax.naming.ConfigurationException;
import com.cloud.utils.StringUtils;
import com.cloud.utils.db.Filter;
import com.cloud.utils.fsm.StateMachine2;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.log4j.Logger;
import org.apache.cloudstack.affinity.AffinityGroupProcessor;
import org.apache.cloudstack.affinity.AffinityGroupService;
@ -271,6 +273,7 @@ StateListener<State, VirtualMachine.Event, VirtualMachine> {
}
String haVmTag = (String)vmProfile.getParameter(VirtualMachineProfile.Param.HaTag);
String uefiFlag = (String)vmProfile.getParameter(VirtualMachineProfile.Param.UefiFlag);
if (plan.getHostId() != null && haVmTag == null) {
Long hostIdSpecified = plan.getHostId();
@ -278,6 +281,14 @@ StateListener<State, VirtualMachine.Event, VirtualMachine> {
s_logger.debug("DeploymentPlan has host_id specified, choosing this host and making no checks on this host: " + hostIdSpecified);
}
HostVO host = _hostDao.findById(hostIdSpecified);
if (host != null && StringUtils.isNotBlank(uefiFlag) && "yes".equalsIgnoreCase(uefiFlag)) {
_hostDao.loadDetails(host);
if (MapUtils.isNotEmpty(host.getDetails()) && host.getDetails().containsKey(Host.HOST_UEFI_ENABLE) && "false".equalsIgnoreCase(host.getDetails().get(Host.HOST_UEFI_ENABLE))) {
s_logger.debug("Cannot deploy to specified host as host does n't support uefi vm deployment, returning.");
return null;
}
}
if (host == null) {
s_logger.debug("The specified host cannot be found");
} else if (avoids.shouldAvoid(host)) {

View File

@ -68,12 +68,15 @@ import com.cloud.vm.VirtualMachineProfile;
import com.cloud.vm.dao.UserVmDao;
import com.cloud.vm.dao.UserVmDetailsDao;
import com.cloud.vm.dao.VMInstanceDao;
import com.cloud.host.dao.HostDetailsDao;
public class FirstFitPlanner extends AdapterBase implements DeploymentClusterPlanner, Configurable, DeploymentPlanner {
private static final Logger s_logger = Logger.getLogger(FirstFitPlanner.class);
@Inject
protected HostDao hostDao;
@Inject
protected HostDetailsDao hostDetailsDao;
@Inject
protected DataCenterDao dcDao;
@Inject
protected HostPodDao podDao;
@ -187,8 +190,16 @@ public class FirstFitPlanner extends AdapterBase implements DeploymentClusterPla
if (clusterList != null && !clusterList.isEmpty()) {
ServiceOffering offering = vmProfile.getServiceOffering();
boolean nonUefiVMDeploy =false;
if (vmProfile.getParameters().containsKey(VirtualMachineProfile.Param.BootType)) {
if (vmProfile.getParameters().get(VirtualMachineProfile.Param.BootType).toString().equalsIgnoreCase("BIOS")) {
nonUefiVMDeploy = true;
}
}
// In case of non-GPU VMs, protect GPU enabled Hosts and prefer VM deployment on non-GPU Hosts.
if ((serviceOfferingDetailsDao.findDetail(offering.getId(), GPU.Keys.vgpuType.toString()) == null) && !(hostGpuGroupsDao.listHostIds().isEmpty())) {
if (((serviceOfferingDetailsDao.findDetail(offering.getId(), GPU.Keys.vgpuType.toString()) == null) && !(hostGpuGroupsDao.listHostIds().isEmpty())) || nonUefiVMDeploy) {
int requiredCpu = offering.getCpu() * offering.getSpeed();
long requiredRam = offering.getRamSize() * 1024L * 1024L;
reorderClustersBasedOnImplicitTags(clusterList, requiredCpu, requiredRam);
@ -205,7 +216,8 @@ public class FirstFitPlanner extends AdapterBase implements DeploymentClusterPla
List<Long> hostList = capacityDao.listHostsWithEnoughCapacity(requiredCpu, requiredRam, clusterId, Host.Type.Routing.toString());
if (!hostList.isEmpty() && implicitHostTags.length > 0) {
uniqueTags = new Long(hostTagsDao.getDistinctImplicitHostTags(hostList, implicitHostTags).size());
}
uniqueTags = uniqueTags + getHostsByCapability(hostList, Host.HOST_UEFI_ENABLE);
}
UniqueTagsInClusterMap.put(clusterId, uniqueTags);
}
Collections.sort(clusterList, new Comparator<Long>() {
@ -218,6 +230,19 @@ public class FirstFitPlanner extends AdapterBase implements DeploymentClusterPla
});
}
private Long getHostsByCapability(List<Long> hostList, String hostCapability) {
for (Long host : hostList) { //TODO: Fix this in single query instead of polling request for each Host
Map<String, String> details = hostDetailsDao.findDetails(host);
if (details.containsKey(Host.HOST_UEFI_ENABLE)) {
if (details.get(Host.HOST_UEFI_ENABLE).equalsIgnoreCase("Yes")) {
return new Long(1);
}
}
}
return new Long(0);
}
private List<Long> scanPodsForDestination(VirtualMachineProfile vmProfile, DeploymentPlan plan, ExcludeList avoid) {
ServiceOffering offering = vmProfile.getServiceOffering();

View File

@ -22,8 +22,6 @@ import java.util.UUID;
import javax.inject.Inject;
import com.cloud.network.dao.NetworkDetailVO;
import com.cloud.network.dao.NetworkDetailsDao;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.backup.Backup;
import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService;
@ -37,6 +35,8 @@ import com.cloud.agent.api.to.VirtualMachineTO;
import com.cloud.gpu.GPU;
import com.cloud.network.Networks.BroadcastDomainType;
import com.cloud.network.dao.NetworkDao;
import com.cloud.network.dao.NetworkDetailVO;
import com.cloud.network.dao.NetworkDetailsDao;
import com.cloud.network.dao.NetworkVO;
import com.cloud.offering.NetworkOffering;
import com.cloud.offering.ServiceOffering;
@ -47,6 +47,7 @@ import com.cloud.service.dao.ServiceOfferingDao;
import com.cloud.service.dao.ServiceOfferingDetailsDao;
import com.cloud.storage.StoragePool;
import com.cloud.utils.Pair;
import com.cloud.utils.StringUtils;
import com.cloud.utils.component.AdapterBase;
import com.cloud.vm.NicProfile;
import com.cloud.vm.NicVO;
@ -171,6 +172,11 @@ public abstract class HypervisorGuruBase extends AdapterBase implements Hypervis
offering.getRamSize() * 1024l * 1024l, null, null, vm.isHaEnabled(), vm.limitCpuUse(), vm.getVncPassword());
to.setBootArgs(vmProfile.getBootArgs());
String bootType = (String)vmProfile.getParameter(new VirtualMachineProfile.Param("BootType"));
if (StringUtils.isNotBlank(bootType)) {
to.setBootType(bootType);
}
List<NicProfile> nicProfiles = vmProfile.getNics();
NicTO[] nics = new NicTO[nicProfiles.size()];
int i = 0;

View File

@ -202,6 +202,7 @@ public abstract class LibvirtServerDiscoverer extends DiscovererBase implements
@Override
public Map<? extends ServerResource, Map<String, String>>
find(long dcId, Long podId, Long clusterId, URI uri, String username, String password, List<String> hostTags) throws DiscoveryException {
boolean isUefiSupported = false;
ClusterVO cluster = _clusterDao.findById(clusterId);
if (cluster == null || cluster.getHypervisorType() != getHypervisorType()) {
@ -256,6 +257,11 @@ public abstract class LibvirtServerDiscoverer extends DiscovererBase implements
return null;
}
if (SSHCmdHelper.sshExecuteCmd(sshConnection, "rpm -qa | grep -i ovmf", 3)) {
s_logger.debug("It's UEFI enabled KVM machine");
isUefiSupported = true;
}
List<PhysicalNetworkSetupInfo> netInfos = _networkMgr.getPhysicalNetworkInfo(dcId, getHypervisorType());
String kvmPrivateNic = null;
String kvmPublicNic = null;
@ -338,6 +344,7 @@ public abstract class LibvirtServerDiscoverer extends DiscovererBase implements
Map<String, String> hostDetails = connectedHost.getDetails();
hostDetails.put("password", password);
hostDetails.put("username", username);
hostDetails.put(Host.HOST_UEFI_ENABLE, isUefiSupported == true ? Boolean.toString(true) : Boolean.toString(false));
_hostDao.saveDetails(connectedHost);
return resources;
} catch (DiscoveredWithErrorException e) {

View File

@ -709,6 +709,8 @@ import com.cloud.vm.dao.InstanceGroupDao;
import com.cloud.vm.dao.SecondaryStorageVmDao;
import com.cloud.vm.dao.UserVmDao;
import com.cloud.vm.dao.VMInstanceDao;
import com.cloud.vm.UserVmDetailVO;
import com.cloud.vm.dao.UserVmDetailsDao;
public class ManagementServerImpl extends ManagerBase implements ManagementServer, Configurable {
public static final Logger s_logger = Logger.getLogger(ManagementServerImpl.class.getName());
@ -728,6 +730,8 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
@Inject
private ClusterDao _clusterDao;
@Inject
private UserVmDetailsDao _UserVmDetailsDao;
@Inject
private SecondaryStorageVmDao _secStorageVmDao;
@Inject
public EventDao _eventDao;
@ -1191,6 +1195,16 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
throw ex;
}
UserVmDetailVO userVmDetailVO = _UserVmDetailsDao.findDetail(vm.getId(), ApiConstants.BootType.UEFI.toString());
if (userVmDetailVO != null) {
s_logger.info(" Live Migration of UEFI enabled VM : " + vm.getInstanceName() + " is not supported");
if ("legacy".equalsIgnoreCase(userVmDetailVO.getValue()) || "secure".equalsIgnoreCase(userVmDetailVO.getValue())) {
// Return empty list.
return new Ternary<Pair<List<? extends Host>, Integer>, List<? extends Host>, Map<Host, Boolean>>(new Pair<List<? extends Host>,
Integer>(new ArrayList<HostVO>(), new Integer(0)), new ArrayList<Host>(), new HashMap<Host, Boolean>());
}
}
if (_serviceOfferingDetailsDao.findDetail(vm.getServiceOfferingId(), GPU.Keys.pciDevice.toString()) != null) {
s_logger.info(" Live Migration of GPU enabled VM : " + vm.getInstanceName() + " is not supported");
// Return empty list.

View File

@ -3963,6 +3963,11 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
} else {
vm.setDetail(key, customParameters.get(key));
}
if (key.equalsIgnoreCase(ApiConstants.BootType.UEFI.toString())) {
vm.setDetail(key, customParameters.get(key));
continue;
}
}
vm.setDetail(VmDetailConstants.DEPLOY_VM, "true");
@ -4282,13 +4287,21 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
Long podId = null;
Long clusterId = null;
Long hostId = cmd.getHostId();
Map<VirtualMachineProfile.Param, Object> additonalParams = null;
Map<Long, DiskOffering> diskOfferingMap = cmd.getDataDiskTemplateToDiskOfferingMap();
if (cmd instanceof DeployVMCmdByAdmin) {
DeployVMCmdByAdmin adminCmd = (DeployVMCmdByAdmin)cmd;
podId = adminCmd.getPodId();
clusterId = adminCmd.getClusterId();
}
return startVirtualMachine(vmId, podId, clusterId, hostId, diskOfferingMap, null, cmd.getDeploymentPlanner());
if (MapUtils.isNotEmpty(cmd.getDetails()) && cmd.getDetails().containsKey(ApiConstants.BootType.UEFI.toString())) {
additonalParams = new HashMap<VirtualMachineProfile.Param, Object>();
Map<String, String> map = cmd.getDetails();
additonalParams.put(VirtualMachineProfile.Param.UefiFlag, "Yes");
additonalParams.put(VirtualMachineProfile.Param.BootType, ApiConstants.BootType.UEFI.toString());
additonalParams.put(VirtualMachineProfile.Param.BootMode, map.get(ApiConstants.BootType.UEFI.toString()));
}
return startVirtualMachine(vmId, podId, clusterId, hostId, diskOfferingMap, additonalParams, cmd.getDeploymentPlanner());
}
private UserVm startVirtualMachine(long vmId, Long podId, Long clusterId, Long hostId, Map<Long, DiskOffering> diskOfferingMap, Map<VirtualMachineProfile.Param, Object> additonalParams, String deploymentPlannerToUse)
@ -4747,6 +4760,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
throw new InvalidParameterValueException("Can't find a planner by name " + deploymentPlannerToUse);
}
}
vmEntity.setParamsToEntity(additionalParams);
String reservationId = vmEntity.reserve(planner, plan, new ExcludeList(), Long.toString(callerUser.getId()));
vmEntity.deploy(reservationId, Long.toString(callerUser.getId()), params, deployOnGivenHost);

View File

@ -102,6 +102,7 @@ import com.cloud.utils.component.ComponentContext;
import com.cloud.vm.dao.UserVmDao;
import com.cloud.vm.dao.UserVmDetailsDao;
import com.cloud.vm.dao.VMInstanceDao;
import com.cloud.host.dao.HostDetailsDao;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(loader = AnnotationConfigContextLoader.class)
@ -284,6 +285,12 @@ public class DeploymentPlanningManagerImplTest {
return Mockito.mock(HostTagsDao.class);
}
@Bean
public HostDetailsDao hostDetailsDao() {
return Mockito.mock(HostDetailsDao.class);
}
@Bean
public ClusterDetailsDao clusterDetailsDao() {
return Mockito.mock(ClusterDetailsDao.class);

View File

@ -95,6 +95,7 @@ import com.cloud.utils.component.ComponentContext;
import com.cloud.vm.dao.UserVmDao;
import com.cloud.vm.dao.UserVmDetailsDao;
import com.cloud.vm.dao.VMInstanceDao;
import com.cloud.host.dao.HostDetailsDao;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(loader = AnnotationConfigContextLoader.class)
@ -109,6 +110,8 @@ public class FirstFitPlannerTest {
@Inject
UserVmDao vmDao;
@Inject
HostDetailsDao hostDetailsDao;
@Inject
UserVmDetailsDao vmDetailsDao;
@Inject
ConfigurationDao configDao;
@ -355,6 +358,9 @@ public class FirstFitPlannerTest {
return Mockito.mock(HostTagsDao.class);
}
@Bean
public HostDetailsDao hostDetailsDao() { return Mockito.mock(HostDetailsDao.class); }
@Bean
public HostGpuGroupsDao hostGpuGroupsDao() {
return Mockito.mock(HostGpuGroupsDao.class);

View File

@ -480,6 +480,31 @@
</div>
</div>
<!-- UEFI Boot -->
<div class="select" odd>
<div class="name">
<span><translate key="label.vm.boottype" /></span>
</div>
<div class="value">
<select name="customboot" id="customboot">
<option value="BIOS">BIOS</option>
<option value="UEFI">UEFI</option>
</select>
</div>
</div>
<div class="select field hide-if-unselected">
<div class="name">
<span><translate key="label.vm.bootmode" /></span>
</div>
<div class="value">
<select name="bootmode" id="bootmode">
<option value="LEGACY">LEGACY</option>
</select>
</div>
</div>
<!-- Zone -->
<div class="select">
<div class="name">

View File

@ -893,6 +893,7 @@ var dictionary = {
"label.host.name":"Host Name",
"label.host.tag":"Host Tag",
"label.host.tags":"Host Tags",
"label.host.ueficapability":"UEFI Supported",
"label.hosts":"Hosts",
"label.hourly":"Hourly",
"label.hvm":"HVM",
@ -990,6 +991,8 @@ var dictionary = {
"label.keep.colon":"Keep:",
"label.key":"Key",
"label.keyboard.language":"Keyboard language",
"label.vm.boottype":"Boot Type",
"label.vm.bootmode":"Boot Mode",
"label.keyboard.type":"Keyboard type",
"label.kubernetes.cluster":"Kubernetes cluster",
"label.kubernetes.cluster.details":"Kubernetes cluster details",

View File

@ -1399,6 +1399,18 @@
keyboard : keyboard
});
}
var boottype = args.data.customboot;
if (boottype != null && boottype.length > 0) {
$.extend(deployVmData, {
boottype : boottype
});
}
var bootmode = args.data.bootmode;
if (bootmode != null && bootmode.length > 0) {
$.extend(deployVmData, {
bootmode : bootmode
});
}
if (g_hostid != null) {
$.extend(deployVmData, {

View File

@ -3322,6 +3322,12 @@
},
id: {
label: 'label.id'
},
boottype: {
label: 'label.vm.boottype'
},
bootmode: {
label: 'label.vm.bootmode'
}
}],

View File

@ -18024,6 +18024,10 @@
});
}
},
ueficapability: {
label:'label.host.ueficapability',
converter: cloudStack.converters.toBooleanText
},
hahost: {
label: 'label.ha.enabled',
converter: cloudStack.converters.toBooleanText

View File

@ -1392,6 +1392,50 @@
$(this).closest('div.select').hide();
}
}
var uefi = function(bootType){
var $bootmode = $step.find('select[name=bootmode]');
if(bootType.toLowerCase() == 'uefi' ){
$bootmode.html('');
var $option = $('<option>');
var id = 'LEGACY';
var description = 'LEGACY';
$option.attr('value', id);
$option.html(description);
$option.appendTo($bootmode);
var $option2 = $('<option>');
var id2 = 'SECURE';
var description2 = 'SECURE';
$option2.attr('value', id2);
$option2.html(description2);
$option2.appendTo($bootmode);
}
if(bootType.toLowerCase() == 'bios' ){
$bootmode.html('');
var $option = $('<option>');
var id = 'LEGACY';
var description = 'LEGACY';
$option.attr('value', id);
$option.html(description);
$option.appendTo($bootmode);
}
}
var $uefiselect = $step.find('select[name=customboot]');
$uefiselect.unbind('change');
$uefiselect.change(function(){
uefi($uefiselect.val());
});
});
}
};

View File

@ -1196,4 +1196,17 @@ public class HostMO extends BaseMO implements VmwareHypervisorHost {
}
return morNetwork;
}
public String getProductVersion() throws Exception {
return getHostAboutInfo().getVersion();
}
public boolean isUefiLegacySupported() throws Exception {
String hostVersion = getProductVersion();
if (hostVersion.compareTo(VmwareHelper.MIN_VERSION_UEFI_LEGACY) >= 0) {
return true;
}
return false;
}
}

View File

@ -92,6 +92,7 @@ public class VmwareHelper {
public static final int MAX_IDE_CONTROLLER_COUNT = 2;
public static final int MAX_ALLOWED_DEVICES_IDE_CONTROLLER = 2;
public static final int MAX_ALLOWED_DEVICES_SCSI_CONTROLLER = 15;
public static final String MIN_VERSION_UEFI_LEGACY = "5.5";
public static boolean isReservedScsiDeviceNumber(int deviceNumber) {
return deviceNumber == 7;