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.framework.config.ConfigKey;
|
||||
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.DeleteCommand;
|
||||
import org.apache.cloudstack.storage.command.StorageSubSystemCommand;
|
||||
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
|
||||
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
|
||||
import org.apache.cloudstack.storage.to.VolumeObjectTO;
|
||||
import org.apache.commons.lang.BooleanUtils;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
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.VirtualMachineTO;
|
||||
import com.cloud.cluster.ClusterManager;
|
||||
import com.cloud.configuration.Config;
|
||||
import com.cloud.exception.InsufficientAddressCapacityException;
|
||||
import com.cloud.host.Host;
|
||||
import com.cloud.host.HostVO;
|
||||
@ -127,8 +126,6 @@ public class VMwareGuru extends HypervisorGuruBase implements HypervisorGuru, Co
|
||||
@Inject
|
||||
private NetworkModel _networkMgr;
|
||||
@Inject
|
||||
private ConfigurationDao _configDao;
|
||||
@Inject
|
||||
private NicDao _nicDao;
|
||||
@Inject
|
||||
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,
|
||||
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
|
||||
public HypervisorType getHypervisorType() {
|
||||
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
|
||||
// Should only be done on user machines
|
||||
if (userVm) {
|
||||
String nestedVirt = _configDao.getValue(Config.VmwareEnableNestedVirtualization.key());
|
||||
if (nestedVirt != null) {
|
||||
s_logger.debug("Nested virtualization requested, adding flag to vm configuration");
|
||||
details.put(VmDetailConstants.NESTED_VIRTUALIZATION_FLAG, nestedVirt);
|
||||
to.setDetails(details);
|
||||
|
||||
}
|
||||
configureNestedVirtualization(details, to);
|
||||
}
|
||||
// Determine the VM's OS description
|
||||
GuestOSVO guestOS = _guestOsDao.findByIdIncludingRemoved(vm.getVirtualMachine().getGuestOSId());
|
||||
@ -331,6 +328,50 @@ public class VMwareGuru extends HypervisorGuruBase implements HypervisorGuru, Co
|
||||
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) {
|
||||
long clusterId;
|
||||
Long hostId;
|
||||
@ -525,7 +566,7 @@ public class VMwareGuru extends HypervisorGuruBase implements HypervisorGuru, Co
|
||||
|
||||
@Override
|
||||
public ConfigKey<?>[] getConfigKeys() {
|
||||
return new ConfigKey<?>[] {VmwareReserveCpu, VmwareReserveMemory};
|
||||
return new ConfigKey<?>[] {VmwareReserveCpu, VmwareReserveMemory, VmwareEnableNestedVirtualization, VmwareEnableNestedVirtualizationPerVM};
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -2208,7 +2208,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
|
||||
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();
|
||||
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.modules.junit4.PowerMockRunner;
|
||||
|
||||
import com.vmware.vim25.HostCapability;
|
||||
import com.vmware.vim25.ManagedObjectReference;
|
||||
import com.vmware.vim25.VimPortType;
|
||||
import com.vmware.vim25.VirtualDevice;
|
||||
import com.vmware.vim25.VirtualDeviceConfigSpec;
|
||||
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.hypervisor.vmware.mo.DatacenterMO;
|
||||
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.VmwareHypervisorHost;
|
||||
import com.cloud.hypervisor.vmware.util.VmwareClient;
|
||||
import com.cloud.hypervisor.vmware.util.VmwareContext;
|
||||
import com.cloud.vm.VmDetailConstants;
|
||||
import com.cloud.storage.resource.VmwareStorageProcessor;
|
||||
import com.cloud.storage.resource.VmwareStorageSubsystemCommandHandler;
|
||||
import com.cloud.storage.resource.VmwareStorageProcessor.VmwareStorageProcessorConfigurableFields;
|
||||
@ -135,6 +140,20 @@ public class VmwareResourceTest {
|
||||
DataTO destDataTO;
|
||||
@Mock
|
||||
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;
|
||||
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 Boolean FULL_CLONE_FLAG = true;
|
||||
|
||||
private Map<String,String> specsArray = new HashMap<String,String>();
|
||||
|
||||
@Before
|
||||
public void setup() throws Exception {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
@ -163,6 +184,17 @@ public class VmwareResourceTest {
|
||||
when(destDataTO.getDataStore()).thenReturn(destDataStoreTO);
|
||||
when(destDataStoreTO.isFullCloneFlag()).thenReturn(FULL_CLONE_FLAG);
|
||||
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
|
||||
@ -348,4 +380,28 @@ public class VmwareResourceTest {
|
||||
VirtualMachineMO result = _resource.findVmOnDatacenter(context, hyperHost, volume);
|
||||
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",
|
||||
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),
|
||||
|
||||
// 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