Repository: cloudstack
Updated Branches:
  refs/heads/master 97f9ef52a -> feaeed7b1


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


Project: http://git-wip-us.apache.org/repos/asf/cloudstack/repo
Commit: http://git-wip-us.apache.org/repos/asf/cloudstack/commit/cebee7cb
Tree: http://git-wip-us.apache.org/repos/asf/cloudstack/tree/cebee7cb
Diff: http://git-wip-us.apache.org/repos/asf/cloudstack/diff/cebee7cb

Branch: refs/heads/master
Commit: cebee7cbda62eb7967b4dacaa3911e669cb05560
Parents: 4c15cfc
Author: nvazquez <[email protected]>
Authored: Mon May 9 17:06:02 2016 -0300
Committer: nvazquez <[email protected]>
Committed: Thu Nov 17 17:51:50 2016 -0300

----------------------------------------------------------------------
 .../com/cloud/hypervisor/guru/VMwareGuru.java   |  65 ++++++--
 .../vmware/resource/VmwareResource.java         |   2 +-
 .../cloud/hypervisor/guru/VMwareGuruTest.java   | 157 +++++++++++++++++++
 .../vmware/resource/VmwareResourceTest.java     |  56 +++++++
 server/src/com/cloud/configuration/Config.java  |   8 -
 .../smoke/test_nested_virtualization.py         | 152 ++++++++++++++++++
 6 files changed, 419 insertions(+), 21 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/cebee7cb/plugins/hypervisors/vmware/src/com/cloud/hypervisor/guru/VMwareGuru.java
----------------------------------------------------------------------
diff --git 
a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/guru/VMwareGuru.java 
b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/guru/VMwareGuru.java
index 986000a..64ca406 100644
--- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/guru/VMwareGuru.java
+++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/guru/VMwareGuru.java
@@ -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

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/cebee7cb/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java
----------------------------------------------------------------------
diff --git 
a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java
 
b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java
index 522b8ae..9f38cae 100644
--- 
a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java
+++ 
b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java
@@ -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)))
 {

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/cebee7cb/plugins/hypervisors/vmware/test/com/cloud/hypervisor/guru/VMwareGuruTest.java
----------------------------------------------------------------------
diff --git 
a/plugins/hypervisors/vmware/test/com/cloud/hypervisor/guru/VMwareGuruTest.java 
b/plugins/hypervisors/vmware/test/com/cloud/hypervisor/guru/VMwareGuruTest.java
new file mode 100755
index 0000000..77042fd
--- /dev/null
+++ 
b/plugins/hypervisors/vmware/test/com/cloud/hypervisor/guru/VMwareGuruTest.java
@@ -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);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/cebee7cb/plugins/hypervisors/vmware/test/com/cloud/hypervisor/vmware/resource/VmwareResourceTest.java
----------------------------------------------------------------------
diff --git 
a/plugins/hypervisors/vmware/test/com/cloud/hypervisor/vmware/resource/VmwareResourceTest.java
 
b/plugins/hypervisors/vmware/test/com/cloud/hypervisor/vmware/resource/VmwareResourceTest.java
index 6f411dc..744c93a 100644
--- 
a/plugins/hypervisors/vmware/test/com/cloud/hypervisor/vmware/resource/VmwareResourceTest.java
+++ 
b/plugins/hypervisors/vmware/test/com/cloud/hypervisor/vmware/resource/VmwareResourceTest.java
@@ -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();
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/cebee7cb/server/src/com/cloud/configuration/Config.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/configuration/Config.java 
b/server/src/com/cloud/configuration/Config.java
index ed7f161..851b868 100644
--- a/server/src/com/cloud/configuration/Config.java
+++ b/server/src/com/cloud/configuration/Config.java
@@ -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

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/cebee7cb/test/integration/smoke/test_nested_virtualization.py
----------------------------------------------------------------------
diff --git a/test/integration/smoke/test_nested_virtualization.py 
b/test/integration/smoke/test_nested_virtualization.py
new file mode 100755
index 0000000..3b03f77
--- /dev/null
+++ b/test/integration/smoke/test_nested_virtualization.py
@@ -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)
+    
\ No newline at end of file

Reply via email to