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 40f30df1895b..dceacf0e65bc 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 @@ -65,6 +65,7 @@ public class VirtualMachineTO { String uuid; String bootType; String bootMode; + boolean enterHardwareSetup; DiskTO[] disks; NicTO[] nics; @@ -393,4 +394,12 @@ public void setBootType(String bootType) { public String getBootMode() { return bootMode; } public void setBootMode(String bootMode) { this.bootMode = bootMode; } + + public boolean isEnterHardwareSetup() { + return enterHardwareSetup; + } + + public void setEnterHardwareSetup(boolean enterHardwareSetup) { + this.enterHardwareSetup = enterHardwareSetup; + } } diff --git a/api/src/main/java/com/cloud/vm/VirtualMachineProfile.java b/api/src/main/java/com/cloud/vm/VirtualMachineProfile.java index 1abc76440a2d..4354a2c69ed7 100644 --- a/api/src/main/java/com/cloud/vm/VirtualMachineProfile.java +++ b/api/src/main/java/com/cloud/vm/VirtualMachineProfile.java @@ -63,6 +63,7 @@ public static class Param { public static final Param UefiFlag = new Param("UefiFlag"); public static final Param BootMode = new Param("BootMode"); public static final Param BootType = new Param("BootType"); + public static final Param BootIntoSetup = new Param("enterHardwareSetup"); private String name; 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 932f62dfa29b..55f87065dadf 100644 --- a/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java +++ b/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java @@ -805,8 +805,9 @@ 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 static final String BOOT_TYPE = "boottype"; + public static final String BOOT_MODE = "bootmode"; + public static final String BOOT_INTO_SETUP = "bootintosetup"; public enum BootType { UEFI, BIOS; 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 db315cca92e1..b4514b1c759b 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 @@ -113,12 +113,15 @@ 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 networkIds; - @Parameter(name = ApiConstants.BOOT_TYPE, type = CommandType.STRING, required = false, description = "Guest VM Boot option either custom[UEFI] or default boot [BIOS]") + @Parameter(name = ApiConstants.BOOT_TYPE, type = CommandType.STRING, required = false, description = "Guest VM Boot option either custom[UEFI] or default boot [BIOS]", since = "4.14.0.0") 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") + @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", since = "4.14.0.0") private String bootMode; + @Parameter(name = ApiConstants.BOOT_INTO_SETUP, type = CommandType.BOOLEAN, required = false, description = "Boot into hardware setup or not (ignored if startVm = false, only valid for vmware)", since = "4.15.0.0") + private Boolean bootIntoSetup; + //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," @@ -281,15 +284,14 @@ public Map getDetails() { } } } - if(getBootType() != null){ // export to get - if(getBootType() == ApiConstants.BootType.UEFI) { - customparameterMap.put(getBootType().toString(), getBootMode().toString()); - } + if (ApiConstants.BootType.UEFI.equals(getBootType())) { + customparameterMap.put(getBootType().toString(), getBootMode().toString()); } if (rootdisksize != null && !customparameterMap.containsKey("rootdisksize")) { customparameterMap.put("rootdisksize", rootdisksize.toString()); } + return customparameterMap; } @@ -577,6 +579,10 @@ public boolean getCopyImageTags() { return copyImageTags == null ? false : copyImageTags; } + public Boolean getBootIntoSetup() { + return bootIntoSetup; + } + ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// ///////////////////////////////////////////////////// diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/vm/RebootVMCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/RebootVMCmd.java index 6011bdbcffee..5bdbbb651ebb 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/user/vm/RebootVMCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/RebootVMCmd.java @@ -53,6 +53,9 @@ public class RebootVMCmd extends BaseAsyncCmd implements UserCmd { required=true, description="The ID of the virtual machine") private Long id; + @Parameter(name = ApiConstants.BOOT_INTO_SETUP, type = CommandType.BOOLEAN, required = false, description = "Boot into hardware setup menu or not", since = "4.15.0.0") + private Boolean bootIntoSetup; + ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// @@ -61,6 +64,10 @@ public Long getId() { return id; } + public Boolean getBootIntoSetup() { + return bootIntoSetup; + } + ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// ///////////////////////////////////////////////////// diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/vm/StartVMCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/StartVMCmd.java index 2a7f6d0316de..ffbce175b5d5 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/user/vm/StartVMCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/StartVMCmd.java @@ -85,6 +85,9 @@ public class StartVMCmd extends BaseAsyncCmd implements UserCmd { @Parameter(name = ApiConstants.DEPLOYMENT_PLANNER, type = CommandType.STRING, description = "Deployment planner to use for vm allocation. Available to ROOT admin only", since = "4.4", authorized = { RoleType.Admin }) private String deploymentPlanner; + @Parameter(name = ApiConstants.BOOT_INTO_SETUP, type = CommandType.BOOLEAN, required = false, description = "Boot into hardware setup menu or not", since = "4.15.0.0") + private Boolean bootIntoSetup; + // /////////////////////////////////////////////////// // ///////////////// Accessors /////////////////////// // /////////////////////////////////////////////////// @@ -105,6 +108,10 @@ public Long getClusterId() { return clusterId; } + public Boolean getBootIntoSetup() { + return bootIntoSetup; + } + // /////////////////////////////////////////////////// // ///////////// API Implementation/////////////////// // /////////////////////////////////////////////////// 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 7b47f8a28caa..369e91ba02da 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 @@ -503,14 +503,13 @@ public void setDetails(Map details) { detailsCopy.remove("username"); detailsCopy.remove("password"); - if(detailsCopy.containsKey(Host.HOST_UEFI_ENABLE)) { + 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; } 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 8817efbeaedc..e0173cf73ac6 100755 --- a/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java +++ b/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java @@ -889,6 +889,11 @@ public void advanceStart(final String vmUuid, final Map":params.get(VirtualMachineProfile.Param.BootIntoSetup)))); + } // avoid re-entrance VmWorkJobVO placeHolder = null; final VirtualMachine vm = _vmDao.findByUuid(vmUuid); @@ -901,6 +906,11 @@ public void advanceStart(final String vmUuid, final Map":params.get(VirtualMachineProfile.Param.BootIntoSetup)))); + } final Outcome outcome = startVmThroughJobQueue(vmUuid, params, planToDeploy, planner); try { @@ -1064,10 +1074,7 @@ public void orchestrateStart(final String vmUuid, final Map params) { + StringBuffer msgBuf = new StringBuffer("Uefi params "); + boolean log = false; + if (params.get(VirtualMachineProfile.Param.UefiFlag) != null) { + msgBuf.append(String.format("UefiFlag: %s ", params.get(VirtualMachineProfile.Param.UefiFlag))); + log = true; + } + if (params.get(VirtualMachineProfile.Param.BootType) != null) { + msgBuf.append(String.format("Boot Type: %s ", params.get(VirtualMachineProfile.Param.BootType))); + log = true; + } + if (params.get(VirtualMachineProfile.Param.BootMode) != null) { + msgBuf.append(String.format("Boot Mode: %s ", params.get(VirtualMachineProfile.Param.BootMode))); + log = true; + } + if (params.get(VirtualMachineProfile.Param.BootIntoSetup) != null) { + msgBuf.append(String.format("Boot into Setup: %s ", params.get(VirtualMachineProfile.Param.BootIntoSetup))); + log = true; + } + if (log) { + s_logger.info(msgBuf.toString()); + } + } + // Add extra config data to the vmTO as a Map private void addExtraConfig(VirtualMachineTO vmTO) { Map details = vmTO.getDetails(); @@ -3094,6 +3127,10 @@ public void advanceReboot(final String vmUuid, final Map":params.get(VirtualMachineProfile.Param.BootIntoSetup)))); + } orchestrateReboot(vmUuid, params); } finally { if (placeHolder != null) { @@ -3101,6 +3138,10 @@ public void advanceReboot(final String vmUuid, final Map":params.get(VirtualMachineProfile.Param.BootIntoSetup)))); + } final Outcome outcome = rebootVmThroughJobQueue(vmUuid, params); try { @@ -3150,7 +3191,9 @@ private void orchestrateReboot(final String vmUuid, final Map params) { + Boolean enterSetup = (Boolean)params.get(VirtualMachineProfile.Param.BootIntoSetup); + if (s_logger.isTraceEnabled()) { + s_logger.trace(String.format("orchestrating VM reboot for '%s' %s set to %s", vmTo.getName(), VirtualMachineProfile.Param.BootIntoSetup, enterSetup)); + } + vmTo.setEnterHardwareSetup(enterSetup == null ? false : enterSetup); + } + protected VirtualMachineTO getVmTO(Long vmId) { final VMInstanceVO vm = _vmDao.findById(vmId); final VirtualMachineProfile profile = new VirtualMachineProfileImpl(vm); @@ -5223,6 +5274,11 @@ private Pair orchestrateStart(final VmWorkStart work) th } assert vm != null; + Boolean enterSetup = (Boolean)work.getParams().get(VirtualMachineProfile.Param.BootIntoSetup); + if (s_logger.isTraceEnabled()) { + s_logger.trace(String.format("orchestrating VM start for '%s' %s set to %s", vm.getInstanceName(), VirtualMachineProfile.Param.BootIntoSetup, enterSetup)); + } + try{ orchestrateStart(vm.getUuid(), work.getParams(), work.getPlan(), _dpMgr.getDeploymentPlannerByName(work.getDeploymentPlanner())); } 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 59b27bd2410e..a2a086b0b6c7 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 @@ -17,19 +17,15 @@ package com.cloud.hypervisor.guru; import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.UUID; -import java.util.stream.Collectors; import javax.inject.Inject; import org.apache.cloudstack.acl.ControlledEntity; -import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.backup.Backup; import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine; import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStore; @@ -61,13 +57,11 @@ import com.cloud.agent.api.storage.CopyVolumeCommand; import com.cloud.agent.api.storage.CreateEntityDownloadURLCommand; import com.cloud.agent.api.storage.CreateVolumeOVACommand; -import com.cloud.agent.api.storage.OVFPropertyTO; import com.cloud.agent.api.storage.PrepareOVAPackingCommand; import com.cloud.agent.api.to.DataObjectType; import com.cloud.agent.api.to.DataStoreTO; import com.cloud.agent.api.to.DataTO; import com.cloud.agent.api.to.DiskTO; -import com.cloud.agent.api.to.NicTO; import com.cloud.agent.api.to.VirtualMachineTO; import com.cloud.agent.api.to.VolumeTO; import com.cloud.cluster.ClusterManager; @@ -75,7 +69,6 @@ import com.cloud.dc.ClusterDetailsDao; import com.cloud.event.EventTypes; import com.cloud.event.UsageEventUtils; -import com.cloud.exception.InsufficientAddressCapacityException; import com.cloud.exception.InvalidParameterValueException; import com.cloud.host.Host; import com.cloud.host.HostVO; @@ -90,18 +83,13 @@ import com.cloud.hypervisor.vmware.dao.VmwareDatacenterZoneMapDao; import com.cloud.hypervisor.vmware.manager.VmwareManager; import com.cloud.hypervisor.vmware.mo.DatacenterMO; -import com.cloud.hypervisor.vmware.mo.DiskControllerType; import com.cloud.hypervisor.vmware.mo.NetworkMO; import com.cloud.hypervisor.vmware.mo.VirtualDiskManagerMO; -import com.cloud.hypervisor.vmware.mo.VirtualEthernetCardType; import com.cloud.hypervisor.vmware.mo.VirtualMachineDiskInfoBuilder; import com.cloud.hypervisor.vmware.mo.VirtualMachineMO; import com.cloud.hypervisor.vmware.resource.VmwareContextFactory; import com.cloud.hypervisor.vmware.util.VmwareContext; import com.cloud.network.Network; -import com.cloud.network.Network.Provider; -import com.cloud.network.Network.Service; -import com.cloud.network.NetworkModel; import com.cloud.network.Networks; import com.cloud.network.Networks.BroadcastDomainType; import com.cloud.network.Networks.TrafficType; @@ -117,11 +105,9 @@ import com.cloud.service.dao.ServiceOfferingDao; import com.cloud.storage.DataStoreRole; import com.cloud.storage.DiskOfferingVO; -import com.cloud.storage.GuestOSHypervisorVO; import com.cloud.storage.GuestOSVO; import com.cloud.storage.Storage; import com.cloud.storage.StoragePool; -import com.cloud.storage.TemplateOVFPropertyVO; import com.cloud.storage.VMTemplateStoragePoolVO; import com.cloud.storage.VMTemplateStorageResourceAssoc; import com.cloud.storage.VMTemplateVO; @@ -129,20 +115,16 @@ import com.cloud.storage.VolumeVO; import com.cloud.storage.dao.DiskOfferingDao; import com.cloud.storage.dao.GuestOSDao; -import com.cloud.storage.dao.GuestOSHypervisorDao; -import com.cloud.storage.dao.TemplateOVFPropertiesDao; import com.cloud.storage.dao.VMTemplateDao; import com.cloud.storage.dao.VMTemplatePoolDao; import com.cloud.storage.dao.VolumeDao; import com.cloud.storage.secondary.SecondaryStorageVmManager; -import com.cloud.template.VirtualMachineTemplate.BootloaderType; import com.cloud.user.ResourceLimitService; import com.cloud.utils.Pair; import com.cloud.utils.UuidUtils; import com.cloud.utils.db.DB; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.net.NetUtils; -import com.cloud.vm.DomainRouterVO; import com.cloud.vm.NicProfile; import com.cloud.vm.NicVO; import com.cloud.vm.SecondaryStorageVmVO; @@ -152,8 +134,6 @@ import com.cloud.vm.VirtualMachine.Type; import com.cloud.vm.VirtualMachineManager; import com.cloud.vm.VirtualMachineProfile; -import com.cloud.vm.VmDetailConstants; -import com.cloud.vm.dao.DomainRouterDao; import com.cloud.vm.dao.NicDao; import com.cloud.vm.dao.UserVmDao; import com.cloud.vm.dao.VMInstanceDao; @@ -172,373 +152,62 @@ public class VMwareGuru extends HypervisorGuruBase implements HypervisorGuru, Configurable { private static final Logger s_logger = Logger.getLogger(VMwareGuru.class); - @Inject - private NetworkDao _networkDao; - @Inject - private GuestOSDao _guestOsDao; - @Inject - private GuestOSHypervisorDao _guestOsHypervisorDao; - @Inject - private HostDao _hostDao; - @Inject - private HostDetailsDao _hostDetailsDao; - @Inject - private ClusterDetailsDao _clusterDetailsDao; - @Inject - private CommandExecLogDao _cmdExecLogDao; - @Inject - private VmwareManager _vmwareMgr; - @Inject - private SecondaryStorageVmManager _secStorageMgr; - @Inject - private NetworkModel _networkMgr; - @Inject - private NicDao _nicDao; - @Inject - private DomainRouterDao _domainRouterDao; - @Inject - private PhysicalNetworkTrafficTypeDao _physicalNetworkTrafficTypeDao; - @Inject - private VMInstanceDao _vmDao; - @Inject - private VirtualMachineManager vmManager; - @Inject - private ClusterManager _clusterMgr; - @Inject - VolumeDao _volumeDao; - @Inject - ResourceLimitService _resourceLimitService; - @Inject - PrimaryDataStoreDao _storagePoolDao; - @Inject - VolumeDataFactory _volFactory; - @Inject - private VmwareDatacenterDao vmwareDatacenterDao; - @Inject - private VmwareDatacenterZoneMapDao vmwareDatacenterZoneMapDao; - @Inject - private ServiceOfferingDao serviceOfferingDao; - @Inject - private VMTemplatePoolDao templateStoragePoolDao; - @Inject - private VMTemplateDao vmTemplateDao; - @Inject - private UserVmDao userVmDao; - @Inject - private DiskOfferingDao diskOfferingDao; - @Inject - private PhysicalNetworkDao physicalNetworkDao; - @Inject - private TemplateOVFPropertiesDao templateOVFPropertiesDao; + + @Inject VmwareVmImplementer vmwareVmImplementer; + + @Inject NetworkDao _networkDao; + @Inject GuestOSDao _guestOsDao; + @Inject HostDao _hostDao; + @Inject HostDetailsDao _hostDetailsDao; + @Inject ClusterDetailsDao _clusterDetailsDao; + @Inject CommandExecLogDao _cmdExecLogDao; + @Inject VmwareManager _vmwareMgr; + @Inject SecondaryStorageVmManager _secStorageMgr; + @Inject NicDao _nicDao; + @Inject PhysicalNetworkTrafficTypeDao _physicalNetworkTrafficTypeDao; + @Inject VMInstanceDao _vmDao; + @Inject VirtualMachineManager vmManager; + @Inject ClusterManager _clusterMgr; + @Inject VolumeDao _volumeDao; + @Inject ResourceLimitService _resourceLimitService; + @Inject PrimaryDataStoreDao _storagePoolDao; + @Inject VolumeDataFactory _volFactory; + @Inject VmwareDatacenterDao vmwareDatacenterDao; + @Inject VmwareDatacenterZoneMapDao vmwareDatacenterZoneMapDao; + @Inject ServiceOfferingDao serviceOfferingDao; + @Inject VMTemplatePoolDao templateStoragePoolDao; + @Inject VMTemplateDao vmTemplateDao; + @Inject UserVmDao userVmDao; + @Inject DiskOfferingDao diskOfferingDao; + @Inject PhysicalNetworkDao physicalNetworkDao; protected VMwareGuru() { super(); } public static final ConfigKey VmwareReserveCpu = new ConfigKey(Boolean.class, "vmware.reserve.cpu", "Advanced", "false", - "Specify whether or not to reserve CPU when deploying an instance.", true, ConfigKey.Scope.Cluster, - null); + "Specify whether or not to reserve CPU when deploying an instance.", true, ConfigKey.Scope.Cluster, null); public static final ConfigKey VmwareReserveMemory = new ConfigKey(Boolean.class, "vmware.reserve.mem", "Advanced", "false", - "Specify whether or not to reserve memory when deploying an instance.", true, - ConfigKey.Scope.Cluster, null); + "Specify whether or not to reserve memory when deploying an instance.", true, ConfigKey.Scope.Cluster, null); - protected ConfigKey VmwareEnableNestedVirtualization = new ConfigKey(Boolean.class, "vmware.nested.virtualization", "Advanced", "false", + public static final ConfigKey VmwareEnableNestedVirtualization = new ConfigKey(Boolean.class, "vmware.nested.virtualization", "Advanced", "false", "When set to true this will enable nested virtualization when this is supported by the hypervisor", true, ConfigKey.Scope.Global, null); - protected ConfigKey VmwareEnableNestedVirtualizationPerVM = new ConfigKey(Boolean.class, "vmware.nested.virtualization.perVM", "Advanced", "false", + public static final ConfigKey VmwareEnableNestedVirtualizationPerVM = new ConfigKey(Boolean.class, "vmware.nested.virtualization.perVM", "Advanced", "false", "When set to true this will enable nested virtualization per vm", true, ConfigKey.Scope.Global, null); - @Override - public HypervisorType getHypervisorType() { + @Override public HypervisorType getHypervisorType() { return HypervisorType.VMware; } - @Override - public VirtualMachineTO implement(VirtualMachineProfile vm) { - VirtualMachineTO to = toVirtualMachineTO(vm); - to.setBootloader(BootloaderType.HVM); - - Map details = to.getDetails(); - if (details == null) - details = new HashMap(); - - Type vmType = vm.getType(); - boolean userVm = !(vmType.equals(VirtualMachine.Type.DomainRouter) || vmType.equals(VirtualMachine.Type.ConsoleProxy) - || vmType.equals(VirtualMachine.Type.SecondaryStorageVm)); - - String nicDeviceType = details.get(VmDetailConstants.NIC_ADAPTER); - if (!userVm) { - - if (nicDeviceType == null) { - details.put(VmDetailConstants.NIC_ADAPTER, _vmwareMgr.getSystemVMDefaultNicAdapterType()); - } else { - try { - VirtualEthernetCardType.valueOf(nicDeviceType); - } catch (Exception e) { - s_logger.warn("Invalid NIC device type " + nicDeviceType + " is specified in VM details, switch to default E1000"); - details.put(VmDetailConstants.NIC_ADAPTER, VirtualEthernetCardType.E1000.toString()); - } - } - } else { - // for user-VM, use E1000 as default - if (nicDeviceType == null) { - details.put(VmDetailConstants.NIC_ADAPTER, VirtualEthernetCardType.E1000.toString()); - } else { - try { - VirtualEthernetCardType.valueOf(nicDeviceType); - } catch (Exception e) { - s_logger.warn("Invalid NIC device type " + nicDeviceType + " is specified in VM details, switch to default E1000"); - details.put(VmDetailConstants.NIC_ADAPTER, VirtualEthernetCardType.E1000.toString()); - } - } - } - - details.put(VmDetailConstants.BOOT_MODE, to.getBootMode()); - String diskDeviceType = details.get(VmDetailConstants.ROOT_DISK_CONTROLLER); - if (userVm) { - if (diskDeviceType == null) { - details.put(VmDetailConstants.ROOT_DISK_CONTROLLER, _vmwareMgr.getRootDiskController()); - } - } - String diskController = details.get(VmDetailConstants.DATA_DISK_CONTROLLER); - if (userVm) { - if (diskController == null) { - details.put(VmDetailConstants.DATA_DISK_CONTROLLER, DiskControllerType.lsilogic.toString()); - } - } - - if (vm.getType() == VirtualMachine.Type.NetScalerVm) { - details.put(VmDetailConstants.ROOT_DISK_CONTROLLER, "scsi"); - } - - List nicProfiles = vm.getNics(); - - for (NicProfile nicProfile : nicProfiles) { - if (nicProfile.getTrafficType() == TrafficType.Guest) { - if (_networkMgr.isProviderSupportServiceInNetwork(nicProfile.getNetworkId(), Service.Firewall, Provider.CiscoVnmc)) { - details.put("ConfigureVServiceInNexus", Boolean.TRUE.toString()); - } - break; - } - } - - long clusterId = getClusterId(vm.getId()); - details.put(VmwareReserveCpu.key(), VmwareReserveCpu.valueIn(clusterId).toString()); - details.put(VmwareReserveMemory.key(), VmwareReserveMemory.valueIn(clusterId).toString()); - to.setDetails(details); - - if (vmType.equals(VirtualMachine.Type.DomainRouter)) { - - NicProfile publicNicProfile = null; - for (NicProfile nicProfile : nicProfiles) { - if (nicProfile.getTrafficType() == TrafficType.Public) { - publicNicProfile = nicProfile; - break; - } - } - - if (publicNicProfile != null) { - NicTO[] nics = to.getNics(); - - // reserve extra NICs - NicTO[] expandedNics = new NicTO[nics.length + _vmwareMgr.getRouterExtraPublicNics()]; - int i = 0; - int deviceId = -1; - for (i = 0; i < nics.length; i++) { - expandedNics[i] = nics[i]; - if (nics[i].getDeviceId() > deviceId) - deviceId = nics[i].getDeviceId(); - } - deviceId++; - - long networkId = publicNicProfile.getNetworkId(); - NetworkVO network = _networkDao.findById(networkId); - - for (; i < nics.length + _vmwareMgr.getRouterExtraPublicNics(); i++) { - NicTO nicTo = new NicTO(); - - nicTo.setDeviceId(deviceId++); - nicTo.setBroadcastType(publicNicProfile.getBroadcastType()); - nicTo.setType(publicNicProfile.getTrafficType()); - nicTo.setIp("0.0.0.0"); - nicTo.setNetmask("255.255.255.255"); - - try { - String mac = _networkMgr.getNextAvailableMacAddressInNetwork(networkId); - nicTo.setMac(mac); - } catch (InsufficientAddressCapacityException e) { - throw new CloudRuntimeException("unable to allocate mac address on network: " + networkId); - } - nicTo.setDns1(publicNicProfile.getIPv4Dns1()); - nicTo.setDns2(publicNicProfile.getIPv4Dns2()); - if (publicNicProfile.getIPv4Gateway() != null) { - nicTo.setGateway(publicNicProfile.getIPv4Gateway()); - } else { - nicTo.setGateway(network.getGateway()); - } - nicTo.setDefaultNic(false); - nicTo.setBroadcastUri(publicNicProfile.getBroadCastUri()); - nicTo.setIsolationuri(publicNicProfile.getIsolationUri()); - - Integer networkRate = _networkMgr.getNetworkRate(network.getId(), null); - nicTo.setNetworkRateMbps(networkRate); - - expandedNics[i] = nicTo; - } - - to.setNics(expandedNics); - - VirtualMachine router = vm.getVirtualMachine(); - DomainRouterVO routerVO = _domainRouterDao.findById(router.getId()); - if (routerVO != null && routerVO.getIsRedundantRouter()) { - Long peerRouterId = _nicDao.getPeerRouterId(publicNicProfile.getMacAddress(), router.getId()); - DomainRouterVO peerRouterVO = null; - if (peerRouterId != null) { - peerRouterVO = _domainRouterDao.findById(peerRouterId); - if (peerRouterVO != null) { - details.put("PeerRouterInstanceName", peerRouterVO.getInstanceName()); - } - } - } - } - - StringBuffer sbMacSequence = new StringBuffer(); - for (NicTO nicTo : sortNicsByDeviceId(to.getNics())) { - sbMacSequence.append(nicTo.getMac()).append("|"); - } - if (!sbMacSequence.toString().isEmpty()) { - sbMacSequence.deleteCharAt(sbMacSequence.length() - 1); - String bootArgs = to.getBootArgs(); - to.setBootArgs(bootArgs + " nic_macs=" + sbMacSequence.toString()); - } - - } - - // Don't do this if the virtual machine is one of the special types - // Should only be done on user machines - if (userVm) { - configureNestedVirtualization(details, to); - } - // Determine the VM's OS description - GuestOSVO guestOS = _guestOsDao.findByIdIncludingRemoved(vm.getVirtualMachine().getGuestOSId()); - to.setOs(guestOS.getDisplayName()); - to.setHostName(vm.getHostName()); - HostVO host = _hostDao.findById(vm.getVirtualMachine().getHostId()); - GuestOSHypervisorVO guestOsMapping = null; - if (host != null) { - guestOsMapping = _guestOsHypervisorDao.findByOsIdAndHypervisor(guestOS.getId(), getHypervisorType().toString(), host.getHypervisorVersion()); - } - if (guestOsMapping == null || host == null) { - to.setPlatformEmulator(null); - } else { - to.setPlatformEmulator(guestOsMapping.getGuestOsName()); - } - - List ovfProperties = new ArrayList<>(); - for (String detailKey : details.keySet()) { - if (detailKey.startsWith(ApiConstants.OVF_PROPERTIES)) { - String ovfPropKey = detailKey.replace(ApiConstants.OVF_PROPERTIES + "-", ""); - TemplateOVFPropertyVO templateOVFPropertyVO = templateOVFPropertiesDao.findByTemplateAndKey(vm.getTemplateId(), ovfPropKey); - if (templateOVFPropertyVO == null) { - s_logger.warn(String.format("OVF property %s not found on template, discarding", ovfPropKey)); - continue; - } - String ovfValue = details.get(detailKey); - boolean isPassword = templateOVFPropertyVO.isPassword(); - OVFPropertyTO propertyTO = new OVFPropertyTO(ovfPropKey, ovfValue, isPassword); - ovfProperties.add(propertyTO); - } - } - - if (CollectionUtils.isNotEmpty(ovfProperties)) { - removeOvfPropertiesFromDetails(ovfProperties, details); - String templateInstallPath = null; - List rootDiskList = vm.getDisks().stream().filter(x -> x.getType() == Volume.Type.ROOT).collect(Collectors.toList()); - if (rootDiskList.size() != 1) { - throw new CloudRuntimeException("Did not find only one root disk for VM " + vm.getHostName()); - } - - DiskTO rootDiskTO = rootDiskList.get(0); - DataStoreTO dataStore = rootDiskTO.getData().getDataStore(); - StoragePoolVO storagePoolVO = _storagePoolDao.findByUuid(dataStore.getUuid()); - long dataCenterId = storagePoolVO.getDataCenterId(); - List pools = _storagePoolDao.listByDataCenterId(dataCenterId); - for (StoragePoolVO pool : pools) { - VMTemplateStoragePoolVO ref = templateStoragePoolDao.findByPoolTemplate(pool.getId(), vm.getTemplateId()); - if (ref != null && ref.getDownloadState() == VMTemplateStorageResourceAssoc.Status.DOWNLOADED) { - templateInstallPath = ref.getInstallPath(); - break; - } - } - - if (templateInstallPath == null) { - throw new CloudRuntimeException("Did not find the template install path for template " + - vm.getTemplateId() + " on zone " + dataCenterId); - } - - Pair> pair = new Pair<>(templateInstallPath, ovfProperties); - to.setOvfProperties(pair); - } - - return to; - } - - /* - Remove OVF properties from details to be sent to hypervisor (avoid duplicate data) - */ - private void removeOvfPropertiesFromDetails(List ovfProperties, Map details) { - for (OVFPropertyTO propertyTO : ovfProperties) { - String key = propertyTO.getKey(); - details.remove(ApiConstants.OVF_PROPERTIES + "-" + key); - } - } - - /** - * Decide in which cases nested virtualization should be enabled based on (1){@code globalNestedV}, (2){@code globalNestedVPerVM}, (3){@code localNestedV}
- * Nested virtualization should be enabled when one of this cases: - *
    - *
  • (1)=TRUE, (2)=TRUE, (3) is NULL (missing)
  • - *
  • (1)=TRUE, (2)=TRUE, (3)=TRUE
  • - *
  • (1)=TRUE, (2)=FALSE
  • - *
  • (1)=FALSE, (2)=TRUE, (3)=TRUE
  • - *
- * In any other case, it shouldn't be enabled - * @param globalNestedV value of {@code 'vmware.nested.virtualization'} global config - * @param globalNestedVPerVM value of {@code 'vmware.nested.virtualization.perVM'} global config - * @param localNestedV value of {@code 'nestedVirtualizationFlag'} key in vm details if present, null if not present - * @return "true" for cases in which nested virtualization is enabled, "false" if not - */ - protected Boolean shouldEnableNestedVirtualization(Boolean globalNestedV, Boolean globalNestedVPerVM, String localNestedV){ - if (globalNestedV == null || globalNestedVPerVM == null) { - return false; - } - boolean globalNV = globalNestedV.booleanValue(); - boolean globalNVPVM = globalNestedVPerVM.booleanValue(); - - if (globalNVPVM){ - return (localNestedV == null && globalNV) || BooleanUtils.toBoolean(localNestedV); - } - return globalNV; + @Override public VirtualMachineTO implement(VirtualMachineProfile vm) { + vmwareVmImplementer.setGlobalNestedVirtualisationEnabled(VmwareEnableNestedVirtualization.value()); + vmwareVmImplementer.setGlobalNestedVPerVMEnabled(VmwareEnableNestedVirtualizationPerVM.value()); + return vmwareVmImplementer.implement(vm, toVirtualMachineTO(vm), getClusterId(vm.getId())); } - /** - * Adds {@code 'nestedVirtualizationFlag'} value to {@code details} due to if it should be enabled or not - * @param details vm details - * @param to vm to - */ - protected void configureNestedVirtualization(Map details, VirtualMachineTO to) { - Boolean globalNestedV = VmwareEnableNestedVirtualization.value(); - Boolean globalNestedVPerVM = VmwareEnableNestedVirtualizationPerVM.value(); - String localNestedV = details.get(VmDetailConstants.NESTED_VIRTUALIZATION_FLAG); - - Boolean shouldEnableNestedVirtualization = shouldEnableNestedVirtualization(globalNestedV, globalNestedVPerVM, localNestedV); - s_logger.debug("Nested virtualization requested, adding flag to vm configuration"); - details.put(VmDetailConstants.NESTED_VIRTUALIZATION_FLAG, Boolean.toString(shouldEnableNestedVirtualization)); - to.setDetails(details); - } - - private long getClusterId(long vmId) { + long getClusterId(long vmId) { long clusterId; Long hostId; @@ -552,32 +221,7 @@ private long getClusterId(long vmId) { return clusterId; } - private NicTO[] sortNicsByDeviceId(NicTO[] nics) { - - List listForSort = new ArrayList(); - for (NicTO nic : nics) { - listForSort.add(nic); - } - Collections.sort(listForSort, new Comparator() { - - @Override - public int compare(NicTO arg0, NicTO arg1) { - if (arg0.getDeviceId() < arg1.getDeviceId()) { - return -1; - } else if (arg0.getDeviceId() == arg1.getDeviceId()) { - return 0; - } - - return 1; - } - }); - - return listForSort.toArray(new NicTO[0]); - } - - @Override - @DB - public Pair getCommandHostDelegation(long hostId, Command cmd) { + @Override @DB public Pair getCommandHostDelegation(long hostId, Command cmd) { boolean needDelegation = false; if (cmd instanceof StorageSubSystemCommand) { Boolean fullCloneEnabled = VmwareFullClone.value(); @@ -585,12 +229,12 @@ public Pair getCommandHostDelegation(long hostId, Command cmd) { c.setExecuteInSequence(fullCloneEnabled); } if (cmd instanceof DownloadCommand) { - cmd.setContextParam(VmwareManager.s_vmwareOVAPackageTimeout.key(), String.valueOf(VmwareManager.s_vmwareOVAPackageTimeout.value())); + cmd.setContextParam(VmwareManager.s_vmwareOVAPackageTimeout.key(), String.valueOf(VmwareManager.s_vmwareOVAPackageTimeout.value())); } //NOTE: the hostid can be a hypervisor host, or a ssvm agent. For copycommand, if it's for volume upload, the hypervisor //type is empty, so we need to check the format of volume at first. if (cmd instanceof CopyCommand) { - CopyCommand cpyCommand = (CopyCommand) cmd; + CopyCommand cpyCommand = (CopyCommand)cmd; DataTO srcData = cpyCommand.getSrcTO(); DataStoreTO srcStoreTO = srcData.getDataStore(); DataTO destData = cpyCommand.getDestTO(); @@ -617,8 +261,8 @@ public Pair getCommandHostDelegation(long hostId, Command cmd) { return new Pair(Boolean.FALSE, new Long(hostId)); } - if (destData.getObjectType() == DataObjectType.VOLUME && destStoreTO.getRole() == DataStoreRole.Primary && - srcData.getObjectType() == DataObjectType.TEMPLATE && srcStoreTO.getRole() == DataStoreRole.Primary) { + if (destData.getObjectType() == DataObjectType.VOLUME && destStoreTO.getRole() == DataStoreRole.Primary && srcData.getObjectType() == DataObjectType.TEMPLATE + && srcStoreTO.getRole() == DataStoreRole.Primary) { needDelegation = false; } else { needDelegation = true; @@ -662,9 +306,8 @@ public Pair getCommandHostDelegation(long hostId, Command cmd) { cmd.setContextParam("vCenterSessionTimeout", String.valueOf(_vmwareMgr.getVcenterSessionTimeout())); cmd.setContextParam(VmwareManager.s_vmwareOVAPackageTimeout.key(), String.valueOf(VmwareManager.s_vmwareOVAPackageTimeout.value())); - if (cmd instanceof BackupSnapshotCommand || cmd instanceof CreatePrivateTemplateFromVolumeCommand || - cmd instanceof CreatePrivateTemplateFromSnapshotCommand || cmd instanceof CopyVolumeCommand || cmd instanceof CopyCommand || - cmd instanceof CreateVolumeOVACommand || cmd instanceof PrepareOVAPackingCommand || cmd instanceof CreateVolumeFromSnapshotCommand) { + if (cmd instanceof BackupSnapshotCommand || cmd instanceof CreatePrivateTemplateFromVolumeCommand || cmd instanceof CreatePrivateTemplateFromSnapshotCommand || cmd instanceof CopyVolumeCommand || cmd instanceof CopyCommand || cmd instanceof CreateVolumeOVACommand || cmd instanceof PrepareOVAPackingCommand + || cmd instanceof CreateVolumeFromSnapshotCommand) { String workerName = _vmwareMgr.composeWorkerName(); long checkPointId = 1; // FIXME: Fix long checkPointId = _checkPointMgr.pushCheckPoint(new VmwareCleanupMaid(hostDetails.get("guid"), workerName)); @@ -707,8 +350,7 @@ private static String resolveNameInGuid(String guid) { return tokens[0] + "@" + vCenterIp; } - @Override - public List finalizeExpungeNics(VirtualMachine vm, List nics) { + @Override public List finalizeExpungeNics(VirtualMachine vm, List nics) { List commands = new ArrayList(); List nicVOs = _nicDao.listByVmId(vm.getId()); for (NicVO nic : nicVOs) { @@ -719,26 +361,22 @@ public List finalizeExpungeNics(VirtualMachine vm, List nic // We need the traffic label to figure out which vSwitch has the // portgroup PhysicalNetworkTrafficTypeVO trafficTypeVO = _physicalNetworkTrafficTypeDao.findBy(networkVO.getPhysicalNetworkId(), networkVO.getTrafficType()); - UnregisterNicCommand unregisterNicCommand = - new UnregisterNicCommand(vm.getInstanceName(), trafficTypeVO.getVmwareNetworkLabel(), UUID.fromString(nic.getUuid())); + UnregisterNicCommand unregisterNicCommand = new UnregisterNicCommand(vm.getInstanceName(), trafficTypeVO.getVmwareNetworkLabel(), UUID.fromString(nic.getUuid())); commands.add(unregisterNicCommand); } } return commands; } - @Override - public String getConfigComponentName() { + @Override public String getConfigComponentName() { return VMwareGuru.class.getSimpleName(); } - @Override - public ConfigKey[] getConfigKeys() { + @Override public ConfigKey[] getConfigKeys() { return new ConfigKey[] {VmwareReserveCpu, VmwareReserveMemory, VmwareEnableNestedVirtualization, VmwareEnableNestedVirtualizationPerVM}; } - @Override - public List finalizeExpungeVolumes(VirtualMachine vm) { + @Override public List finalizeExpungeVolumes(VirtualMachine vm) { List commands = new ArrayList(); List volumes = _volumeDao.findByInstance(vm.getId()); @@ -776,8 +414,7 @@ public List finalizeExpungeVolumes(VirtualMachine vm) { return commands; } - @Override - public Map getClusterSettings(long vmId) { + @Override public Map getClusterSettings(long vmId) { Map details = new HashMap(); long clusterId = getClusterId(vmId); details.put(VmwareReserveCpu.key(), VmwareReserveCpu.valueIn(clusterId).toString()); @@ -799,8 +436,7 @@ private VmwareDatacenterVO getVmwareDatacenter(long zoneId) { */ private DatacenterMO getDatacenterMO(long zoneId) throws Exception { VmwareDatacenterVO vmwareDatacenter = getVmwareDatacenter(zoneId); - VmwareContext context = VmwareContextFactory.getContext(vmwareDatacenter.getVcenterHost(), - vmwareDatacenter.getUser(), vmwareDatacenter.getPassword()); + VmwareContext context = VmwareContextFactory.getContext(vmwareDatacenter.getVcenterHost(), vmwareDatacenter.getUser(), vmwareDatacenter.getPassword()); DatacenterMO dcMo = new DatacenterMO(context, vmwareDatacenter.getVmwareDatacenterName()); ManagedObjectReference dcMor = dcMo.getMor(); if (dcMor == null) { @@ -826,9 +462,8 @@ private Long getImportingVMGuestOs(VirtualMachineConfigSummary configSummary) { */ private ServiceOfferingVO createServiceOfferingForVMImporting(Integer cpus, Integer memory, Integer maxCpuUsage) { String name = "Imported-" + cpus + "-" + memory; - ServiceOfferingVO vo = new ServiceOfferingVO(name, cpus, memory, maxCpuUsage, null, null, - false, name, Storage.ProvisioningType.THIN, false, false, - null, false, Type.User, false); + ServiceOfferingVO vo = new ServiceOfferingVO(name, cpus, memory, maxCpuUsage, null, null, false, name, Storage.ProvisioningType.THIN, false, false, null, false, Type.User, + false); return serviceOfferingDao.persist(vo); } @@ -836,15 +471,12 @@ private ServiceOfferingVO createServiceOfferingForVMImporting(Integer cpus, Inte * Get service offering ID for VM being imported. * If it cannot be found it creates one and returns its ID */ - private Long getImportingVMServiceOffering(VirtualMachineConfigSummary configSummary, - VirtualMachineRuntimeInfo runtimeInfo) { + private Long getImportingVMServiceOffering(VirtualMachineConfigSummary configSummary, VirtualMachineRuntimeInfo runtimeInfo) { Integer numCpu = configSummary.getNumCpu(); Integer memorySizeMB = configSummary.getMemorySizeMB(); Integer maxCpuUsage = runtimeInfo.getMaxCpuUsage(); List offerings = serviceOfferingDao.listPublicByCpuAndMemory(numCpu, memorySizeMB); - return CollectionUtils.isEmpty(offerings) ? - createServiceOfferingForVMImporting(numCpu, memorySizeMB, maxCpuUsage).getId() : - offerings.get(0).getId(); + return CollectionUtils.isEmpty(offerings) ? createServiceOfferingForVMImporting(numCpu, memorySizeMB, maxCpuUsage).getId() : offerings.get(0).getId(); } /** @@ -876,7 +508,7 @@ private boolean isRootDisk(VirtualDisk disk, Map disksMap * Check backing info */ private void checkBackingInfo(VirtualDeviceBackingInfo backingInfo) { - if (! (backingInfo instanceof VirtualDiskFlatVer2BackingInfo)) { + if (!(backingInfo instanceof VirtualDiskFlatVer2BackingInfo)) { throw new CloudRuntimeException("Unsopported backing, expected " + VirtualDiskFlatVer2BackingInfo.class.getSimpleName()); } } @@ -899,7 +531,7 @@ private Long getPoolIdFromDatastoreUuid(String datastoreUuid) { private Long getPoolId(VirtualDisk disk) { VirtualDeviceBackingInfo backing = disk.getBacking(); checkBackingInfo(backing); - VirtualDiskFlatVer2BackingInfo info = (VirtualDiskFlatVer2BackingInfo) backing; + VirtualDiskFlatVer2BackingInfo info = (VirtualDiskFlatVer2BackingInfo)backing; String[] fileNameParts = info.getFileName().split(" "); String datastoreUuid = StringUtils.substringBetween(fileNameParts[0], "[", "]"); return getPoolIdFromDatastoreUuid(datastoreUuid); @@ -920,7 +552,7 @@ private String getVolumeNameFromFileName(String fileName) { private String getRootDiskTemplatePath(VirtualDisk rootDisk) { VirtualDeviceBackingInfo backing = rootDisk.getBacking(); checkBackingInfo(backing); - VirtualDiskFlatVer2BackingInfo info = (VirtualDiskFlatVer2BackingInfo) backing; + VirtualDiskFlatVer2BackingInfo info = (VirtualDiskFlatVer2BackingInfo)backing; VirtualDiskFlatVer2BackingInfo parent = info.getParent(); return (parent != null) ? getVolumeNameFromFileName(parent.getFileName()) : getVolumeNameFromFileName(info.getFileName()); } @@ -950,8 +582,7 @@ private Long getTemplatePoolId(VirtualMachineMO template) throws Exception { /** * Get template size */ - private Long getTemplateSize(VirtualMachineMO template, String vmInternalName, - Map disksMapping, Backup backup) throws Exception { + private Long getTemplateSize(VirtualMachineMO template, String vmInternalName, Map disksMapping, Backup backup) throws Exception { List disks = template.getVirtualDisks(); if (CollectionUtils.isEmpty(disks)) { throw new CloudRuntimeException("Couldn't find VM template size"); @@ -964,11 +595,8 @@ private Long getTemplateSize(VirtualMachineMO template, String vmInternalName, */ private VMTemplateVO createVMTemplateRecord(String vmInternalName, long guestOsId, long accountId) { Long nextTemplateId = vmTemplateDao.getNextInSequence(Long.class, "id"); - VMTemplateVO templateVO = new VMTemplateVO(nextTemplateId, "Imported-from-" + vmInternalName, - Storage.ImageFormat.OVA,false, false, false, Storage.TemplateType.USER, - null, false, 64, accountId, null, "Template imported from VM " + vmInternalName, - false, guestOsId, false, HypervisorType.VMware, null, null, - false, false, false); + VMTemplateVO templateVO = new VMTemplateVO(nextTemplateId, "Imported-from-" + vmInternalName, Storage.ImageFormat.OVA, false, false, false, Storage.TemplateType.USER, null, + false, 64, accountId, null, "Template imported from VM " + vmInternalName, false, guestOsId, false, HypervisorType.VMware, null, null, false, false, false); return vmTemplateDao.persist(templateVO); } @@ -979,9 +607,7 @@ private VMTemplateVO createVMTemplateRecord(String vmInternalName, long guestOsI */ private long getTemplateId(String templatePath, String vmInternalName, Long guestOsId, long accountId) { List poolRefs = templateStoragePoolDao.listByTemplatePath(templatePath); - return CollectionUtils.isNotEmpty(poolRefs) ? - poolRefs.get(0).getTemplateId() : - createVMTemplateRecord(vmInternalName, guestOsId, accountId).getId(); + return CollectionUtils.isNotEmpty(poolRefs) ? poolRefs.get(0).getTemplateId() : createVMTemplateRecord(vmInternalName, guestOsId, accountId).getId(); } /** @@ -990,9 +616,8 @@ private long getTemplateId(String templatePath, String vmInternalName, Long gues private void updateTemplateRef(long templateId, Long poolId, String templatePath, Long templateSize) { VMTemplateStoragePoolVO templateRef = templateStoragePoolDao.findByPoolPath(poolId, templatePath); if (templateRef == null) { - templateRef = new VMTemplateStoragePoolVO(poolId, templateId, null, 100, - VMTemplateStorageResourceAssoc.Status.DOWNLOADED, templatePath, null, - null, templatePath, templateSize); + templateRef = new VMTemplateStoragePoolVO(poolId, templateId, null, 100, VMTemplateStorageResourceAssoc.Status.DOWNLOADED, templatePath, null, null, templatePath, + templateSize); templateRef.setState(ObjectInDataStoreStateMachine.State.Ready); templateStoragePoolDao.persist(templateRef); } @@ -1001,8 +626,7 @@ private void updateTemplateRef(long templateId, Long poolId, String templatePath /** * Get template ID for VM being imported. If it is not found, it is created */ - private Long getImportingVMTemplate(List virtualDisks, DatacenterMO dcMo, String vmInternalName, - Long guestOsId, long accountId, Map disksMapping, Backup backup) throws Exception { + private Long getImportingVMTemplate(List virtualDisks, DatacenterMO dcMo, String vmInternalName, Long guestOsId, long accountId, Map disksMapping, Backup backup) throws Exception { for (VirtualDisk disk : virtualDisks) { if (isRootDisk(disk, disksMapping, backup)) { VolumeVO volumeVO = disksMapping.get(disk); @@ -1026,9 +650,7 @@ private Long getImportingVMTemplate(List virtualDisks, DatacenterMO * If VM does not exist: create and persist VM * If VM exists: update VM */ - private VMInstanceVO getVM(String vmInternalName, long templateId, long guestOsId, - long serviceOfferingId, long zoneId, long accountId, long userId, - long domainId) { + private VMInstanceVO getVM(String vmInternalName, long templateId, long guestOsId, long serviceOfferingId, long zoneId, long accountId, long userId, long domainId) { VMInstanceVO vm = _vmDao.findVMByInstanceNameIncludingRemoved(vmInternalName); if (vm != null) { vm.setState(VirtualMachine.State.Stopped); @@ -1036,16 +658,14 @@ private VMInstanceVO getVM(String vmInternalName, long templateId, long guestOsI _vmDao.update(vm.getId(), vm); if (vm.getRemoved() != null) { _vmDao.unremove(vm.getId()); - UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VM_CREATE, accountId, vm.getDataCenterId(), vm.getId(), - vm.getHostName(), vm.getServiceOfferingId(), vm.getTemplateId(), + UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VM_CREATE, accountId, vm.getDataCenterId(), vm.getId(), vm.getHostName(), vm.getServiceOfferingId(), vm.getTemplateId(), vm.getHypervisorType().toString(), VirtualMachine.class.getName(), vm.getUuid(), vm.isDisplayVm()); } return _vmDao.findById(vm.getId()); } else { long id = userVmDao.getNextInSequence(Long.class, "id"); - UserVmVO vmInstanceVO = new UserVmVO(id, vmInternalName, vmInternalName, templateId, HypervisorType.VMware, - guestOsId, false, false, domainId, accountId, userId, serviceOfferingId, - null, vmInternalName, null); + UserVmVO vmInstanceVO = new UserVmVO(id, vmInternalName, vmInternalName, templateId, HypervisorType.VMware, guestOsId, false, false, domainId, accountId, userId, + serviceOfferingId, null, vmInternalName, null); vmInstanceVO.setDataCenterId(zoneId); return userVmDao.persist(vmInstanceVO); } @@ -1054,11 +674,9 @@ private VMInstanceVO getVM(String vmInternalName, long templateId, long guestOsI /** * Create and persist volume */ - private VolumeVO createVolumeRecord(Volume.Type type, String volumeName, long zoneId, long domainId, - long accountId, long diskOfferingId, Storage.ProvisioningType provisioningType, - Long size, long instanceId, Long poolId, long templateId, Integer unitNumber, VirtualMachineDiskInfo diskInfo) { - VolumeVO volumeVO = new VolumeVO(type, volumeName, zoneId, domainId, accountId, diskOfferingId, - provisioningType, size, null, null, null); + private VolumeVO createVolumeRecord(Volume.Type type, String volumeName, long zoneId, long domainId, long accountId, long diskOfferingId, Storage.ProvisioningType provisioningType, + Long size, long instanceId, Long poolId, long templateId, Integer unitNumber, VirtualMachineDiskInfo diskInfo) { + VolumeVO volumeVO = new VolumeVO(type, volumeName, zoneId, domainId, accountId, diskOfferingId, provisioningType, size, null, null, null); volumeVO.setFormat(Storage.ImageFormat.OVA); volumeVO.setPath(volumeName); volumeVO.setState(Volume.State.Ready); @@ -1097,9 +715,7 @@ private Storage.ProvisioningType getProvisioningType(VirtualDiskFlatVer2BackingI */ private long getDiskOfferingId(long size, Storage.ProvisioningType provisioningType) { List offerings = diskOfferingDao.listAllBySizeAndProvisioningType(size, provisioningType); - return CollectionUtils.isNotEmpty(offerings) ? - offerings.get(0).getId() : - diskOfferingDao.findByUniqueName("Cloud.Com-Custom").getId(); + return CollectionUtils.isNotEmpty(offerings) ? offerings.get(0).getId() : diskOfferingDao.findByUniqueName("Cloud.Com-Custom").getId(); } protected VolumeVO updateVolume(VirtualDisk disk, Map disksMapping, VirtualMachineMO vmToImport, Long poolId, VirtualMachine vm) throws Exception { @@ -1116,8 +732,7 @@ protected VolumeVO updateVolume(VirtualDisk disk, Map dis if (volume.getRemoved() != null) { _volumeDao.unremove(volume.getId()); if (vm.getType() == Type.User) { - UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VOLUME_CREATE, volume.getAccountId(), volume.getDataCenterId(), - volume.getId(), volume.getName(), volume.getDiskOfferingId(), null, volume.getSize(), + UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VOLUME_CREATE, volume.getAccountId(), volume.getDataCenterId(), volume.getId(), volume.getName(), volume.getDiskOfferingId(), null, volume.getSize(), Volume.class.getName(), volume.getUuid(), volume.isDisplayVolume()); _resourceLimitService.incrementResourceCount(vm.getAccountId(), Resource.ResourceType.volume, volume.isDisplayVolume()); _resourceLimitService.incrementResourceCount(vm.getAccountId(), Resource.ResourceType.primary_storage, volume.isDisplayVolume(), volume.getSize()); @@ -1129,8 +744,8 @@ protected VolumeVO updateVolume(VirtualDisk disk, Map dis /** * Get volumes for VM being imported */ - private void syncVMVolumes(VMInstanceVO vmInstanceVO, List virtualDisks, - Map disksMapping, VirtualMachineMO vmToImport, Backup backup) throws Exception { + private void syncVMVolumes(VMInstanceVO vmInstanceVO, List virtualDisks, Map disksMapping, VirtualMachineMO vmToImport, Backup backup) + throws Exception { long zoneId = vmInstanceVO.getDataCenterId(); long accountId = vmInstanceVO.getAccountId(); long domainId = vmInstanceVO.getDomainId(); @@ -1155,8 +770,7 @@ private VirtualMachineDiskInfo getDiskInfo(VirtualMachineMO vmMo, Long poolId, S return diskInfoBuilder.getDiskInfoByBackingFileBaseName(volumeName, poolName); } - private VolumeVO createVolume(VirtualDisk disk, VirtualMachineMO vmToImport, long domainId, long zoneId, - long accountId, long instanceId, Long poolId, long templateId, Backup backup, boolean isImport) throws Exception { + private VolumeVO createVolume(VirtualDisk disk, VirtualMachineMO vmToImport, long domainId, long zoneId, long accountId, long instanceId, Long poolId, long templateId, Backup backup, boolean isImport) throws Exception { VMInstanceVO vm = _vmDao.findByIdIncludingRemoved(backup.getVmId()); if (vm == null) { throw new CloudRuntimeException("Failed to find the backup volume information from the VM backup"); @@ -1173,14 +787,13 @@ private VolumeVO createVolume(VirtualDisk disk, VirtualMachineMO vmToImport, lon } VirtualDeviceBackingInfo backing = disk.getBacking(); checkBackingInfo(backing); - VirtualDiskFlatVer2BackingInfo info = (VirtualDiskFlatVer2BackingInfo) backing; + VirtualDiskFlatVer2BackingInfo info = (VirtualDiskFlatVer2BackingInfo)backing; String volumeName = getVolumeName(disk, vmToImport); Storage.ProvisioningType provisioningType = getProvisioningType(info); long diskOfferingId = getDiskOfferingId(size, provisioningType); Integer unitNumber = disk.getUnitNumber(); VirtualMachineDiskInfo diskInfo = getDiskInfo(vmToImport, poolId, volumeName); - return createVolumeRecord(type, volumeName, zoneId, domainId, accountId, diskOfferingId, - provisioningType, size, instanceId, poolId, templateId, unitNumber, diskInfo); + return createVolumeRecord(type, volumeName, zoneId, domainId, accountId, diskOfferingId, provisioningType, size, instanceId, poolId, templateId, unitNumber, diskInfo); } /** @@ -1208,9 +821,8 @@ private long getPhysicalNetworkId(Long zoneId, String tag) { private NetworkVO createNetworkRecord(Long zoneId, String tag, String vlan, long accountId, long domainId) { Long physicalNetworkId = getPhysicalNetworkId(zoneId, tag); final long id = _networkDao.getNextInSequence(Long.class, "id"); - NetworkVO networkVO = new NetworkVO(id, TrafficType.Guest, Networks.Mode.Dhcp, BroadcastDomainType.Vlan, 9L, - domainId, accountId, id, "Imported-network-" + id, "Imported-network-" + id, null, Network.GuestType.Isolated, - zoneId, physicalNetworkId, ControlledEntity.ACLType.Account, false, null, false); + NetworkVO networkVO = new NetworkVO(id, TrafficType.Guest, Networks.Mode.Dhcp, BroadcastDomainType.Vlan, 9L, domainId, accountId, id, "Imported-network-" + id, + "Imported-network-" + id, null, Network.GuestType.Isolated, zoneId, physicalNetworkId, ControlledEntity.ACLType.Account, false, null, false); networkVO.setBroadcastUri(BroadcastDomainType.Vlan.toUri(vlan)); networkVO.setGuruName("ExternalGuestNetworkGuru"); networkVO.setState(Network.State.Implemented); @@ -1252,7 +864,7 @@ private Map getNetworksMapping(String[] vmNetworkNames, long */ private NetworkMO getNetworkMO(VirtualE1000 nic, VmwareContext context) { VirtualDeviceConnectInfo connectable = nic.getConnectable(); - VirtualEthernetCardNetworkBackingInfo info = (VirtualEthernetCardNetworkBackingInfo) nic.getBacking(); + VirtualEthernetCardNetworkBackingInfo info = (VirtualEthernetCardNetworkBackingInfo)nic.getBacking(); ManagedObjectReference networkMor = info.getNetwork(); if (networkMor == null) { throw new CloudRuntimeException("Could not find network for NIC on: " + nic.getMacAddress()); @@ -1261,15 +873,14 @@ private NetworkMO getNetworkMO(VirtualE1000 nic, VmwareContext context) { } private Pair getNicMacAddressAndNetworkName(VirtualDevice nicDevice, VmwareContext context) throws Exception { - VirtualE1000 nic = (VirtualE1000) nicDevice; + VirtualE1000 nic = (VirtualE1000)nicDevice; String macAddress = nic.getMacAddress(); NetworkMO networkMO = getNetworkMO(nic, context); String networkName = networkMO.getName(); return new Pair<>(macAddress, networkName); } - private void syncVMNics(VirtualDevice[] nicDevices, DatacenterMO dcMo, Map networksMapping, - VMInstanceVO vm) throws Exception { + private void syncVMNics(VirtualDevice[] nicDevices, DatacenterMO dcMo, Map networksMapping, VMInstanceVO vm) throws Exception { VmwareContext context = dcMo.getContext(); List allNics = _nicDao.listByVmId(vm.getId()); for (VirtualDevice nicDevice : nicDevices) { @@ -1298,14 +909,12 @@ private Map getDisksMapping(Backup backup, List virtualDisks = vm.getVirtualDisks(); - for (VirtualDisk disk: virtualDisks) { + for (VirtualDisk disk : virtualDisks) { if (disk.getCapacityInBytes().equals(volumeInfo.getSize())) { return disk; } @@ -1342,15 +951,14 @@ private VirtualDisk findRestoredVolume(Backup.VolumeInfo volumeInfo, VirtualMach private String getVolumeFullPath(VirtualDisk disk) { VirtualDeviceBackingInfo backing = disk.getBacking(); checkBackingInfo(backing); - VirtualDiskFlatVer2BackingInfo info = (VirtualDiskFlatVer2BackingInfo) backing; + VirtualDiskFlatVer2BackingInfo info = (VirtualDiskFlatVer2BackingInfo)backing; return info.getFileName(); } /** * Get dest volume full path */ - private String getDestVolumeFullPath(VirtualDisk restoredDisk, VirtualMachineMO restoredVm, - VirtualMachineMO vmMo) throws Exception { + private String getDestVolumeFullPath(VirtualDisk restoredDisk, VirtualMachineMO restoredVm, VirtualMachineMO vmMo) throws Exception { VirtualDisk vmDisk = vmMo.getVirtualDisks().get(0); String vmDiskPath = vmMo.getVmdkFileBaseName(vmDisk); String vmDiskFullPath = getVolumeFullPath(vmMo.getVirtualDisks().get(0)); @@ -1365,13 +973,11 @@ private ManagedObjectReference getDestStoreMor(VirtualMachineMO vmMo) throws Exc VirtualDisk vmDisk = vmMo.getVirtualDisks().get(0); VirtualDeviceBackingInfo backing = vmDisk.getBacking(); checkBackingInfo(backing); - VirtualDiskFlatVer2BackingInfo info = (VirtualDiskFlatVer2BackingInfo) backing; + VirtualDiskFlatVer2BackingInfo info = (VirtualDiskFlatVer2BackingInfo)backing; return info.getDatastore(); } - @Override - public VirtualMachine importVirtualMachineFromBackup(long zoneId, long domainId, long accountId, long userId, - String vmInternalName, Backup backup) throws Exception { + @Override public VirtualMachine importVirtualMachineFromBackup(long zoneId, long domainId, long accountId, long userId, String vmInternalName, Backup backup) throws Exception { DatacenterMO dcMo = getDatacenterMO(zoneId); VirtualMachineMO vmToImport = dcMo.findVm(vmInternalName); if (vmToImport == null) { @@ -1397,9 +1003,8 @@ public VirtualMachine importVirtualMachineFromBackup(long zoneId, long domainId, return vm; } - @Override - public boolean attachRestoredVolumeToVirtualMachine(long zoneId, String location, Backup.VolumeInfo volumeInfo, - VirtualMachine vm, long poolId, Backup backup) throws Exception { + @Override public boolean attachRestoredVolumeToVirtualMachine(long zoneId, String location, Backup.VolumeInfo volumeInfo, VirtualMachine vm, long poolId, Backup backup) + throws Exception { DatacenterMO dcMo = getDatacenterMO(zoneId); VirtualMachineMO vmRestored = findVM(dcMo, location); VirtualMachineMO vmMo = findVM(dcMo, vm.getInstanceName()); @@ -1435,8 +1040,7 @@ public boolean attachRestoredVolumeToVirtualMachine(long zoneId, String location s_logger.error("Failed to get the attached the (restored) volume " + diskPath); return false; } - createVolume(attachedDisk, vmMo, vm.getDomainId(), vm.getDataCenterId(), vm.getAccountId(), vm.getId(), - poolId, vm.getTemplateId(), backup, false); + createVolume(attachedDisk, vmMo, vm.getDomainId(), vm.getDataCenterId(), vm.getAccountId(), vm.getId(), poolId, vm.getTemplateId(), backup, false); return true; } @@ -1450,15 +1054,14 @@ private VirtualDisk getAttachedDisk(VirtualMachineMO vmMo, String diskPath) thro return null; } - @Override - public List finalizeMigrate(VirtualMachine vm, StoragePool destination) { + @Override public List finalizeMigrate(VirtualMachine vm, StoragePool destination) { List commands = new ArrayList(); // OfflineVmwareMigration: specialised migration command List volumes = _volumeDao.findByInstance(vm.getId()); List vols = new ArrayList<>(); for (Volume volume : volumes) { - VolumeTO vol = new VolumeTO(volume,destination); + VolumeTO vol = new VolumeTO(volume, destination); vols.add(vol); } MigrateVmToPoolCommand migrateVmToPoolCommand = new MigrateVmToPoolCommand(vm.getInstanceName(), vols, destination.getUuid(), true); @@ -1468,7 +1071,7 @@ public List finalizeMigrate(VirtualMachine vm, StoragePool destination) final Long destClusterId = destination.getClusterId(); final Long srcClusterId = getClusterId(vm.getId()); - if (srcClusterId != null && destClusterId != null && ! srcClusterId.equals(destClusterId)) { + if (srcClusterId != null && destClusterId != null && !srcClusterId.equals(destClusterId)) { final String srcDcName = _clusterDetailsDao.getVmwareDcName(srcClusterId); final String destDcName = _clusterDetailsDao.getVmwareDcName(destClusterId); if (srcDcName != null && destDcName != null && !srcDcName.equals(destDcName)) { @@ -1480,4 +1083,9 @@ public List finalizeMigrate(VirtualMachine vm, StoragePool destination) } return commands; } + + @Override + protected VirtualMachineTO toVirtualMachineTO(VirtualMachineProfile vmProfile) { + return super.toVirtualMachineTO(vmProfile); + } } diff --git a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/guru/VmwareVmImplementer.java b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/guru/VmwareVmImplementer.java new file mode 100644 index 000000000000..c9f8b0c337a2 --- /dev/null +++ b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/guru/VmwareVmImplementer.java @@ -0,0 +1,468 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package com.cloud.hypervisor.guru; + +import com.cloud.agent.api.storage.OVFPropertyTO; +import com.cloud.agent.api.to.DataStoreTO; +import com.cloud.agent.api.to.DiskTO; +import com.cloud.agent.api.to.NicTO; +import com.cloud.agent.api.to.VirtualMachineTO; +import com.cloud.exception.InsufficientAddressCapacityException; +import com.cloud.host.HostVO; +import com.cloud.host.dao.HostDao; +import com.cloud.hypervisor.Hypervisor; +import com.cloud.hypervisor.vmware.manager.VmwareManager; +import com.cloud.hypervisor.vmware.mo.DiskControllerType; +import com.cloud.hypervisor.vmware.mo.VirtualEthernetCardType; +import com.cloud.network.Network; +import com.cloud.network.NetworkModel; +import com.cloud.network.Networks; +import com.cloud.network.dao.NetworkDao; +import com.cloud.network.dao.NetworkVO; +import com.cloud.storage.GuestOSHypervisorVO; +import com.cloud.storage.GuestOSVO; +import com.cloud.storage.TemplateOVFPropertyVO; +import com.cloud.storage.VMTemplateStoragePoolVO; +import com.cloud.storage.VMTemplateStorageResourceAssoc; +import com.cloud.storage.Volume; +import com.cloud.storage.dao.GuestOSDao; +import com.cloud.storage.dao.GuestOSHypervisorDao; +import com.cloud.storage.dao.TemplateOVFPropertiesDao; +import com.cloud.storage.dao.VMTemplatePoolDao; +import com.cloud.template.VirtualMachineTemplate; +import com.cloud.utils.Pair; +import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.vm.DomainRouterVO; +import com.cloud.vm.NicProfile; +import com.cloud.vm.VirtualMachine; +import com.cloud.vm.VirtualMachineProfile; +import com.cloud.vm.VmDetailConstants; +import com.cloud.vm.dao.DomainRouterDao; +import com.cloud.vm.dao.NicDao; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; +import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang.BooleanUtils; +import org.apache.log4j.Logger; + +import javax.inject.Inject; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +class VmwareVmImplementer { + private static final Logger LOG = Logger.getLogger(VmwareVmImplementer.class); + + @Inject + DomainRouterDao domainRouterDao; + @Inject + GuestOSDao guestOsDao; + @Inject + GuestOSHypervisorDao guestOsHypervisorDao; + @Inject + HostDao hostDao; + @Inject + NetworkDao networkDao; + @Inject + NetworkModel networkMgr; + @Inject + NicDao nicDao; + @Inject + PrimaryDataStoreDao storagePoolDao; + @Inject + TemplateOVFPropertiesDao templateOVFPropertiesDao; + @Inject + VMTemplatePoolDao templateStoragePoolDao; + @Inject + VmwareManager vmwareMgr; + + private Boolean globalNestedVirtualisationEnabled; + private Boolean globalNestedVPerVMEnabled; + + Boolean getGlobalNestedVirtualisationEnabled() { + return globalNestedVirtualisationEnabled != null ? globalNestedVirtualisationEnabled : false; + } + + void setGlobalNestedVirtualisationEnabled(Boolean globalNestedVirtualisationEnabled) { + this.globalNestedVirtualisationEnabled = globalNestedVirtualisationEnabled; + } + + Boolean getGlobalNestedVPerVMEnabled() { + return globalNestedVPerVMEnabled != null ? globalNestedVPerVMEnabled : false; + } + + void setGlobalNestedVPerVMEnabled(Boolean globalNestedVPerVMEnabled) { + this.globalNestedVPerVMEnabled = globalNestedVPerVMEnabled; + } + + VirtualMachineTO implement(VirtualMachineProfile vm, VirtualMachineTO to, long clusterId) { + to.setBootloader(VirtualMachineTemplate.BootloaderType.HVM); + + Map details = to.getDetails(); + if (details == null) + details = new HashMap(); + + VirtualMachine.Type vmType = vm.getType(); + boolean userVm = !(vmType.equals(VirtualMachine.Type.DomainRouter) || vmType.equals(VirtualMachine.Type.ConsoleProxy) || vmType.equals(VirtualMachine.Type.SecondaryStorageVm)); + + String nicDeviceType = details.get(VmDetailConstants.NIC_ADAPTER); + if (!userVm) { + + if (nicDeviceType == null) { + details.put(VmDetailConstants.NIC_ADAPTER, vmwareMgr.getSystemVMDefaultNicAdapterType()); + } else { + try { + VirtualEthernetCardType.valueOf(nicDeviceType); + } catch (Exception e) { + LOG.warn("Invalid NIC device type " + nicDeviceType + " is specified in VM details, switch to default E1000"); + details.put(VmDetailConstants.NIC_ADAPTER, VirtualEthernetCardType.E1000.toString()); + } + } + } else { + // for user-VM, use E1000 as default + if (nicDeviceType == null) { + details.put(VmDetailConstants.NIC_ADAPTER, VirtualEthernetCardType.E1000.toString()); + } else { + try { + VirtualEthernetCardType.valueOf(nicDeviceType); + } catch (Exception e) { + LOG.warn("Invalid NIC device type " + nicDeviceType + " is specified in VM details, switch to default E1000"); + details.put(VmDetailConstants.NIC_ADAPTER, VirtualEthernetCardType.E1000.toString()); + } + } + } + + setBootParameters(vm, to, details); + + setDiskControllers(vm, details, userVm); + + List nicProfiles = getNicProfiles(vm, details); + + addReservationDetails(clusterId, details); + + if (vmType.equals(VirtualMachine.Type.DomainRouter)) { + configureDomainRouterNicsAndDetails(vm, to, details, nicProfiles); + } + + // Don't do this if the virtual machine is one of the special types + // Should only be done on user machines + if (userVm) { + configureNestedVirtualization(details, to); + } + // Determine the VM's OS description + GuestOSVO guestOS = guestOsDao.findByIdIncludingRemoved(vm.getVirtualMachine().getGuestOSId()); + to.setOs(guestOS.getDisplayName()); + to.setHostName(vm.getHostName()); + HostVO host = hostDao.findById(vm.getVirtualMachine().getHostId()); + GuestOSHypervisorVO guestOsMapping = null; + if (host != null) { + guestOsMapping = guestOsHypervisorDao.findByOsIdAndHypervisor(guestOS.getId(), Hypervisor.HypervisorType.VMware.toString(), host.getHypervisorVersion()); + } + if (guestOsMapping == null || host == null) { + to.setPlatformEmulator(null); + } else { + to.setPlatformEmulator(guestOsMapping.getGuestOsName()); + } + + List ovfProperties = getOvfPropertyList(vm, details); + + handleOvfProperties(vm, to, details, ovfProperties); + + setDetails(to, details); + + return to; + } + + private void setDetails(VirtualMachineTO to, Map details) { + if (LOG.isTraceEnabled()) { + for (String key: details.keySet()) { + LOG.trace(String.format("Detail for VM %s: %s => %s",to.getName(), key, details.get(key))); + } + } + to.setDetails(details); + } + + private void configureDomainRouterNicsAndDetails(VirtualMachineProfile vm, VirtualMachineTO to, Map details, List nicProfiles) { + NicProfile publicNicProfile = null; + for (NicProfile nicProfile : nicProfiles) { + if (nicProfile.getTrafficType() == Networks.TrafficType.Public) { + publicNicProfile = nicProfile; + break; + } + } + + if (publicNicProfile != null) { + NicTO[] nics = to.getNics(); + + // reserve extra NICs + NicTO[] expandedNics = new NicTO[nics.length + vmwareMgr.getRouterExtraPublicNics()]; + int i = 0; + int deviceId = -1; + for (i = 0; i < nics.length; i++) { + expandedNics[i] = nics[i]; + if (nics[i].getDeviceId() > deviceId) + deviceId = nics[i].getDeviceId(); + } + deviceId++; + + long networkId = publicNicProfile.getNetworkId(); + NetworkVO network = networkDao.findById(networkId); + + for (; i < nics.length + vmwareMgr.getRouterExtraPublicNics(); i++) { + NicTO nicTo = new NicTO(); + + nicTo.setDeviceId(deviceId++); + nicTo.setBroadcastType(publicNicProfile.getBroadcastType()); + nicTo.setType(publicNicProfile.getTrafficType()); + nicTo.setIp("0.0.0.0"); + nicTo.setNetmask("255.255.255.255"); + + try { + String mac = networkMgr.getNextAvailableMacAddressInNetwork(networkId); + nicTo.setMac(mac); + } catch (InsufficientAddressCapacityException e) { + throw new CloudRuntimeException("unable to allocate mac address on network: " + networkId); + } + nicTo.setDns1(publicNicProfile.getIPv4Dns1()); + nicTo.setDns2(publicNicProfile.getIPv4Dns2()); + if (publicNicProfile.getIPv4Gateway() != null) { + nicTo.setGateway(publicNicProfile.getIPv4Gateway()); + } else { + nicTo.setGateway(network.getGateway()); + } + nicTo.setDefaultNic(false); + nicTo.setBroadcastUri(publicNicProfile.getBroadCastUri()); + nicTo.setIsolationuri(publicNicProfile.getIsolationUri()); + + Integer networkRate = networkMgr.getNetworkRate(network.getId(), null); + nicTo.setNetworkRateMbps(networkRate); + + expandedNics[i] = nicTo; + } + + to.setNics(expandedNics); + + VirtualMachine router = vm.getVirtualMachine(); + DomainRouterVO routerVO = domainRouterDao.findById(router.getId()); + if (routerVO != null && routerVO.getIsRedundantRouter()) { + Long peerRouterId = nicDao.getPeerRouterId(publicNicProfile.getMacAddress(), router.getId()); + DomainRouterVO peerRouterVO = null; + if (peerRouterId != null) { + peerRouterVO = domainRouterDao.findById(peerRouterId); + if (peerRouterVO != null) { + details.put("PeerRouterInstanceName", peerRouterVO.getInstanceName()); + } + } + } + } + + StringBuffer sbMacSequence = new StringBuffer(); + for (NicTO nicTo : sortNicsByDeviceId(to.getNics())) { + sbMacSequence.append(nicTo.getMac()).append("|"); + } + if (!sbMacSequence.toString().isEmpty()) { + sbMacSequence.deleteCharAt(sbMacSequence.length() - 1); + String bootArgs = to.getBootArgs(); + to.setBootArgs(bootArgs + " nic_macs=" + sbMacSequence.toString()); + } + } + + private void handleOvfProperties(VirtualMachineProfile vm, VirtualMachineTO to, Map details, List ovfProperties) { + if (CollectionUtils.isNotEmpty(ovfProperties)) { + removeOvfPropertiesFromDetails(ovfProperties, details); + String templateInstallPath = null; + List rootDiskList = vm.getDisks().stream().filter(x -> x.getType() == Volume.Type.ROOT).collect(Collectors.toList()); + if (rootDiskList.size() != 1) { + throw new CloudRuntimeException("Did not find only one root disk for VM " + vm.getHostName()); + } + + DiskTO rootDiskTO = rootDiskList.get(0); + DataStoreTO dataStore = rootDiskTO.getData().getDataStore(); + StoragePoolVO storagePoolVO = storagePoolDao.findByUuid(dataStore.getUuid()); + long dataCenterId = storagePoolVO.getDataCenterId(); + List pools = storagePoolDao.listByDataCenterId(dataCenterId); + for (StoragePoolVO pool : pools) { + VMTemplateStoragePoolVO ref = templateStoragePoolDao.findByPoolTemplate(pool.getId(), vm.getTemplateId()); + if (ref != null && ref.getDownloadState() == VMTemplateStorageResourceAssoc.Status.DOWNLOADED) { + templateInstallPath = ref.getInstallPath(); + break; + } + } + + if (templateInstallPath == null) { + throw new CloudRuntimeException("Did not find the template install path for template " + vm.getTemplateId() + " on zone " + dataCenterId); + } + + Pair> pair = new Pair>(templateInstallPath, ovfProperties); + to.setOvfProperties(pair); + } + } + + private List getOvfPropertyList(VirtualMachineProfile vm, Map details) { + List ovfProperties = new ArrayList(); + for (String detailKey : details.keySet()) { + if (detailKey.startsWith(ApiConstants.OVF_PROPERTIES)) { + String ovfPropKey = detailKey.replace(ApiConstants.OVF_PROPERTIES + "-", ""); + TemplateOVFPropertyVO templateOVFPropertyVO = templateOVFPropertiesDao.findByTemplateAndKey(vm.getTemplateId(), ovfPropKey); + if (templateOVFPropertyVO == null) { + LOG.warn(String.format("OVF property %s not found on template, discarding", ovfPropKey)); + continue; + } + String ovfValue = details.get(detailKey); + boolean isPassword = templateOVFPropertyVO.isPassword(); + OVFPropertyTO propertyTO = new OVFPropertyTO(ovfPropKey, ovfValue, isPassword); + ovfProperties.add(propertyTO); + } + } + return ovfProperties; + } + + private void addReservationDetails(long clusterId, Map details) { + details.put(VMwareGuru.VmwareReserveCpu.key(), VMwareGuru.VmwareReserveCpu.valueIn(clusterId).toString()); + details.put(VMwareGuru.VmwareReserveMemory.key(), VMwareGuru.VmwareReserveMemory.valueIn(clusterId).toString()); + } + + private List getNicProfiles(VirtualMachineProfile vm, Map details) { + List nicProfiles = vm.getNics(); + + for (NicProfile nicProfile : nicProfiles) { + if (nicProfile.getTrafficType() == Networks.TrafficType.Guest) { + if (networkMgr.isProviderSupportServiceInNetwork(nicProfile.getNetworkId(), Network.Service.Firewall, Network.Provider.CiscoVnmc)) { + details.put("ConfigureVServiceInNexus", Boolean.TRUE.toString()); + } + break; + } + } + return nicProfiles; + } + + private void setDiskControllers(VirtualMachineProfile vm, Map details, boolean userVm) { + String diskDeviceType = details.get(VmDetailConstants.ROOT_DISK_CONTROLLER); + if (userVm) { + if (diskDeviceType == null) { + details.put(VmDetailConstants.ROOT_DISK_CONTROLLER,vmwareMgr.getRootDiskController()); + } + } + String diskController = details.get(VmDetailConstants.DATA_DISK_CONTROLLER); + if (userVm) { + if (diskController == null) { + details.put(VmDetailConstants.DATA_DISK_CONTROLLER, DiskControllerType.lsilogic.toString()); + } + } + + if (vm.getType() == VirtualMachine.Type.NetScalerVm) { + details.put(VmDetailConstants.ROOT_DISK_CONTROLLER, "scsi"); + } + } + + private void setBootParameters(VirtualMachineProfile vm, VirtualMachineTO to, Map details) { + details.put(VmDetailConstants.BOOT_MODE, to.getBootMode()); + if (vm.getParameter(VirtualMachineProfile.Param.BootIntoSetup) != null && (Boolean)vm.getParameter(VirtualMachineProfile.Param.BootIntoSetup) == true) { + to.setEnterHardwareSetup(true); + } +// there should also be +// details.put(VmDetailConstants.BOOT_TYPE, to.getBootType()); + } + + /* + Remove OVF properties from details to be sent to hypervisor (avoid duplicate data) + */ + private void removeOvfPropertiesFromDetails(List ovfProperties, Map details) { + for (OVFPropertyTO propertyTO : ovfProperties) { + String key = propertyTO.getKey(); + details.remove(ApiConstants.OVF_PROPERTIES + "-" + key); + } + } + + /** + * Adds {@code 'nestedVirtualizationFlag'} value to {@code details} due to if it should be enabled or not + * @param details vm details should not be null + * @param to vm to + */ + protected void configureNestedVirtualization(Map details, VirtualMachineTO to) { + String localNestedV = details.get(VmDetailConstants.NESTED_VIRTUALIZATION_FLAG); + + Boolean globalNestedVirtualisationEnabled = getGlobalNestedVirtualisationEnabled(); + Boolean globalNestedVPerVMEnabled = getGlobalNestedVPerVMEnabled(); + + Boolean shouldEnableNestedVirtualization = shouldEnableNestedVirtualization(globalNestedVirtualisationEnabled, globalNestedVPerVMEnabled, localNestedV); + if(LOG.isDebugEnabled()) { + LOG.debug(String.format( + "Due to '%B'(globalNestedVirtualisationEnabled) and '%B'(globalNestedVPerVMEnabled) I'm adding a flag with value %B to the vm configuration for Nested Virtualisation.", + globalNestedVirtualisationEnabled, + globalNestedVPerVMEnabled, + shouldEnableNestedVirtualization) + ); + } + details.put(VmDetailConstants.NESTED_VIRTUALIZATION_FLAG, Boolean.toString(shouldEnableNestedVirtualization)); + } + + /** + * Decide in which cases nested virtualization should be enabled based on (1){@code globalNestedV}, (2){@code globalNestedVPerVM}, (3){@code localNestedV}
+ * Nested virtualization should be enabled when one of this cases: + *
    + *
  • (1)=TRUE, (2)=TRUE, (3) is NULL (missing)
  • + *
  • (1)=TRUE, (2)=TRUE, (3)=TRUE
  • + *
  • (1)=TRUE, (2)=FALSE
  • + *
  • (1)=FALSE, (2)=TRUE, (3)=TRUE
  • + *
+ * In any other case, it shouldn't be enabled + * @param globalNestedV value of {@code 'vmware.nested.virtualization'} global config + * @param globalNestedVPerVM value of {@code 'vmware.nested.virtualization.perVM'} global config + * @param localNestedV value of {@code 'nestedVirtualizationFlag'} key in vm details if present, null if not present + * @return "true" for cases in which nested virtualization is enabled, "false" if not + */ + Boolean shouldEnableNestedVirtualization(Boolean globalNestedV, Boolean globalNestedVPerVM, String localNestedV) { + if (globalNestedV == null || globalNestedVPerVM == null) { + return false; + } + boolean globalNV = globalNestedV.booleanValue(); + boolean globalNVPVM = globalNestedVPerVM.booleanValue(); + + if (globalNVPVM) { + return (localNestedV == null && globalNV) || BooleanUtils.toBoolean(localNestedV); + } + return globalNV; + } + + private NicTO[] sortNicsByDeviceId(NicTO[] nics) { + + List listForSort = new ArrayList(); + for (NicTO nic : nics) { + listForSort.add(nic); + } + Collections.sort(listForSort, new Comparator() { + + @Override public int compare(NicTO arg0, NicTO arg1) { + if (arg0.getDeviceId() < arg1.getDeviceId()) { + return -1; + } else if (arg0.getDeviceId() == arg1.getDeviceId()) { + return 0; + } + + return 1; + } + }); + + return listForSort.toArray(new NicTO[0]); + } +} \ No newline at end of file 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 fab6f0ad938e..6168441d1db1 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 @@ -1723,10 +1723,13 @@ protected StartAnswer execute(StartCommand cmd) { String dataDiskController = vmSpec.getDetails().get(VmDetailConstants.DATA_DISK_CONTROLLER); String rootDiskController = vmSpec.getDetails().get(VmDetailConstants.ROOT_DISK_CONTROLLER); DiskTO rootDiskTO = null; - String bootMode = "bios"; + String bootMode = null; if (vmSpec.getDetails().containsKey(VmDetailConstants.BOOT_MODE)) { bootMode = vmSpec.getDetails().get(VmDetailConstants.BOOT_MODE); } + if (null == bootMode) { + bootMode = ApiConstants.BootType.BIOS.toString(); + } // 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. @@ -2285,15 +2288,7 @@ protected StartAnswer execute(StartCommand cmd) { } } - if (StringUtils.isNotBlank(bootMode) && !bootMode.equalsIgnoreCase("bios")) { - 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); - } - } - + setBootOptions(vmSpec, bootMode, vmConfigSpec); // // Configure VM @@ -2382,6 +2377,30 @@ protected StartAnswer execute(StartCommand cmd) { } } + private void setBootOptions(VirtualMachineTO vmSpec, String bootMode, VirtualMachineConfigSpec vmConfigSpec) { + VirtualMachineBootOptions bootOptions = null; + if (StringUtils.isNotBlank(bootMode) && !bootMode.equalsIgnoreCase("bios")) { + vmConfigSpec.setFirmware("efi"); + if (vmSpec.getDetails().containsKey(ApiConstants.BootType.UEFI.toString()) && "secure".equalsIgnoreCase(vmSpec.getDetails().get(ApiConstants.BootType.UEFI.toString()))) { + if (bootOptions == null) { + bootOptions = new VirtualMachineBootOptions(); + } + bootOptions.setEfiSecureBootEnabled(true); + } + } + if (vmSpec.isEnterHardwareSetup()) { + if (bootOptions == null) { + bootOptions = new VirtualMachineBootOptions(); + } + if (s_logger.isDebugEnabled()) { + s_logger.debug(String.format("configuring VM '%s' to enter hardware setup",vmSpec.getName())); + } + bootOptions.setEnterBIOSSetup(vmSpec.isEnterHardwareSetup()); + } + if (bootOptions != null) { + vmConfigSpec.setBootOptions(bootOptions); + } + } /** * Set the ovf section spec from existing vApp configuration @@ -3908,8 +3927,12 @@ protected Answer execute(RebootCommand cmd) { s_logger.trace("Detected mounted vmware tools installer for :[" + cmd.getVmName() + "]"); } try { - vmMo.rebootGuest(); - return new RebootAnswer(cmd, "reboot succeeded", true); + if (canSetEnableSetupConfig(vmMo,cmd.getVirtualMachine())) { + vmMo.rebootGuest(); + return new RebootAnswer(cmd, "reboot succeeded", true); + } else { + return new RebootAnswer(cmd, "Failed to configure VM to boot into hardware setup menu: " + vmMo.getName(), false); + } } catch (ToolsUnavailableFaultMsg e) { s_logger.warn("VMware tools is not installed at guest OS, we will perform hard reset for reboot"); } catch (Exception e) { @@ -3950,6 +3973,33 @@ protected Answer execute(RebootCommand cmd) { } } + /** + * set the boot into setup option if possible + * @param vmMo vmware view on the vm + * @param virtualMachine orchestration spec for the vm + * @return true unless reboot into setup is requested and vmware is unable to comply + */ + private boolean canSetEnableSetupConfig(VirtualMachineMO vmMo, VirtualMachineTO virtualMachine) { + if (virtualMachine.isEnterHardwareSetup()) { + VirtualMachineBootOptions bootOptions = new VirtualMachineBootOptions(); + VirtualMachineConfigSpec vmConfigSpec = new VirtualMachineConfigSpec(); + if (s_logger.isDebugEnabled()) { + s_logger.debug(String.format("configuring VM '%s' to reboot into hardware setup menu.",virtualMachine.getName())); + } + bootOptions.setEnterBIOSSetup(virtualMachine.isEnterHardwareSetup()); + vmConfigSpec.setBootOptions(bootOptions); + try { + if (!vmMo.configureVm(vmConfigSpec)) { + return false; + } + } catch (Exception e) { + s_logger.error(String.format("failed to reconfigure VM '%s' to boot into hardware setup menu",virtualMachine.getName()),e); + return false; + } + } + return true; + } + protected Answer execute(CheckVirtualMachineCommand cmd) { if (s_logger.isInfoEnabled()) { s_logger.info("Executing resource CheckVirtualMachineCommand: " + _gson.toJson(cmd)); diff --git a/plugins/hypervisors/vmware/src/main/resources/META-INF/cloudstack/vmware-compute/spring-vmware-compute-context.xml b/plugins/hypervisors/vmware/src/main/resources/META-INF/cloudstack/vmware-compute/spring-vmware-compute-context.xml index 4b9fb85f461f..ec1031d18a0b 100644 --- a/plugins/hypervisors/vmware/src/main/resources/META-INF/cloudstack/vmware-compute/spring-vmware-compute-context.xml +++ b/plugins/hypervisors/vmware/src/main/resources/META-INF/cloudstack/vmware-compute/spring-vmware-compute-context.xml @@ -35,6 +35,8 @@ + + diff --git a/plugins/hypervisors/vmware/src/test/java/com/cloud/hypervisor/guru/VMwareGuruTest.java b/plugins/hypervisors/vmware/src/test/java/com/cloud/hypervisor/guru/VmwareVmImplementerTest.java similarity index 82% rename from plugins/hypervisors/vmware/src/test/java/com/cloud/hypervisor/guru/VMwareGuruTest.java rename to plugins/hypervisors/vmware/src/test/java/com/cloud/hypervisor/guru/VmwareVmImplementerTest.java index 77042fd83074..309eb6d35c46 100755 --- a/plugins/hypervisors/vmware/src/test/java/com/cloud/hypervisor/guru/VMwareGuruTest.java +++ b/plugins/hypervisors/vmware/src/test/java/com/cloud/hypervisor/guru/VmwareVmImplementerTest.java @@ -16,11 +16,9 @@ // under the License. package com.cloud.hypervisor.guru; -import static org.mockito.Mockito.when; -import static org.mockito.Mockito.inOrder; - import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.verify; import java.util.HashMap; import java.util.Map; @@ -29,9 +27,9 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.InOrder; import org.mockito.InjectMocks; import org.mockito.Mock; +import org.mockito.Mockito; import org.mockito.MockitoAnnotations; import org.mockito.Spy; import org.powermock.core.classloader.annotations.PrepareForTest; @@ -43,19 +41,13 @@ import com.cloud.vm.VmDetailConstants; @RunWith(PowerMockRunner.class) -@PrepareForTest({ConfigKey.class, VMwareGuru.class}) +@PrepareForTest({ConfigKey.class, VmwareVmImplementer.class}) @ContextConfiguration(loader = AnnotationConfigContextLoader.class) -public class VMwareGuruTest { - - @Mock(name="VmwareEnableNestedVirtualization") - private ConfigKey vmwareNestedVirtualizationConfig; - - @Mock(name="VmwareEnableNestedVirtualizationPerVM") - private ConfigKey vmwareNestedVirtualizationPerVmConfig; +public class VmwareVmImplementerTest { @Spy @InjectMocks - private VMwareGuru _guru = new VMwareGuru(); + private VmwareVmImplementer implementer = new VmwareVmImplementer(); @Mock VirtualMachineTO vmTO; @@ -68,26 +60,25 @@ public void testSetUp() throws Exception { } private void setConfigValues(Boolean globalNV, Boolean globalNVPVM, String localNV){ - when(vmwareNestedVirtualizationConfig.value()).thenReturn(globalNV); - when(vmwareNestedVirtualizationPerVmConfig.value()).thenReturn(globalNVPVM); + implementer.setGlobalNestedVirtualisationEnabled(globalNV.booleanValue()); + implementer.setGlobalNestedVPerVMEnabled(globalNVPVM.booleanValue()); if (localNV != null) { vmDetails.put(VmDetailConstants.NESTED_VIRTUALIZATION_FLAG, localNV); } } private void executeAndVerifyTest(Boolean globalNV, Boolean globalNVPVM, String localNV, Boolean expectedResult){ - Boolean result = _guru.shouldEnableNestedVirtualization(globalNV, globalNVPVM, localNV); + Boolean result = implementer.shouldEnableNestedVirtualization(globalNV, globalNVPVM, localNV); assertEquals(expectedResult, result); } @Test public void testConfigureNestedVirtualization(){ setConfigValues(true, true, null); - _guru.configureNestedVirtualization(vmDetails, vmTO); + implementer.configureNestedVirtualization(vmDetails, vmTO); + Map spyDetails = Mockito.spy(vmDetails); - InOrder inOrder = inOrder(_guru, vmTO); - inOrder.verify(_guru).shouldEnableNestedVirtualization(true, true, null); - inOrder.verify(vmTO).setDetails(vmDetails); + verify(implementer).shouldEnableNestedVirtualization(true, true, null); assertTrue(vmDetails.containsKey(VmDetailConstants.NESTED_VIRTUALIZATION_FLAG)); assertEquals(Boolean.toString(true), vmDetails.get(VmDetailConstants.NESTED_VIRTUALIZATION_FLAG)); diff --git a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java index 28636f347a21..adadf68c49da 100644 --- a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java @@ -786,7 +786,7 @@ private boolean resetVMPasswordInternal(Long vmId, String password) throws Resou return true; } - if (rebootVirtualMachine(userId, vmId) == null) { + if (rebootVirtualMachine(userId, vmId, false) == null) { s_logger.warn("Failed to reboot the vm " + vmInstance); return false; } else { @@ -897,7 +897,7 @@ private boolean resetVMSSHKeyInternal(Long vmId, String sshPublicKey, String pas s_logger.debug("Vm " + vmInstance + " is stopped, not rebooting it as a part of SSH Key reset"); return true; } - if (rebootVirtualMachine(userId, vmId) == null) { + if (rebootVirtualMachine(userId, vmId, false) == null) { s_logger.warn("Failed to reboot the vm " + vmInstance); return false; } else { @@ -934,9 +934,13 @@ public boolean stopVirtualMachine(long userId, long vmId) { return status; } - private UserVm rebootVirtualMachine(long userId, long vmId) throws InsufficientCapacityException, ResourceUnavailableException { + private UserVm rebootVirtualMachine(long userId, long vmId, boolean enterSetup) throws InsufficientCapacityException, ResourceUnavailableException { UserVmVO vm = _vmDao.findById(vmId); + if (s_logger.isTraceEnabled()) { + s_logger.trace(String.format("reboot %s with enterSetup set to %s", vm.getInstanceName(), Boolean.toString(enterSetup))); + } + if (vm == null || vm.getState() == State.Destroyed || vm.getState() == State.Expunging || vm.getRemoved() != null) { s_logger.warn("Vm id=" + vmId + " doesn't exist"); return null; @@ -969,8 +973,18 @@ private UserVm rebootVirtualMachine(long userId, long vmId) throws InsufficientC } catch (Exception ex){ throw new CloudRuntimeException("Router start failed due to" + ex); }finally { - s_logger.info("Rebooting vm " + vm.getInstanceName()); - _itMgr.reboot(vm.getUuid(), null); + if (s_logger.isInfoEnabled()) { + s_logger.info(String.format("Rebooting vm %s%s.", vm.getInstanceName(), enterSetup? " entering hardware setup menu" : " as is")); + } + Map params = null; + if (enterSetup) { + params = new HashMap(); + params.put(VirtualMachineProfile.Param.BootIntoSetup, Boolean.TRUE); + if (s_logger.isTraceEnabled()) { + s_logger.trace(String.format("Adding %s to paramlist", VirtualMachineProfile.Param.BootIntoSetup)); + } + } + _itMgr.reboot(vm.getUuid(), params); } return _vmDao.findById(vmId); } else { @@ -2836,7 +2850,19 @@ protected boolean applyUserData(HypervisorType hyperVisorType, UserVm vm, Nic ni @Override @ActionEvent(eventType = EventTypes.EVENT_VM_START, eventDescription = "starting Vm", async = true) public UserVm startVirtualMachine(StartVMCmd cmd) throws ExecutionException, ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException, ResourceAllocationException { - return startVirtualMachine(cmd.getId(), cmd.getPodId(), cmd.getClusterId(), cmd.getHostId(), null, cmd.getDeploymentPlanner()).first(); + Map additonalParams = null; + if (cmd.getBootIntoSetup() != null) { + if (additonalParams == null) { + additonalParams = new HashMap<>(); + } + if (s_logger.isTraceEnabled()) { + s_logger.trace(String.format("Adding %s into the param map", VirtualMachineProfile.Param.BootIntoSetup.getName())); + } + + additonalParams.put(VirtualMachineProfile.Param.BootIntoSetup, cmd.getBootIntoSetup()); + } + + return startVirtualMachine(cmd.getId(), cmd.getPodId(), cmd.getClusterId(), cmd.getHostId(), additonalParams, cmd.getDeploymentPlanner()).first(); } @Override @@ -2866,7 +2892,11 @@ public UserVm rebootVirtualMachine(RebootVMCmd cmd) throws InsufficientCapacityE throw new InvalidParameterValueException("Unable to find service offering: " + serviceOfferingId + " corresponding to the vm"); } - UserVm userVm = rebootVirtualMachine(CallContext.current().getCallingUserId(), vmId); + Boolean enterSetup = cmd.getBootIntoSetup(); + if (enterSetup != null && !HypervisorType.VMware.equals(vmInstance.getHypervisorType())) { + throw new InvalidParameterValueException("booting into a hardware setup menu does not make sense on " + vmInstance.getHypervisorType()); + } + UserVm userVm = rebootVirtualMachine(CallContext.current().getCallingUserId(), vmId, enterSetup == null ? false : cmd.getBootIntoSetup()); if (userVm != null ) { // update the vmIdCountMap if the vm is in advanced shared network with out services final List nics = _nicDao.listByVmId(vmId); @@ -4288,7 +4318,7 @@ public UserVm startVirtualMachine(DeployVMCmd cmd) throws ResourceUnavailableExc Long podId = null; Long clusterId = null; Long hostId = cmd.getHostId(); - Map additonalParams = null; + Map additonalParams = new HashMap<>(); Map diskOfferingMap = cmd.getDataDiskTemplateToDiskOfferingMap(); if (cmd instanceof DeployVMCmdByAdmin) { DeployVMCmdByAdmin adminCmd = (DeployVMCmdByAdmin)cmd; @@ -4296,16 +4326,19 @@ public UserVm startVirtualMachine(DeployVMCmd cmd) throws ResourceUnavailableExc clusterId = adminCmd.getClusterId(); } if (MapUtils.isNotEmpty(cmd.getDetails()) && cmd.getDetails().containsKey(ApiConstants.BootType.UEFI.toString())) { - additonalParams = new HashMap(); Map 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())); } + if (cmd.getBootIntoSetup() != null) { + additonalParams.put(VirtualMachineProfile.Param.BootIntoSetup, cmd.getBootIntoSetup()); + } return startVirtualMachine(vmId, podId, clusterId, hostId, diskOfferingMap, additonalParams, cmd.getDeploymentPlanner()); } - private UserVm startVirtualMachine(long vmId, Long podId, Long clusterId, Long hostId, Map diskOfferingMap, Map additonalParams, String deploymentPlannerToUse) + private UserVm startVirtualMachine(long vmId, Long podId, Long clusterId, Long hostId, Map diskOfferingMap + , Map additonalParams, String deploymentPlannerToUse) throws ResourceUnavailableException, InsufficientCapacityException, ConcurrentOperationException, ResourceAllocationException { UserVmVO vm = _vmDao.findById(vmId); @@ -4640,7 +4673,8 @@ public Pair> startVirtualMach } @Override - public Pair> startVirtualMachine(long vmId, Long podId, Long clusterId, Long hostId, Map additionalParams, String deploymentPlannerToUse) + public Pair> startVirtualMachine(long vmId, Long podId, Long clusterId, Long hostId, + Map additionalParams, String deploymentPlannerToUse) throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException, ResourceAllocationException { // Input validation final Account callerAccount = CallContext.current().getCallingAccount(); @@ -4743,11 +4777,18 @@ public Pair> startVirtualMach // use it to encrypt & save the vm password encryptAndStorePassword(vm, password); - params = new HashMap(); - if (additionalParams != null) { - params.putAll(additionalParams); + params = createParameterInParameterMap(params, additionalParams, VirtualMachineProfile.Param.VmPassword, password); + } + + if(null != additionalParams && additionalParams.containsKey(VirtualMachineProfile.Param.BootIntoSetup)) { + if (! HypervisorType.VMware.equals(vm.getHypervisorType())) { + throw new InvalidParameterValueException(ApiConstants.BOOT_INTO_SETUP + " makes no sense for " + vm.getHypervisorType()); + } + Object paramValue = additionalParams.get(VirtualMachineProfile.Param.BootIntoSetup); + if (s_logger.isTraceEnabled()) { + s_logger.trace("It was specified whether to enter setup mode: " + paramValue.toString()); } - params.put(VirtualMachineProfile.Param.VmPassword, password); + params = createParameterInParameterMap(params, additionalParams, VirtualMachineProfile.Param.BootIntoSetup, paramValue); } VirtualMachineEntity vmEntity = _orchSrvc.getVirtualMachine(vm.getUuid()); @@ -4782,6 +4823,24 @@ public Pair> startVirtualMach return vmParamPair; } + private Map createParameterInParameterMap(Map params, Map parameterMap, VirtualMachineProfile.Param parameter, + Object parameterValue) { + if (s_logger.isTraceEnabled()) { + s_logger.trace(String.format("createParameterInParameterMap(%s, %s)", parameter, parameterValue)); + } + if (params == null) { + if (s_logger.isTraceEnabled()) { + s_logger.trace("creating new Parameter map"); + } + params = new HashMap<>(); + if (parameterMap != null) { + params.putAll(parameterMap); + } + } + params.put(parameter, parameterValue); + return params; + } + private Pod getDestinationPod(Long podId, boolean isRootAdmin) { Pod destinationPod = null; if (podId != null) { @@ -7114,4 +7173,4 @@ public UserVm importVM(final DataCenter zone, final Host host, final VirtualMach id, instanceName, uuidName, hypervisorType, customParameters, null, null, null, powerState); } -} \ No newline at end of file +} diff --git a/ui/index.html b/ui/index.html index ef7a461c3e94..a4ea2533e638 100644 --- a/ui/index.html +++ b/ui/index.html @@ -504,6 +504,12 @@

+
+
+ + +
+
diff --git a/ui/l10n/en.js b/ui/l10n/en.js index cb967beca671..c3b74344aeb7 100644 --- a/ui/l10n/en.js +++ b/ui/l10n/en.js @@ -788,6 +788,7 @@ var dictionary = { "label.end.vxlan":"End VXLAN", "label.endpoint":"Endpoint", "label.endpoint.or.operation":"Endpoint or Operation", +"label.enter.hardware.setup":"Enter the hardware setup menu", "label.enter.token":"Enter token", "label.error":"Error", "label.error.code":"Error Code", @@ -993,6 +994,7 @@ var dictionary = { "label.keyboard.language":"Keyboard language", "label.vm.boottype":"Boot Type", "label.vm.bootmode":"Boot Mode", +"label.vm.enterhardwaresetup":"Enter hardware setup after boot", "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 dc7708de1ad9..f06cd9046d48 100644 --- a/ui/scripts/instanceWizard.js +++ b/ui/scripts/instanceWizard.js @@ -1413,6 +1413,12 @@ bootmode : bootmode }); } + var bootintosetup = (args.data.bootintosetup == "on"); + if (bootintosetup) { + $.extend(deployVmData, { + bootintosetup : bootintosetup + }); + } if (g_hostid != null) { $.extend(deployVmData, { diff --git a/ui/scripts/instances.js b/ui/scripts/instances.js index 58cb86c33814..ec005be81aeb 100644 --- a/ui/scripts/instances.js +++ b/ui/scripts/instances.js @@ -74,6 +74,16 @@ }); } } + }, + bootintosetup: { + label: 'label.enter.hardware.setup', + isBoolean: true, + isHidden: function(args) { + if (args.context.instances[0].hypervisor !== 'VMware') { + return true; + } + return false; + } } } }, @@ -1049,7 +1059,18 @@ }); } } + }, + bootintosetup: { + label: 'label.enter.hardware.setup', + isBoolean: true, + isHidden: function(args) { + if (args.context.instances[0].hypervisor !== 'VMware') { + return true; + } + return false; + } } + } }, action: function(args) { @@ -1071,6 +1092,12 @@ hostid: args.data.hostId }); } + var bootintosetup = (args.data.bootintosetup == "on"); + if (bootintosetup) { + $.extend(data, { + bootintosetup : bootintosetup + }); + } $.ajax({ url: createURL("startVirtualMachine"), data: data, @@ -1115,10 +1142,34 @@ restart: { label: 'label.action.reboot.instance', compactLabel: 'label.reboot', + createForm: { + title: 'label.action.reboot.instance', + desc: 'message.action.reboot.instance', + preFilter: function(args) { + args.$form.find('.form-item[rel=bootintosetup]').find('input').attr('checked', 'checked'); //checked + args.$form.find('.form-item[rel=bootintosetup]').css('display', 'inline-block'); //shown + }, + fields: { + bootintosetup: { + label: 'label.enter.hardware.setup', + isBoolean: true, + isHidden: function(args) { + if (args.context.instances[0].hypervisor !== 'VMware') { + return true; + } + return false; + } + } + } + }, action: function(args) { $.ajax({ - url: createURL("rebootVirtualMachine&id=" + args.context.instances[0].id), + url: createURL("rebootVirtualMachine"), dataType: "json", + data: { + id: args.context.instances[0].id, + bootintosetup: (args.data.bootintosetup == "on") + }, async: true, success: function(json) { var jid = json.rebootvirtualmachineresponse.jobid;