You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by an...@apache.org on 2020/03/13 19:56:41 UTC
[cloudstack] branch master updated: 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)
This is an automated email from the ASF dual-hosted git repository.
andrijapanic pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/cloudstack.git
The following commit(s) were added to refs/heads/master by this push:
new d4b537e 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)
d4b537e is described below
commit d4b537efa7ed27ef88b735a22493808b61529186
Author: pavanaravapalli <pa...@accelerite.com>
AuthorDate: Sat Mar 14 01:26:26 2020 +0530
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 <pa...@accelerite.com>
Co-authored-by: dahn <da...@shapeblue.com>
---
.../com/cloud/agent/api/to/VirtualMachineTO.java | 13 +++
api/src/main/java/com/cloud/host/Host.java | 1 +
.../java/com/cloud/vm/VirtualMachineProfile.java | 3 +
.../main/java/com/cloud/vm/VmDetailConstants.java | 1 +
.../org/apache/cloudstack/api/ApiConstants.java | 21 ++++
.../api/command/user/vm/DeployVMCmd.java | 48 ++++++++
.../cloudstack/api/response/HostResponse.java | 16 +++
.../cloudstack/api/response/UserVmResponse.java | 17 +++
.../cloud/entity/api/VirtualMachineEntity.java | 6 +
.../com/cloud/vm/VirtualMachineManagerImpl.java | 4 +
.../cloud/entity/api/VMEntityManagerImpl.java | 10 ++
.../cloud/entity/api/VirtualMachineEntityImpl.java | 20 ++++
.../src/main/java/com/cloud/host/dao/HostDao.java | 2 +
.../main/java/com/cloud/host/dao/HostDaoImpl.java | 34 ++++++
.../implicitplanner/ImplicitPlannerTest.java | 5 +
.../kvm/resource/LibvirtComputingResource.java | 113 +++++++++++++++++-
.../hypervisor/kvm/resource/LibvirtVMDef.java | 129 ++++++++++++++++++++-
.../java/com/cloud/hypervisor/guru/VMwareGuru.java | 1 +
.../hypervisor/vmware/VmwareServerDiscoverer.java | 5 +
.../hypervisor/vmware/resource/VmwareResource.java | 19 +++
.../manager/allocator/impl/FirstFitAllocator.java | 28 +++++
.../com/cloud/api/query/dao/UserVmJoinDaoImpl.java | 9 ++
.../deploy/DeploymentPlanningManagerImpl.java | 11 ++
.../java/com/cloud/deploy/FirstFitPlanner.java | 29 ++++-
.../com/cloud/hypervisor/HypervisorGuruBase.java | 10 +-
.../kvm/discoverer/LibvirtServerDiscoverer.java | 7 ++
.../com/cloud/server/ManagementServerImpl.java | 14 +++
.../main/java/com/cloud/vm/UserVmManagerImpl.java | 16 ++-
.../vm/DeploymentPlanningManagerImplTest.java | 7 ++
.../java/com/cloud/vm/FirstFitPlannerTest.java | 6 +
ui/index.html | 25 ++++
ui/l10n/en.js | 3 +
ui/scripts/instanceWizard.js | 12 ++
ui/scripts/instances.js | 6 +
ui/scripts/system.js | 4 +
ui/scripts/ui-custom/instanceWizard.js | 44 +++++++
.../com/cloud/hypervisor/vmware/mo/HostMO.java | 13 +++
.../cloud/hypervisor/vmware/util/VmwareHelper.java | 1 +
38 files changed, 700 insertions(+), 13 deletions(-)
diff --git a/api/src/main/java/com/cloud/agent/api/to/VirtualMachineTO.java b/api/src/main/java/com/cloud/agent/api/to/VirtualMachineTO.java
index d25ffe3..40f30df 100644
--- a/api/src/main/java/com/cloud/agent/api/to/VirtualMachineTO.java
+++ b/api/src/main/java/com/cloud/agent/api/to/VirtualMachineTO.java
@@ -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; }
}
diff --git a/api/src/main/java/com/cloud/host/Host.java b/api/src/main/java/com/cloud/host/Host.java
index 1ecd48d..e5a3889 100644
--- a/api/src/main/java/com/cloud/host/Host.java
+++ b/api/src/main/java/com/cloud/host/Host.java
@@ -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.
diff --git a/api/src/main/java/com/cloud/vm/VirtualMachineProfile.java b/api/src/main/java/com/cloud/vm/VirtualMachineProfile.java
index 977e27e..1abc764 100644
--- a/api/src/main/java/com/cloud/vm/VirtualMachineProfile.java
+++ b/api/src/main/java/com/cloud/vm/VirtualMachineProfile.java
@@ -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;
diff --git a/api/src/main/java/com/cloud/vm/VmDetailConstants.java b/api/src/main/java/com/cloud/vm/VmDetailConstants.java
index 7c40a7b..3812aa2 100644
--- a/api/src/main/java/com/cloud/vm/VmDetailConstants.java
+++ b/api/src/main/java/com/cloud/vm/VmDetailConstants.java
@@ -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";
diff --git a/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java b/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java
index 0482364..2a201db 100644
--- a/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java
+++ b/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java
@@ -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;
}
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/vm/DeployVMCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/DeployVMCmd.java
index 60b9f31..db315cc 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/vm/DeployVMCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/DeployVMCmd.java
@@ -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)) {
diff --git a/api/src/main/java/org/apache/cloudstack/api/response/HostResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/HostResponse.java
index cd70af1..7b47f8a 100644
--- a/api/src/main/java/org/apache/cloudstack/api/response/HostResponse.java
+++ b/api/src/main/java/org/apache/cloudstack/api/response/HostResponse.java
@@ -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;
+ }
}
diff --git a/api/src/main/java/org/apache/cloudstack/api/response/UserVmResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/UserVmResponse.java
index ca3ca87..b8b0189 100644
--- a/api/src/main/java/org/apache/cloudstack/api/response/UserVmResponse.java
+++ b/api/src/main/java/org/apache/cloudstack/api/response/UserVmResponse.java
@@ -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; }
+
}
diff --git a/engine/api/src/main/java/org/apache/cloudstack/engine/cloud/entity/api/VirtualMachineEntity.java b/engine/api/src/main/java/org/apache/cloudstack/engine/cloud/entity/api/VirtualMachineEntity.java
index c004514..7b34077 100644
--- a/engine/api/src/main/java/org/apache/cloudstack/engine/cloud/entity/api/VirtualMachineEntity.java
+++ b/engine/api/src/main/java/org/apache/cloudstack/engine/cloud/entity/api/VirtualMachineEntity.java
@@ -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);
+
}
diff --git a/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java b/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java
index 7765611..8817efb 100755
--- a/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java
+++ b/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java
@@ -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);
diff --git a/engine/orchestration/src/main/java/org/apache/cloudstack/engine/cloud/entity/api/VMEntityManagerImpl.java b/engine/orchestration/src/main/java/org/apache/cloudstack/engine/cloud/entity/api/VMEntityManagerImpl.java
index ef9c44a..567675a 100644
--- a/engine/orchestration/src/main/java/org/apache/cloudstack/engine/cloud/entity/api/VMEntityManagerImpl.java
+++ b/engine/orchestration/src/main/java/org/apache/cloudstack/engine/cloud/entity/api/VMEntityManagerImpl.java
@@ -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 =
diff --git a/engine/orchestration/src/main/java/org/apache/cloudstack/engine/cloud/entity/api/VirtualMachineEntityImpl.java b/engine/orchestration/src/main/java/org/apache/cloudstack/engine/cloud/entity/api/VirtualMachineEntityImpl.java
index 598e619..3e5f910 100644
--- a/engine/orchestration/src/main/java/org/apache/cloudstack/engine/cloud/entity/api/VirtualMachineEntityImpl.java
+++ b/engine/orchestration/src/main/java/org/apache/cloudstack/engine/cloud/entity/api/VirtualMachineEntityImpl.java
@@ -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);
+ }
+ }
+
+ }
}
diff --git a/engine/schema/src/main/java/com/cloud/host/dao/HostDao.java b/engine/schema/src/main/java/com/cloud/host/dao/HostDao.java
index 34b8963..ced19ce 100644
--- a/engine/schema/src/main/java/com/cloud/host/dao/HostDao.java
+++ b/engine/schema/src/main/java/com/cloud/host/dao/HostDao.java
@@ -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);
}
diff --git a/engine/schema/src/main/java/com/cloud/host/dao/HostDaoImpl.java b/engine/schema/src/main/java/com/cloud/host/dao/HostDaoImpl.java
index 20d817c..ec4573f 100644
--- a/engine/schema/src/main/java/com/cloud/host/dao/HostDaoImpl.java
+++ b/engine/schema/src/main/java/com/cloud/host/dao/HostDaoImpl.java
@@ -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);
diff --git a/plugins/deployment-planners/implicit-dedication/src/test/java/org/apache/cloudstack/implicitplanner/ImplicitPlannerTest.java b/plugins/deployment-planners/implicit-dedication/src/test/java/org/apache/cloudstack/implicitplanner/ImplicitPlannerTest.java
index 79cb1b4..1a3aed0 100644
--- a/plugins/deployment-planners/implicit-dedication/src/test/java/org/apache/cloudstack/implicitplanner/ImplicitPlannerTest.java
+++ b/plugins/deployment-planners/implicit-dedication/src/test/java/org/apache/cloudstack/implicitplanner/ImplicitPlannerTest.java
@@ -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;
@@ -574,6 +575,10 @@ public class ImplicitPlannerTest {
}
@Bean
+ public HostDetailsDao hostDetailsDao() { return Mockito.mock(HostDetailsDao.class); }
+
+
+ @Bean
public ClusterDetailsDao clusterDetailsDao() {
return Mockito.mock(ClusterDetailsDao.class);
}
diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java
index 1be6785..fd9075e 100644
--- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java
+++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java
@@ -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;
+ }
}
diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java
index bfbb4d5..e2d506c 100644
--- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java
+++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java
@@ -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;
diff --git a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/guru/VMwareGuru.java b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/guru/VMwareGuru.java
index 39c1e66..4e8acad 100644
--- a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/guru/VMwareGuru.java
+++ b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/guru/VMwareGuru.java
@@ -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) {
diff --git a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/VmwareServerDiscoverer.java b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/VmwareServerDiscoverer.java
index 4b2f830..1102f9d 100644
--- a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/VmwareServerDiscoverer.java
+++ b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/VmwareServerDiscoverer.java
@@ -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);
diff --git a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/resource/VmwareResource.java b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/resource/VmwareResource.java
index 7624f95..5a1459d 100644
--- a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/resource/VmwareResource.java
+++ b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/resource/VmwareResource.java
@@ -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());
diff --git a/server/src/main/java/com/cloud/agent/manager/allocator/impl/FirstFitAllocator.java b/server/src/main/java/com/cloud/agent/manager/allocator/impl/FirstFitAllocator.java
index 186c654..aab9510 100644
--- a/server/src/main/java/com/cloud/agent/manager/allocator/impl/FirstFitAllocator.java
+++ b/server/src/main/java/com/cloud/agent/manager/allocator/impl/FirstFitAllocator.java
@@ -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);
diff --git a/server/src/main/java/com/cloud/api/query/dao/UserVmJoinDaoImpl.java b/server/src/main/java/com/cloud/api/query/dao/UserVmJoinDaoImpl.java
index a612829..21c6786 100644
--- a/server/src/main/java/com/cloud/api/query/dao/UserVmJoinDaoImpl.java
+++ b/server/src/main/java/com/cloud/api/query/dao/UserVmJoinDaoImpl.java
@@ -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) {
diff --git a/server/src/main/java/com/cloud/deploy/DeploymentPlanningManagerImpl.java b/server/src/main/java/com/cloud/deploy/DeploymentPlanningManagerImpl.java
index 1315cdf..0c1aab3 100644
--- a/server/src/main/java/com/cloud/deploy/DeploymentPlanningManagerImpl.java
+++ b/server/src/main/java/com/cloud/deploy/DeploymentPlanningManagerImpl.java
@@ -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)) {
diff --git a/server/src/main/java/com/cloud/deploy/FirstFitPlanner.java b/server/src/main/java/com/cloud/deploy/FirstFitPlanner.java
index 5760e24..88f6b95 100644
--- a/server/src/main/java/com/cloud/deploy/FirstFitPlanner.java
+++ b/server/src/main/java/com/cloud/deploy/FirstFitPlanner.java
@@ -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();
diff --git a/server/src/main/java/com/cloud/hypervisor/HypervisorGuruBase.java b/server/src/main/java/com/cloud/hypervisor/HypervisorGuruBase.java
index 9e55506..0c3263a 100644
--- a/server/src/main/java/com/cloud/hypervisor/HypervisorGuruBase.java
+++ b/server/src/main/java/com/cloud/hypervisor/HypervisorGuruBase.java
@@ -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;
diff --git a/server/src/main/java/com/cloud/hypervisor/kvm/discoverer/LibvirtServerDiscoverer.java b/server/src/main/java/com/cloud/hypervisor/kvm/discoverer/LibvirtServerDiscoverer.java
index e232d6a..904a488 100644
--- a/server/src/main/java/com/cloud/hypervisor/kvm/discoverer/LibvirtServerDiscoverer.java
+++ b/server/src/main/java/com/cloud/hypervisor/kvm/discoverer/LibvirtServerDiscoverer.java
@@ -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) {
diff --git a/server/src/main/java/com/cloud/server/ManagementServerImpl.java b/server/src/main/java/com/cloud/server/ManagementServerImpl.java
index ff29f1d..a3e9bb6 100644
--- a/server/src/main/java/com/cloud/server/ManagementServerImpl.java
+++ b/server/src/main/java/com/cloud/server/ManagementServerImpl.java
@@ -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.
diff --git a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java
index 3f28f12..b88e250 100644
--- a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java
+++ b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java
@@ -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);
diff --git a/server/src/test/java/com/cloud/vm/DeploymentPlanningManagerImplTest.java b/server/src/test/java/com/cloud/vm/DeploymentPlanningManagerImplTest.java
index 1d1ab89..e73c0c6 100644
--- a/server/src/test/java/com/cloud/vm/DeploymentPlanningManagerImplTest.java
+++ b/server/src/test/java/com/cloud/vm/DeploymentPlanningManagerImplTest.java
@@ -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)
@@ -285,6 +286,12 @@ public class DeploymentPlanningManagerImplTest {
}
@Bean
+ public HostDetailsDao hostDetailsDao() {
+ return Mockito.mock(HostDetailsDao.class);
+ }
+
+
+ @Bean
public ClusterDetailsDao clusterDetailsDao() {
return Mockito.mock(ClusterDetailsDao.class);
}
diff --git a/server/src/test/java/com/cloud/vm/FirstFitPlannerTest.java b/server/src/test/java/com/cloud/vm/FirstFitPlannerTest.java
index 85463de..41deea2 100644
--- a/server/src/test/java/com/cloud/vm/FirstFitPlannerTest.java
+++ b/server/src/test/java/com/cloud/vm/FirstFitPlannerTest.java
@@ -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;
@@ -356,6 +359,9 @@ public class FirstFitPlannerTest {
}
@Bean
+ public HostDetailsDao hostDetailsDao() { return Mockito.mock(HostDetailsDao.class); }
+
+ @Bean
public HostGpuGroupsDao hostGpuGroupsDao() {
return Mockito.mock(HostGpuGroupsDao.class);
}
diff --git a/ui/index.html b/ui/index.html
index 7d24838..ef7a461 100644
--- a/ui/index.html
+++ b/ui/index.html
@@ -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">
diff --git a/ui/l10n/en.js b/ui/l10n/en.js
index d01b622..cb967be 100644
--- a/ui/l10n/en.js
+++ b/ui/l10n/en.js
@@ -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",
diff --git a/ui/scripts/instanceWizard.js b/ui/scripts/instanceWizard.js
index 04cceaa..cd95913 100644
--- a/ui/scripts/instanceWizard.js
+++ b/ui/scripts/instanceWizard.js
@@ -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, {
diff --git a/ui/scripts/instances.js b/ui/scripts/instances.js
index bb32d3a..58cb86c 100644
--- a/ui/scripts/instances.js
+++ b/ui/scripts/instances.js
@@ -3322,6 +3322,12 @@
},
id: {
label: 'label.id'
+ },
+ boottype: {
+ label: 'label.vm.boottype'
+ },
+ bootmode: {
+ label: 'label.vm.bootmode'
}
}],
diff --git a/ui/scripts/system.js b/ui/scripts/system.js
index 1e29500..29f428a 100755
--- a/ui/scripts/system.js
+++ b/ui/scripts/system.js
@@ -18024,6 +18024,10 @@
});
}
},
+ ueficapability: {
+ label:'label.host.ueficapability',
+ converter: cloudStack.converters.toBooleanText
+ },
hahost: {
label: 'label.ha.enabled',
converter: cloudStack.converters.toBooleanText
diff --git a/ui/scripts/ui-custom/instanceWizard.js b/ui/scripts/ui-custom/instanceWizard.js
index 2450ed1..4aefa97 100644
--- a/ui/scripts/ui-custom/instanceWizard.js
+++ b/ui/scripts/ui-custom/instanceWizard.js
@@ -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());
+ });
+
});
}
};
diff --git a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/HostMO.java b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/HostMO.java
index 5aab3a2..7877db9 100644
--- a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/HostMO.java
+++ b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/HostMO.java
@@ -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;
+ }
+
}
diff --git a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/util/VmwareHelper.java b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/util/VmwareHelper.java
index dd65775..3d209fb 100644
--- a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/util/VmwareHelper.java
+++ b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/util/VmwareHelper.java
@@ -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;