mirror of
https://github.com/apache/cloudstack.git
synced 2025-10-26 08:42:29 +01:00
CLOUDSTACK-9379: Support nested virtualization at VM level on VMware Hypervisor
This commit is contained in:
parent
4c15cfce07
commit
cebee7cbda
@ -31,13 +31,13 @@ import org.apache.cloudstack.engine.subsystem.api.storage.VolumeDataFactory;
|
|||||||
import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo;
|
import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo;
|
||||||
import org.apache.cloudstack.framework.config.ConfigKey;
|
import org.apache.cloudstack.framework.config.ConfigKey;
|
||||||
import org.apache.cloudstack.framework.config.Configurable;
|
import org.apache.cloudstack.framework.config.Configurable;
|
||||||
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
|
|
||||||
import org.apache.cloudstack.storage.command.CopyCommand;
|
import org.apache.cloudstack.storage.command.CopyCommand;
|
||||||
import org.apache.cloudstack.storage.command.DeleteCommand;
|
import org.apache.cloudstack.storage.command.DeleteCommand;
|
||||||
import org.apache.cloudstack.storage.command.StorageSubSystemCommand;
|
import org.apache.cloudstack.storage.command.StorageSubSystemCommand;
|
||||||
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
|
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
|
||||||
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
|
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
|
||||||
import org.apache.cloudstack.storage.to.VolumeObjectTO;
|
import org.apache.cloudstack.storage.to.VolumeObjectTO;
|
||||||
|
import org.apache.commons.lang.BooleanUtils;
|
||||||
import org.apache.log4j.Logger;
|
import org.apache.log4j.Logger;
|
||||||
|
|
||||||
import com.cloud.agent.api.BackupSnapshotCommand;
|
import com.cloud.agent.api.BackupSnapshotCommand;
|
||||||
@ -57,7 +57,6 @@ import com.cloud.agent.api.to.DiskTO;
|
|||||||
import com.cloud.agent.api.to.NicTO;
|
import com.cloud.agent.api.to.NicTO;
|
||||||
import com.cloud.agent.api.to.VirtualMachineTO;
|
import com.cloud.agent.api.to.VirtualMachineTO;
|
||||||
import com.cloud.cluster.ClusterManager;
|
import com.cloud.cluster.ClusterManager;
|
||||||
import com.cloud.configuration.Config;
|
|
||||||
import com.cloud.exception.InsufficientAddressCapacityException;
|
import com.cloud.exception.InsufficientAddressCapacityException;
|
||||||
import com.cloud.host.Host;
|
import com.cloud.host.Host;
|
||||||
import com.cloud.host.HostVO;
|
import com.cloud.host.HostVO;
|
||||||
@ -127,8 +126,6 @@ public class VMwareGuru extends HypervisorGuruBase implements HypervisorGuru, Co
|
|||||||
@Inject
|
@Inject
|
||||||
private NetworkModel _networkMgr;
|
private NetworkModel _networkMgr;
|
||||||
@Inject
|
@Inject
|
||||||
private ConfigurationDao _configDao;
|
|
||||||
@Inject
|
|
||||||
private NicDao _nicDao;
|
private NicDao _nicDao;
|
||||||
@Inject
|
@Inject
|
||||||
private PhysicalNetworkTrafficTypeDao _physicalNetworkTrafficTypeDao;
|
private PhysicalNetworkTrafficTypeDao _physicalNetworkTrafficTypeDao;
|
||||||
@ -155,6 +152,12 @@ public class VMwareGuru extends HypervisorGuruBase implements HypervisorGuru, Co
|
|||||||
"Specify whether or not to reserve memory when not overprovisioning, In case of memory overprovisioning we will always reserve memory.", true,
|
"Specify whether or not to reserve memory when not overprovisioning, In case of memory overprovisioning we will always reserve memory.", true,
|
||||||
ConfigKey.Scope.Cluster, null);
|
ConfigKey.Scope.Cluster, null);
|
||||||
|
|
||||||
|
protected ConfigKey<Boolean> VmwareEnableNestedVirtualization = new ConfigKey<Boolean>(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<Boolean> VmwareEnableNestedVirtualizationPerVM = new ConfigKey<Boolean>(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
|
@Override
|
||||||
public HypervisorType getHypervisorType() {
|
public HypervisorType getHypervisorType() {
|
||||||
return HypervisorType.VMware;
|
return HypervisorType.VMware;
|
||||||
@ -306,13 +309,7 @@ public class VMwareGuru extends HypervisorGuruBase implements HypervisorGuru, Co
|
|||||||
// Don't do this if the virtual machine is one of the special types
|
// Don't do this if the virtual machine is one of the special types
|
||||||
// Should only be done on user machines
|
// Should only be done on user machines
|
||||||
if (userVm) {
|
if (userVm) {
|
||||||
String nestedVirt = _configDao.getValue(Config.VmwareEnableNestedVirtualization.key());
|
configureNestedVirtualization(details, to);
|
||||||
if (nestedVirt != null) {
|
|
||||||
s_logger.debug("Nested virtualization requested, adding flag to vm configuration");
|
|
||||||
details.put(VmDetailConstants.NESTED_VIRTUALIZATION_FLAG, nestedVirt);
|
|
||||||
to.setDetails(details);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// Determine the VM's OS description
|
// Determine the VM's OS description
|
||||||
GuestOSVO guestOS = _guestOsDao.findByIdIncludingRemoved(vm.getVirtualMachine().getGuestOSId());
|
GuestOSVO guestOS = _guestOsDao.findByIdIncludingRemoved(vm.getVirtualMachine().getGuestOSId());
|
||||||
@ -331,6 +328,50 @@ public class VMwareGuru extends HypervisorGuruBase implements HypervisorGuru, Co
|
|||||||
return to;
|
return to;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decide in which cases nested virtualization should be enabled based on (1){@code globalNestedV}, (2){@code globalNestedVPerVM}, (3){@code localNestedV}<br/>
|
||||||
|
* Nested virtualization should be enabled when one of this cases:
|
||||||
|
* <ul>
|
||||||
|
* <li>(1)=TRUE, (2)=TRUE, (3) is NULL (missing)</li>
|
||||||
|
* <li>(1)=TRUE, (2)=TRUE, (3)=TRUE</li>
|
||||||
|
* <li>(1)=TRUE, (2)=FALSE</li>
|
||||||
|
* <li>(1)=FALSE, (2)=TRUE, (3)=TRUE</li>
|
||||||
|
* </ul>
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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<String, String> 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) {
|
private long getClusterId(long vmId) {
|
||||||
long clusterId;
|
long clusterId;
|
||||||
Long hostId;
|
Long hostId;
|
||||||
@ -525,7 +566,7 @@ public class VMwareGuru extends HypervisorGuruBase implements HypervisorGuru, Co
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ConfigKey<?>[] getConfigKeys() {
|
public ConfigKey<?>[] getConfigKeys() {
|
||||||
return new ConfigKey<?>[] {VmwareReserveCpu, VmwareReserveMemory};
|
return new ConfigKey<?>[] {VmwareReserveCpu, VmwareReserveMemory, VmwareEnableNestedVirtualization, VmwareEnableNestedVirtualizationPerVM};
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@ -2208,7 +2208,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
|
|||||||
return new Pair<String, String>(vmInternalCSName, vmNameOnVcenter);
|
return new Pair<String, String>(vmInternalCSName, vmNameOnVcenter);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void configNestedHVSupport(VirtualMachineMO vmMo, VirtualMachineTO vmSpec, VirtualMachineConfigSpec vmConfigSpec) throws Exception {
|
protected void configNestedHVSupport(VirtualMachineMO vmMo, VirtualMachineTO vmSpec, VirtualMachineConfigSpec vmConfigSpec) throws Exception {
|
||||||
|
|
||||||
VmwareContext context = vmMo.getContext();
|
VmwareContext context = vmMo.getContext();
|
||||||
if ("true".equals(vmSpec.getDetails().get(VmDetailConstants.NESTED_VIRTUALIZATION_FLAG))) {
|
if ("true".equals(vmSpec.getDetails().get(VmDetailConstants.NESTED_VIRTUALIZATION_FLAG))) {
|
||||||
|
|||||||
157
plugins/hypervisors/vmware/test/com/cloud/hypervisor/guru/VMwareGuruTest.java
Executable file
157
plugins/hypervisors/vmware/test/com/cloud/hypervisor/guru/VMwareGuruTest.java
Executable file
@ -0,0 +1,157 @@
|
|||||||
|
// 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 static org.mockito.Mockito.when;
|
||||||
|
import static org.mockito.Mockito.inOrder;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.apache.cloudstack.framework.config.ConfigKey;
|
||||||
|
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.MockitoAnnotations;
|
||||||
|
import org.mockito.Spy;
|
||||||
|
import org.powermock.core.classloader.annotations.PrepareForTest;
|
||||||
|
import org.powermock.modules.junit4.PowerMockRunner;
|
||||||
|
import org.springframework.test.context.ContextConfiguration;
|
||||||
|
import org.springframework.test.context.support.AnnotationConfigContextLoader;
|
||||||
|
|
||||||
|
import com.cloud.agent.api.to.VirtualMachineTO;
|
||||||
|
import com.cloud.vm.VmDetailConstants;
|
||||||
|
|
||||||
|
@RunWith(PowerMockRunner.class)
|
||||||
|
@PrepareForTest({ConfigKey.class, VMwareGuru.class})
|
||||||
|
@ContextConfiguration(loader = AnnotationConfigContextLoader.class)
|
||||||
|
public class VMwareGuruTest {
|
||||||
|
|
||||||
|
@Mock(name="VmwareEnableNestedVirtualization")
|
||||||
|
private ConfigKey<Boolean> vmwareNestedVirtualizationConfig;
|
||||||
|
|
||||||
|
@Mock(name="VmwareEnableNestedVirtualizationPerVM")
|
||||||
|
private ConfigKey<Boolean> vmwareNestedVirtualizationPerVmConfig;
|
||||||
|
|
||||||
|
@Spy
|
||||||
|
@InjectMocks
|
||||||
|
private VMwareGuru _guru = new VMwareGuru();
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
VirtualMachineTO vmTO;
|
||||||
|
|
||||||
|
private Map<String,String> vmDetails = new HashMap<String, String>();
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void testSetUp() throws Exception {
|
||||||
|
MockitoAnnotations.initMocks(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setConfigValues(Boolean globalNV, Boolean globalNVPVM, String localNV){
|
||||||
|
when(vmwareNestedVirtualizationConfig.value()).thenReturn(globalNV);
|
||||||
|
when(vmwareNestedVirtualizationPerVmConfig.value()).thenReturn(globalNVPVM);
|
||||||
|
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);
|
||||||
|
assertEquals(expectedResult, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testConfigureNestedVirtualization(){
|
||||||
|
setConfigValues(true, true, null);
|
||||||
|
_guru.configureNestedVirtualization(vmDetails, vmTO);
|
||||||
|
|
||||||
|
InOrder inOrder = inOrder(_guru, vmTO);
|
||||||
|
inOrder.verify(_guru).shouldEnableNestedVirtualization(true, true, null);
|
||||||
|
inOrder.verify(vmTO).setDetails(vmDetails);
|
||||||
|
|
||||||
|
assertTrue(vmDetails.containsKey(VmDetailConstants.NESTED_VIRTUALIZATION_FLAG));
|
||||||
|
assertEquals(Boolean.toString(true), vmDetails.get(VmDetailConstants.NESTED_VIRTUALIZATION_FLAG));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testEnableNestedVirtualizationCaseGlobalNVTrueGlobalNVPVMTrueLocalNVNull(){
|
||||||
|
executeAndVerifyTest(true, true, null, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testEnableNestedVirtualizationCaseGlobalNVTrueGlobalNVPVMTrueLocalNVTrue(){
|
||||||
|
executeAndVerifyTest(true, true, "true", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testEnableNestedVirtualizationCaseGlobalNVTrueGlobalNVPVMTrueLocalNVFalse(){
|
||||||
|
executeAndVerifyTest(true, true, "false", false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testEnableNestedVirtualizationCaseGlobalNVTrueGlobalNVPVMFalseLocalNVNull(){
|
||||||
|
executeAndVerifyTest(true, false, null, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testEnableNestedVirtualizationCaseGlobalNVTrueGlobalNVPVMFalseLocalNVTrue(){
|
||||||
|
executeAndVerifyTest(true, false, "true", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testEnableNestedVirtualizationCaseGlobalNVTrueGlobalNVPVMFalseLocalNVNFalse(){
|
||||||
|
executeAndVerifyTest(true, false, "false", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testEnableNestedVirtualizationCaseGlobalNVFalseGlobalNVPVMTrueLocalNVNull(){
|
||||||
|
executeAndVerifyTest(false, true, null, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testEnableNestedVirtualizationCaseGlobalNVFalseGlobalNVPVMTrueLocalNVTrue(){
|
||||||
|
executeAndVerifyTest(false, true, "true", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testEnableNestedVirtualizationCaseGlobalNVFalseGlobalNVPVMTrueLocalNVFalse(){
|
||||||
|
executeAndVerifyTest(false, true, "false", false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testEnableNestedVirtualizationCaseGlobalNVFalseGlobalNVPVMFalseLocalNVNull(){
|
||||||
|
executeAndVerifyTest(false, false, null, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testEnableNestedVirtualizationCaseGlobalNVFalseGlobalNVPVMFalseLocalNVTrue(){
|
||||||
|
executeAndVerifyTest(false, false, "true", false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testEnableNestedVirtualizationCaseGlobalNVFalseGlobalNVPVMFalseLocalNVFalse(){
|
||||||
|
executeAndVerifyTest(false, false, "false", false);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -51,7 +51,9 @@ import org.powermock.api.mockito.PowerMockito;
|
|||||||
import org.powermock.core.classloader.annotations.PrepareForTest;
|
import org.powermock.core.classloader.annotations.PrepareForTest;
|
||||||
import org.powermock.modules.junit4.PowerMockRunner;
|
import org.powermock.modules.junit4.PowerMockRunner;
|
||||||
|
|
||||||
|
import com.vmware.vim25.HostCapability;
|
||||||
import com.vmware.vim25.ManagedObjectReference;
|
import com.vmware.vim25.ManagedObjectReference;
|
||||||
|
import com.vmware.vim25.VimPortType;
|
||||||
import com.vmware.vim25.VirtualDevice;
|
import com.vmware.vim25.VirtualDevice;
|
||||||
import com.vmware.vim25.VirtualDeviceConfigSpec;
|
import com.vmware.vim25.VirtualDeviceConfigSpec;
|
||||||
import com.vmware.vim25.VirtualMachineConfigSpec;
|
import com.vmware.vim25.VirtualMachineConfigSpec;
|
||||||
@ -65,9 +67,12 @@ import com.cloud.agent.api.to.VirtualMachineTO;
|
|||||||
import com.cloud.agent.api.to.VolumeTO;
|
import com.cloud.agent.api.to.VolumeTO;
|
||||||
import com.cloud.hypervisor.vmware.mo.DatacenterMO;
|
import com.cloud.hypervisor.vmware.mo.DatacenterMO;
|
||||||
import com.cloud.hypervisor.Hypervisor.HypervisorType;
|
import com.cloud.hypervisor.Hypervisor.HypervisorType;
|
||||||
|
import com.cloud.hypervisor.vmware.mo.HostMO;
|
||||||
import com.cloud.hypervisor.vmware.mo.VirtualMachineMO;
|
import com.cloud.hypervisor.vmware.mo.VirtualMachineMO;
|
||||||
import com.cloud.hypervisor.vmware.mo.VmwareHypervisorHost;
|
import com.cloud.hypervisor.vmware.mo.VmwareHypervisorHost;
|
||||||
|
import com.cloud.hypervisor.vmware.util.VmwareClient;
|
||||||
import com.cloud.hypervisor.vmware.util.VmwareContext;
|
import com.cloud.hypervisor.vmware.util.VmwareContext;
|
||||||
|
import com.cloud.vm.VmDetailConstants;
|
||||||
import com.cloud.storage.resource.VmwareStorageProcessor;
|
import com.cloud.storage.resource.VmwareStorageProcessor;
|
||||||
import com.cloud.storage.resource.VmwareStorageSubsystemCommandHandler;
|
import com.cloud.storage.resource.VmwareStorageSubsystemCommandHandler;
|
||||||
import com.cloud.storage.resource.VmwareStorageProcessor.VmwareStorageProcessorConfigurableFields;
|
import com.cloud.storage.resource.VmwareStorageProcessor.VmwareStorageProcessorConfigurableFields;
|
||||||
@ -135,6 +140,20 @@ public class VmwareResourceTest {
|
|||||||
DataTO destDataTO;
|
DataTO destDataTO;
|
||||||
@Mock
|
@Mock
|
||||||
PrimaryDataStoreTO destDataStoreTO;
|
PrimaryDataStoreTO destDataStoreTO;
|
||||||
|
@Mock
|
||||||
|
HostMO host;
|
||||||
|
@Mock
|
||||||
|
ManagedObjectReference hostRef;
|
||||||
|
@Mock
|
||||||
|
ManagedObjectReference computeRef;
|
||||||
|
@Mock
|
||||||
|
ManagedObjectReference envRef;
|
||||||
|
@Mock
|
||||||
|
VmwareClient client;
|
||||||
|
@Mock
|
||||||
|
VimPortType vimService;
|
||||||
|
@Mock
|
||||||
|
HostCapability hostCapability;
|
||||||
|
|
||||||
CopyCommand storageCmd;
|
CopyCommand storageCmd;
|
||||||
EnumMap<VmwareStorageProcessorConfigurableFields, Object> params = new EnumMap<VmwareStorageProcessorConfigurableFields,Object>(VmwareStorageProcessorConfigurableFields.class);
|
EnumMap<VmwareStorageProcessorConfigurableFields, Object> params = new EnumMap<VmwareStorageProcessorConfigurableFields,Object>(VmwareStorageProcessorConfigurableFields.class);
|
||||||
@ -145,6 +164,8 @@ public class VmwareResourceTest {
|
|||||||
private static final long VIDEO_CARD_MEMORY_SIZE = 65536l;
|
private static final long VIDEO_CARD_MEMORY_SIZE = 65536l;
|
||||||
private static final Boolean FULL_CLONE_FLAG = true;
|
private static final Boolean FULL_CLONE_FLAG = true;
|
||||||
|
|
||||||
|
private Map<String,String> specsArray = new HashMap<String,String>();
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setup() throws Exception {
|
public void setup() throws Exception {
|
||||||
MockitoAnnotations.initMocks(this);
|
MockitoAnnotations.initMocks(this);
|
||||||
@ -163,6 +184,17 @@ public class VmwareResourceTest {
|
|||||||
when(destDataTO.getDataStore()).thenReturn(destDataStoreTO);
|
when(destDataTO.getDataStore()).thenReturn(destDataStoreTO);
|
||||||
when(destDataStoreTO.isFullCloneFlag()).thenReturn(FULL_CLONE_FLAG);
|
when(destDataStoreTO.isFullCloneFlag()).thenReturn(FULL_CLONE_FLAG);
|
||||||
when(volume.getPath()).thenReturn(VOLUME_PATH);
|
when(volume.getPath()).thenReturn(VOLUME_PATH);
|
||||||
|
when(vmSpec.getDetails()).thenReturn(specsArray);
|
||||||
|
|
||||||
|
when(vmMo.getContext()).thenReturn(context);
|
||||||
|
when(vmMo.getRunningHost()).thenReturn(host);
|
||||||
|
when(host.getMor()).thenReturn(hostRef);
|
||||||
|
when(context.getVimClient()).thenReturn(client);
|
||||||
|
when(client.getMoRefProp(hostRef, "parent")).thenReturn(computeRef);
|
||||||
|
when(client.getMoRefProp(computeRef, "environmentBrowser")).thenReturn(envRef);
|
||||||
|
when(context.getService()).thenReturn(vimService);
|
||||||
|
when(vimService.queryTargetCapabilities(envRef, hostRef)).thenReturn(hostCapability);
|
||||||
|
when(hostCapability.isNestedHVSupported()).thenReturn(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Test successful scaling up the vm
|
//Test successful scaling up the vm
|
||||||
@ -348,4 +380,28 @@ public class VmwareResourceTest {
|
|||||||
VirtualMachineMO result = _resource.findVmOnDatacenter(context, hyperHost, volume);
|
VirtualMachineMO result = _resource.findVmOnDatacenter(context, hyperHost, volume);
|
||||||
assertEquals(vmMo, result);
|
assertEquals(vmMo, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testConfigNestedHVSupportFlagTrue() throws Exception{
|
||||||
|
specsArray.put(VmDetailConstants.NESTED_VIRTUALIZATION_FLAG, "true");
|
||||||
|
_resource.configNestedHVSupport(vmMo, vmSpec, vmConfigSpec);
|
||||||
|
verify(vmMo).getRunningHost();
|
||||||
|
verify(host).getMor();
|
||||||
|
verify(context, times(2)).getVimClient();
|
||||||
|
verify(client).getMoRefProp(hostRef, "parent");
|
||||||
|
verify(client).getMoRefProp(computeRef, "environmentBrowser");
|
||||||
|
verify(context).getService();
|
||||||
|
verify(vimService).queryTargetCapabilities(envRef, hostRef);
|
||||||
|
verify(hostCapability).isNestedHVSupported();
|
||||||
|
|
||||||
|
verify(vmConfigSpec).setNestedHVEnabled(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testConfigNestedHVSupportFlagFalse() throws Exception{
|
||||||
|
specsArray.put(VmDetailConstants.NESTED_VIRTUALIZATION_FLAG, "false");
|
||||||
|
_resource.configNestedHVSupport(vmMo, vmSpec, vmConfigSpec);
|
||||||
|
verify(vmMo, never()).getRunningHost();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1220,14 +1220,6 @@ public enum Config {
|
|||||||
"Specify whether or not to recycle hung worker VMs",
|
"Specify whether or not to recycle hung worker VMs",
|
||||||
null),
|
null),
|
||||||
VmwareHungWorkerTimeout("Advanced", ManagementServer.class, Long.class, "vmware.hung.wokervm.timeout", "7200", "Worker VM timeout in seconds", null),
|
VmwareHungWorkerTimeout("Advanced", ManagementServer.class, Long.class, "vmware.hung.wokervm.timeout", "7200", "Worker VM timeout in seconds", null),
|
||||||
VmwareEnableNestedVirtualization(
|
|
||||||
"Advanced",
|
|
||||||
ManagementServer.class,
|
|
||||||
Boolean.class,
|
|
||||||
"vmware.nested.virtualization",
|
|
||||||
"false",
|
|
||||||
"When set to true this will enable nested virtualization when this is supported by the hypervisor",
|
|
||||||
null),
|
|
||||||
VmwareVcenterSessionTimeout("Advanced", ManagementServer.class, Long.class, "vmware.vcenter.session.timeout", "1200", "VMware client timeout in seconds", null),
|
VmwareVcenterSessionTimeout("Advanced", ManagementServer.class, Long.class, "vmware.vcenter.session.timeout", "1200", "VMware client timeout in seconds", null),
|
||||||
|
|
||||||
// Midonet
|
// Midonet
|
||||||
|
|||||||
152
test/integration/smoke/test_nested_virtualization.py
Executable file
152
test/integration/smoke/test_nested_virtualization.py
Executable file
@ -0,0 +1,152 @@
|
|||||||
|
# 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.
|
||||||
|
""" Tests for Nested Virtualization
|
||||||
|
"""
|
||||||
|
#Import Local Modules
|
||||||
|
from marvin.codes import FAILED
|
||||||
|
from marvin.cloudstackTestCase import cloudstackTestCase
|
||||||
|
from marvin.lib.utils import (cleanup_resources,
|
||||||
|
get_hypervisor_type,
|
||||||
|
get_process_status)
|
||||||
|
from marvin.lib.base import (Account,
|
||||||
|
ServiceOffering,
|
||||||
|
NetworkOffering,
|
||||||
|
Configurations,
|
||||||
|
VirtualMachine,
|
||||||
|
Network)
|
||||||
|
from marvin.lib.common import (get_zone,
|
||||||
|
get_domain,
|
||||||
|
get_template)
|
||||||
|
from nose.plugins.attrib import attr
|
||||||
|
from marvin.sshClient import SshClient
|
||||||
|
import logging
|
||||||
|
|
||||||
|
class TestNestedVirtualization(cloudstackTestCase):
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def setUpClass(cls):
|
||||||
|
testClient = super(TestNestedVirtualization, cls).getClsTestClient()
|
||||||
|
cls.apiclient = testClient.getApiClient()
|
||||||
|
cls.services = testClient.getParsedTestDataConfig()
|
||||||
|
|
||||||
|
cls.logger = logging.getLogger('TestNestedVirtualization')
|
||||||
|
cls.stream_handler = logging.StreamHandler()
|
||||||
|
cls.logger.setLevel(logging.DEBUG)
|
||||||
|
cls.logger.addHandler(cls.stream_handler)
|
||||||
|
|
||||||
|
cls.zone = get_zone(cls.apiclient, testClient.getZoneForTests())
|
||||||
|
cls.services['mode'] = cls.zone.networktype
|
||||||
|
cls.services["isolated_network"]["zoneid"] = cls.zone.id
|
||||||
|
cls.domain = get_domain(cls.apiclient)
|
||||||
|
cls.service_offering = ServiceOffering.create(
|
||||||
|
cls.apiclient,
|
||||||
|
cls.services["service_offerings"]["tiny"]
|
||||||
|
)
|
||||||
|
cls.account = Account.create(cls.apiclient, services=cls.services["account"])
|
||||||
|
cls.template = get_template(
|
||||||
|
cls.apiclient,
|
||||||
|
cls.zone.id,
|
||||||
|
cls.services["ostype"]
|
||||||
|
)
|
||||||
|
cls.hypervisor = get_hypervisor_type(cls.apiclient)
|
||||||
|
|
||||||
|
cls.isolated_network_offering = NetworkOffering.create(
|
||||||
|
cls.apiclient,
|
||||||
|
cls.services["isolated_network_offering"])
|
||||||
|
# Enable Isolated Network offering
|
||||||
|
cls.isolated_network_offering.update(cls.apiclient, state='Enabled')
|
||||||
|
|
||||||
|
if cls.template == FAILED:
|
||||||
|
assert False, "get_template() failed to return template with description %s" % cls.services["ostype"]
|
||||||
|
|
||||||
|
cls.services["small"]["zoneid"] = cls.zone.id
|
||||||
|
cls.services["small"]["template"] = cls.template.id
|
||||||
|
|
||||||
|
cls.cleanup = [cls.account]
|
||||||
|
|
||||||
|
@attr(tags=["advanced"], required_hardware="true")
|
||||||
|
def test_nested_virtualization_vmware(self):
|
||||||
|
"""Test nested virtualization on Vmware hypervisor"""
|
||||||
|
if self.hypervisor.lower() not in ["vmware"]:
|
||||||
|
self.skipTest("Skipping test because suitable hypervisor/host not present")
|
||||||
|
|
||||||
|
# 1) Update nested virtualization configurations, if needed
|
||||||
|
configs = Configurations.list(self.apiclient, name="vmware.nested.virtualization")
|
||||||
|
rollback_nv = False
|
||||||
|
rollback_nv_per_vm = False
|
||||||
|
for conf in configs:
|
||||||
|
if (conf.name == "vmware.nested.virtualization" and conf.value == "false"):
|
||||||
|
config_update = Configurations.update(self.apiclient, "vmware.nested.virtualization", "true")
|
||||||
|
self.logger.debug("Updated global setting vmware.nested.virtualization to true")
|
||||||
|
rollback_nv = True
|
||||||
|
elif (conf.name == "vmware.nested.virtualization.perVM" and conf.value == "false"):
|
||||||
|
config_update = Configurations.update(self.apiclient, "vmware.nested.virtualization.perVM", "true")
|
||||||
|
self.logger.debug("Updated global setting vmware.nested.virtualization.perVM to true")
|
||||||
|
rollback_nv_per_vm = True
|
||||||
|
|
||||||
|
# 2) Deploy a vm
|
||||||
|
virtual_machine = VirtualMachine.create(
|
||||||
|
self.apiclient,
|
||||||
|
self.services["small"],
|
||||||
|
accountid=self.account.name,
|
||||||
|
domainid=self.account.domainid,
|
||||||
|
serviceofferingid=self.service_offering.id,
|
||||||
|
mode=self.services['mode']
|
||||||
|
)
|
||||||
|
self.assert_(virtual_machine is not None, "VM failed to deploy")
|
||||||
|
self.assert_(virtual_machine.state == 'Running', "VM is not running")
|
||||||
|
self.logger.debug("Deployed vm: %s" % virtual_machine.id)
|
||||||
|
|
||||||
|
isolated_network = Network.create(
|
||||||
|
self.apiclient,
|
||||||
|
self.services["isolated_network"],
|
||||||
|
self.account.name,
|
||||||
|
self.account.domainid,
|
||||||
|
networkofferingid=self.isolated_network_offering.id)
|
||||||
|
|
||||||
|
virtual_machine.add_nic(self.apiclient, isolated_network.id)
|
||||||
|
|
||||||
|
# 3) SSH into vm
|
||||||
|
ssh_client = virtual_machine.get_ssh_client()
|
||||||
|
|
||||||
|
if ssh_client:
|
||||||
|
# run ping test
|
||||||
|
result = ssh_client.execute("cat /proc/cpuinfo | grep flags")
|
||||||
|
self.logger.debug(result)
|
||||||
|
else:
|
||||||
|
self.fail("Failed to setup ssh connection to %s" % virtual_machine.public_ip)
|
||||||
|
|
||||||
|
# 4) Revert configurations, if needed
|
||||||
|
if rollback_nv:
|
||||||
|
config_update = Configurations.update(self.apiclient, "vmware.nested.virtualization", "false")
|
||||||
|
self.logger.debug("Reverted global setting vmware.nested.virtualization back to false")
|
||||||
|
if rollback_nv_per_vm:
|
||||||
|
config_update = Configurations.update(self.apiclient, "vmware.nested.virtualization", "false")
|
||||||
|
self.logger.debug("Reverted global setting vmware.nested.virtualization.perVM back to false")
|
||||||
|
|
||||||
|
#5) Check for CPU flags: vmx for Intel and svm for AMD indicates nested virtualization is enabled
|
||||||
|
self.assert_(result is not None, "Empty result for CPU flags")
|
||||||
|
res = str(result)
|
||||||
|
self.assertTrue('vmx' in res or 'svm' in res)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def tearDownClass(cls):
|
||||||
|
try:
|
||||||
|
cleanup_resources(cls.apiclient, cls.cleanup)
|
||||||
|
except Exception, e:
|
||||||
|
raise Exception("Cleanup failed with %s" % e)
|
||||||
|
|
||||||
Loading…
x
Reference in New Issue
Block a user