CLOUDSTACK-9379: Support nested virtualization at VM level on VMware Hypervisor

This commit is contained in:
nvazquez 2016-05-09 17:06:02 -03:00
parent 4c15cfce07
commit cebee7cbda
6 changed files with 419 additions and 21 deletions

View File

@ -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

View File

@ -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))) {

View 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);
}
}

View File

@ -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();
}
} }

View File

@ -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

View 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)