From 92fd5bee3d827d6811d077098d30c52f1d625ab0 Mon Sep 17 00:00:00 2001 From: Rohit Yadav Date: Thu, 30 Mar 2017 11:39:43 +0530 Subject: [PATCH 1/2] CLOUDSTACK-9591: Fix systemvmtemplate to not include network details This removes nic/network specific details while exporting the systemvmtemplate for vmware (ova file). Having this causes the ssvms to not deploy in dvswitch-based vmware environments that have no vswitch portgroups (dummy etc). Tested this on a local Trillian env. Signed-off-by: Rohit Yadav --- tools/appliance/build.sh | 6 ------ 1 file changed, 6 deletions(-) diff --git a/tools/appliance/build.sh b/tools/appliance/build.sh index 9ac43885cd8..0b31cc1a558 100755 --- a/tools/appliance/build.sh +++ b/tools/appliance/build.sh @@ -433,12 +433,6 @@ scsi0:0.writeThrough = "false" scsi0.virtualDev = "lsilogic" scsi0.present = "TRUE" vmci0.unrestricted = "false" -ethernet0.present = "TRUE" -ethernet0.virtualDev = "e1000" -ethernet0.connectionType = "bridged" -ethernet0.startConnected = "TRUE" -ethernet0.addressType = "generated" -ethernet0.wakeonpcktrcv = "false" vcpu.hotadd = "false" vcpu.hotremove = "false" firmware = "bios" From 00e1b462f62366cbe3135c812de2972eb6af68c2 Mon Sep 17 00:00:00 2001 From: Rohit Yadav Date: Thu, 30 Mar 2017 17:27:19 +0530 Subject: [PATCH 2/2] CLOUDSTACK-9591: Fix guest VM ovf xml to remove network nodes This removes network details from the guest VM template OVF xml before deploying a VM which would fail in case of dvswitch-based vmware environment with no dummy/existing vswitch. Signed-off-by: Rohit Yadav --- .../vmware/mo/HypervisorHostHelper.java | 76 +++++- .../vmware/mo/HypervisorHostHelperTest.java | 251 ++++++++++++++++-- 2 files changed, 297 insertions(+), 30 deletions(-) diff --git a/vmware-base/src/com/cloud/hypervisor/vmware/mo/HypervisorHostHelper.java b/vmware-base/src/com/cloud/hypervisor/vmware/mo/HypervisorHostHelper.java index 71c007d2279..ef3f0ae327c 100644 --- a/vmware-base/src/com/cloud/hypervisor/vmware/mo/HypervisorHostHelper.java +++ b/vmware-base/src/com/cloud/hypervisor/vmware/mo/HypervisorHostHelper.java @@ -16,17 +16,6 @@ // under the License. package com.cloud.hypervisor.vmware.mo; -import java.io.File; -import java.net.URI; -import java.net.URISyntaxException; -import java.security.InvalidParameterException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Map; - -import org.apache.log4j.Logger; - import com.cloud.exception.CloudException; import com.cloud.hypervisor.vmware.util.VmwareContext; import com.cloud.hypervisor.vmware.util.VmwareHelper; @@ -92,6 +81,33 @@ import com.vmware.vim25.VirtualSCSISharing; import com.vmware.vim25.VmwareDistributedVirtualSwitchPvlanSpec; import com.vmware.vim25.VmwareDistributedVirtualSwitchVlanIdSpec; import com.vmware.vim25.VmwareDistributedVirtualSwitchVlanSpec; +import org.apache.log4j.Logger; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.traversal.DocumentTraversal; +import org.w3c.dom.traversal.NodeFilter; +import org.w3c.dom.traversal.NodeIterator; +import org.xml.sax.SAXException; + +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.IOException; +import java.io.StringWriter; +import java.net.URI; +import java.net.URISyntaxException; +import java.security.InvalidParameterException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; public class HypervisorHostHelper { private static final Logger s_logger = Logger.getLogger(HypervisorHostHelper.class); @@ -1477,6 +1493,40 @@ public class HypervisorHostHelper { return url; } + public static String removeOVFNetwork(final String ovfString) { + if (ovfString == null || ovfString.isEmpty()) { + return ovfString; + } + try { + final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + final Document doc = factory.newDocumentBuilder().parse(new ByteArrayInputStream(ovfString.getBytes())); + final DocumentTraversal traversal = (DocumentTraversal) doc; + final NodeIterator iterator = traversal.createNodeIterator(doc.getDocumentElement(), NodeFilter.SHOW_ELEMENT, null, true); + for (Node n = iterator.nextNode(); n != null; n = iterator.nextNode()) { + final Element e = (Element) n; + if ("NetworkSection".equals(e.getTagName())) { + if (e.getParentNode() != null) { + e.getParentNode().removeChild(e); + } + } else if ("rasd:Connection".equals(e.getTagName())) { + if (e.getParentNode() != null && e.getParentNode().getParentNode() != null) { + e.getParentNode().getParentNode().removeChild(e.getParentNode()); + } + } + } + final DOMSource domSource = new DOMSource(doc); + final StringWriter writer = new StringWriter(); + final StreamResult result = new StreamResult(writer); + final TransformerFactory tf = TransformerFactory.newInstance(); + final Transformer transformer = tf.newTransformer(); + transformer.transform(domSource, result); + return writer.toString(); + } catch (SAXException | IOException | ParserConfigurationException | TransformerException e) { + s_logger.warn("Unexpected exception caught while removing network elements from OVF:", e); + } + return ovfString; + } + public static void importVmFromOVF(VmwareHypervisorHost host, String ovfFilePath, String vmName, DatastoreMO dsMo, String diskOption, ManagedObjectReference morRp, ManagedObjectReference morHost) throws Exception { @@ -1488,9 +1538,9 @@ public class HypervisorHostHelper { importSpecParams.setEntityName(vmName); importSpecParams.setDeploymentOption(""); importSpecParams.setDiskProvisioning(diskOption); // diskOption: thin, thick, etc - //importSpecParams.setPropertyMapping(null); - String ovfDescriptor = HttpNfcLeaseMO.readOvfContent(ovfFilePath); + String ovfDescriptor = removeOVFNetwork(HttpNfcLeaseMO.readOvfContent(ovfFilePath)); + VmwareContext context = host.getContext(); OvfCreateImportSpecResult ovfImportResult = context.getService().createImportSpec(context.getServiceContent().getOvfManager(), ovfDescriptor, morRp, dsMo.getMor(), importSpecParams); diff --git a/vmware-base/test/com/cloud/hypervisor/vmware/mo/HypervisorHostHelperTest.java b/vmware-base/test/com/cloud/hypervisor/vmware/mo/HypervisorHostHelperTest.java index 6997805b234..2fc9995091b 100644 --- a/vmware-base/test/com/cloud/hypervisor/vmware/mo/HypervisorHostHelperTest.java +++ b/vmware-base/test/com/cloud/hypervisor/vmware/mo/HypervisorHostHelperTest.java @@ -16,22 +16,7 @@ // under the License. package com.cloud.hypervisor.vmware.mo; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.assertNull; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyZeroInteractions; -import static org.mockito.Mockito.when; - -import org.junit.After; -import org.junit.AfterClass; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Test; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; - +import com.cloud.hypervisor.vmware.util.VmwareContext; import com.vmware.vim25.AboutInfo; import com.vmware.vim25.BoolPolicy; import com.vmware.vim25.DVPortgroupConfigInfo; @@ -41,8 +26,21 @@ import com.vmware.vim25.LongPolicy; import com.vmware.vim25.ServiceContent; import com.vmware.vim25.VMwareDVSPortSetting; import com.vmware.vim25.VmwareDistributedVirtualSwitchVlanIdSpec; +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; -import com.cloud.hypervisor.vmware.util.VmwareContext; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyZeroInteractions; +import static org.mockito.Mockito.when; public class HypervisorHostHelperTest { @Mock @@ -557,4 +555,223 @@ public class HypervisorHostHelperTest { String cloudNetworkName = HypervisorHostHelper.composeCloudNetworkName(prefix, vlanId, svlanId, networkRateMbps, vSwitchName); assertEquals("cloud.guest.400.s123.512.1-vSwitch2", cloudNetworkName); } + + @Test + public void testOvfDomRewriter() { + final String ovfString = "" + + "" + + "\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " Virtual disk information\n" + + " \n" + + " \n" + + " \n" + + " The list of logical networks\n" + + " \n" + + " The bridged network\n" + + " \n" + + " \n" + + " \n" + + " A virtual machine\n" + + " macchinina-vmware\n" + + " \n" + + " The kind of installed guest operating system\n" + + " \n" + + " \n" + + " Virtual hardware requirements\n" + + " \n" + + " Virtual Hardware Family\n" + + " 0\n" + + " macchinina-vmware\n" + + " vmx-07\n" + + " \n" + + " \n" + + " hertz * 10^6\n" + + " Number of Virtual CPUs\n" + + " 1 virtual CPU(s)\n" + + " 1\n" + + " 3\n" + + " 1\n" + + " \n" + + " \n" + + " byte * 2^20\n" + + " Memory Size\n" + + " 256MB of memory\n" + + " 2\n" + + " 4\n" + + " 256\n" + + " \n" + + " \n" + + " 0\n" + + " SCSI Controller\n" + + " scsiController0\n" + + " 3\n" + + " lsilogic\n" + + " 6\n" + + " \n" + + " \n" + + " 0\n" + + " IDE Controller\n" + + " ideController0\n" + + " 4\n" + + " 5\n" + + " \n" + + " \n" + + " 0\n" + + " false\n" + + " cdrom0\n" + + " 5\n" + + " 4\n" + + " 15\n" + + " \n" + + " \n" + + " 0\n" + + " disk0\n" + + " ovf:/disk/vmdisk1\n" + + " 6\n" + + " 3\n" + + " 17\n" + + " \n" + + " \n" + + " 2\n" + + " true\n" + + " bridged\n" + + " E1000 ethernet adapter on "bridged"\n" + + " ethernet0\n" + + " 7\n" + + " E1000\n" + + " 10\n" + + " \n" + + " \n" + + " \n" + + " false\n" + + " video\n" + + " 8\n" + + " 24\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " false\n" + + " vmci\n" + + " 9\n" + + " vmware.vmci\n" + + " 1\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " A human-readable annotation\n" + + " macchinina-vmware\n" + + " \n" + + " \n" + + ""; + + final String expected = "" + + "" + + "\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " Virtual disk information\n" + + " \n" + + " \n \n" + + " \n" + + " A virtual machine\n" + + " macchinina-vmware\n" + + " \n" + + " The kind of installed guest operating system\n" + + " \n" + + " \n" + + " Virtual hardware requirements\n" + + " \n" + + " Virtual Hardware Family\n" + + " 0\n" + + " macchinina-vmware\n" + + " vmx-07\n" + + " \n" + + " \n" + + " hertz * 10^6\n" + + " Number of Virtual CPUs\n" + + " 1 virtual CPU(s)\n" + + " 1\n" + + " 3\n" + + " 1\n" + + " \n" + + " \n" + + " byte * 2^20\n" + + " Memory Size\n" + + " 256MB of memory\n" + + " 2\n" + + " 4\n" + + " 256\n" + + " \n" + + " \n" + + " 0\n" + + " SCSI Controller\n" + + " scsiController0\n" + + " 3\n" + + " lsilogic\n" + + " 6\n" + + " \n" + + " \n" + + " 0\n" + + " IDE Controller\n" + + " ideController0\n" + + " 4\n" + + " 5\n" + + " \n" + + " \n" + + " 0\n" + + " false\n" + + " cdrom0\n" + + " 5\n" + + " 4\n" + + " 15\n" + + " \n" + + " \n" + + " 0\n" + + " disk0\n" + + " ovf:/disk/vmdisk1\n" + + " 6\n" + + " 3\n" + + " 17\n" + + " \n \n" + + " \n" + + " false\n" + + " video\n" + + " 8\n" + + " 24\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " false\n" + + " vmci\n" + + " 9\n" + + " vmware.vmci\n" + + " 1\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " A human-readable annotation\n" + + " macchinina-vmware\n" + + " \n" + + " \n" + + ""; + assertEquals(expected, HypervisorHostHelper.removeOVFNetwork(ovfString)); + } }