From d7c6e1fa857ab04f0d0de96f2c32db26288a6488 Mon Sep 17 00:00:00 2001 From: nvazquez Date: Thu, 30 May 2019 09:39:52 -0300 Subject: [PATCH 1/3] DPDK live migrations --- .../java/com/cloud/agent/api/to/DPDKTO.java | 45 ++++++ .../java/com/cloud/agent/api/to/NicTO.java | 10 +- .../com/cloud/agent/api/MigrateCommand.java | 10 ++ .../agent/api/PrepareForMigrationAnswer.java | 16 ++ .../cloud/vm/VirtualMachineManagerImpl.java | 19 +-- .../resource/LibvirtComputingResource.java | 5 +- .../kvm/resource/LibvirtDomainXMLParser.java | 8 +- .../hypervisor/kvm/resource/LibvirtVMDef.java | 30 +++- .../hypervisor/kvm/resource/OvsVifDriver.java | 42 +++-- .../wrapper/LibvirtMigrateCommandWrapper.java | 76 +++++++++ ...virtPrepareForMigrationCommandWrapper.java | 19 ++- .../wrapper/LibvirtStartCommandWrapper.java | 1 - .../LibvirtMigrateCommandWrapperTest.java | 153 ++++++++++++++++++ .../cloud/hypervisor/HypervisorGuruBase.java | 33 ++++ .../java/com/cloud/hypervisor/KVMGuru.java | 33 ++-- .../cloud/hypervisor/kvm/dpdk/DPDKHelper.java | 15 ++ .../hypervisor/kvm/dpdk/DPDKHelperImpl.java | 88 +++++++++- .../cloud/server/ManagementServerImpl.java | 24 ++- .../java/com/cloud/vm/UserVmManagerImpl.java | 7 + .../com/cloud/hypervisor/KVMGuruTest.java | 13 -- .../kvm/dpdk/DPDKHelperImplTest.java | 110 +++++++++++++ 21 files changed, 675 insertions(+), 82 deletions(-) create mode 100644 api/src/main/java/com/cloud/agent/api/to/DPDKTO.java diff --git a/api/src/main/java/com/cloud/agent/api/to/DPDKTO.java b/api/src/main/java/com/cloud/agent/api/to/DPDKTO.java new file mode 100644 index 000000000000..e465a3421e5d --- /dev/null +++ b/api/src/main/java/com/cloud/agent/api/to/DPDKTO.java @@ -0,0 +1,45 @@ +// 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.agent.api.to; + +public class DPDKTO { + + private String path; + private String port; + private String mode; + + public DPDKTO() { + } + + public DPDKTO(String path, String port, String mode) { + this.path = path; + this.port = port; + this.mode = mode; + } + + public String getPath() { + return path; + } + + public String getPort() { + return port; + } + + public String getMode() { + return mode; + } +} \ No newline at end of file diff --git a/api/src/main/java/com/cloud/agent/api/to/NicTO.java b/api/src/main/java/com/cloud/agent/api/to/NicTO.java index 48612253f937..6a77f62cb07d 100644 --- a/api/src/main/java/com/cloud/agent/api/to/NicTO.java +++ b/api/src/main/java/com/cloud/agent/api/to/NicTO.java @@ -30,7 +30,7 @@ public class NicTO extends NetworkTO { String nicUuid; List nicSecIps; Map details; - boolean dpdkDisabled; + boolean dpdkEnabled; public NicTO() { super(); @@ -111,11 +111,11 @@ public void setDetails(final Map details) { this.details = details; } - public boolean isDpdkDisabled() { - return dpdkDisabled; + public boolean isDpdkEnabled() { + return dpdkEnabled; } - public void setDpdkDisabled(boolean dpdkDisabled) { - this.dpdkDisabled = dpdkDisabled; + public void setDpdkEnabled(boolean dpdkEnabled) { + this.dpdkEnabled = dpdkEnabled; } } diff --git a/core/src/main/java/com/cloud/agent/api/MigrateCommand.java b/core/src/main/java/com/cloud/agent/api/MigrateCommand.java index f189c72b5c90..5ca5df5beb41 100644 --- a/core/src/main/java/com/cloud/agent/api/MigrateCommand.java +++ b/core/src/main/java/com/cloud/agent/api/MigrateCommand.java @@ -24,6 +24,7 @@ import java.util.List; import java.util.Map; +import com.cloud.agent.api.to.DPDKTO; import com.cloud.agent.api.to.VirtualMachineTO; public class MigrateCommand extends Command { @@ -37,6 +38,15 @@ public class MigrateCommand extends Command { private VirtualMachineTO vmTO; private boolean executeInSequence = false; private List migrateDiskInfoList = new ArrayList<>(); + private Map dpdkInterfaceMapping = new HashMap<>(); + + public Map getDpdkInterfaceMapping() { + return dpdkInterfaceMapping; + } + + public void setDpdkInterfaceMapping(Map dpdkInterfaceMapping) { + this.dpdkInterfaceMapping = dpdkInterfaceMapping; + } protected MigrateCommand() { } diff --git a/core/src/main/java/com/cloud/agent/api/PrepareForMigrationAnswer.java b/core/src/main/java/com/cloud/agent/api/PrepareForMigrationAnswer.java index c9f23d664c95..f2ec9ef7e038 100644 --- a/core/src/main/java/com/cloud/agent/api/PrepareForMigrationAnswer.java +++ b/core/src/main/java/com/cloud/agent/api/PrepareForMigrationAnswer.java @@ -19,7 +19,15 @@ package com.cloud.agent.api; +import com.cloud.agent.api.to.DPDKTO; + +import java.util.HashMap; +import java.util.Map; + public class PrepareForMigrationAnswer extends Answer { + + private Map dpdkInterfaceMapping = new HashMap<>(); + protected PrepareForMigrationAnswer() { } @@ -34,4 +42,12 @@ public PrepareForMigrationAnswer(PrepareForMigrationCommand cmd, Exception ex) { public PrepareForMigrationAnswer(PrepareForMigrationCommand cmd) { super(cmd, true, null); } + + public void setDpdkInterfaceMapping(Map mapping) { + this.dpdkInterfaceMapping = mapping; + } + + public Map getDpdkInterfaceMapping() { + return this.dpdkInterfaceMapping; + } } diff --git a/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java b/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java index 354323ecd2f2..93450c29c4bf 100755 --- a/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java +++ b/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java @@ -39,7 +39,8 @@ import javax.inject.Inject; import javax.naming.ConfigurationException; -import org.apache.cloudstack.api.ApiConstants; +import com.cloud.agent.api.PrepareForMigrationAnswer; +import com.cloud.agent.api.to.DPDKTO; import org.apache.cloudstack.affinity.dao.AffinityGroupVMMapDao; import org.apache.cloudstack.api.command.admin.vm.MigrateVMCmd; import org.apache.cloudstack.api.command.admin.volume.MigrateVolumeCmdByAdmin; @@ -1118,8 +1119,6 @@ public void orchestrateStart(final String vmUuid, final Map details = vmTO.getDetails(); - for (String key : details.keySet()) { - if (key.startsWith(ApiConstants.EXTRA_CONFIG)) { - vmTO.addExtraConfig(key, details.get(key)); - } - } - } - // for managed storage on KVM, need to make sure the path field of the volume in question is populated with the IQN private void handlePath(final DiskTO[] disks, final HypervisorType hypervisorType) { if (hypervisorType != HypervisorType.KVM) { @@ -2370,6 +2360,11 @@ protected void migrate(final VMInstanceVO vm, final long srcHostId, final Deploy mc.setAutoConvergence(kvmAutoConvergence); mc.setHostGuid(dest.getHost().getGuid()); + Map dpdkInterfaceMapping = ((PrepareForMigrationAnswer) pfma).getDpdkInterfaceMapping(); + if (MapUtils.isNotEmpty(dpdkInterfaceMapping)) { + mc.setDpdkInterfaceMapping(dpdkInterfaceMapping); + } + try { final Answer ma = _agentMgr.send(vm.getLastHostId(), mc); if (ma == null || !ma.getResult()) { diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java index 5f2a911d6bed..cefae6048fdc 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java @@ -2706,7 +2706,10 @@ public StartupCommand[] initialize() { final KVMHostInfo info = new KVMHostInfo(_dom0MinMem, _dom0OvercommitMem); - final String capabilities = String.join(",", info.getCapabilities()); + String capabilities = String.join(",", info.getCapabilities()); + if (dpdkSupport) { + capabilities += ",dpdk"; + } final StartupRoutingCommand cmd = new StartupRoutingCommand(info.getCpus(), info.getCpuSpeed(), info.getTotalMemory(), info.getReservedMemory(), capabilities, _hypervisorType, diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtDomainXMLParser.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtDomainXMLParser.java index 97963fd2317d..51ebdb3e75f7 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtDomainXMLParser.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtDomainXMLParser.java @@ -224,9 +224,13 @@ public boolean parseDomainXML(String domXML) { def.defEthernet(dev, mac, NicModel.valueOf(model.toUpperCase()), scriptPath, networkRateKBps); } else if (type.equals("vhostuser")) { String sourcePort = getAttrValue("source", "path", nic); - String[] sourcePathParts = sourcePort.split("/"); - String port = sourcePathParts[sourcePathParts.length - 1]; + String mode = getAttrValue("source", "mode", nic); + int lastSlashIndex = sourcePort.lastIndexOf("/"); + String ovsPath = sourcePort.substring(0,lastSlashIndex); + String port = sourcePort.substring(lastSlashIndex + 1); def.setDpdkSourcePort(port); + def.setDpdkOvsPath(ovsPath); + def.setInterfaceMode(mode); } if (StringUtils.isNotBlank(slot)) { diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java index 400e16dba932..dab1af510bff 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java @@ -963,7 +963,7 @@ public String toString() { } public static class InterfaceDef { - enum GuestNetType { + public enum GuestNetType { BRIDGE("bridge"), DIRECT("direct"), NETWORK("network"), USER("user"), ETHERNET("ethernet"), INTERNAL("internal"), VHOSTUSER("vhostuser"); String _type; @@ -1176,10 +1176,24 @@ public void setDpdkSourcePort(String port) { _dpdkSourcePort = port; } - @Override - public String toString() { + public String getDpdkOvsPath() { + return _dpdkSourcePath; + } + + public void setDpdkOvsPath(String path) { + _dpdkSourcePath = path; + } + + public String getInterfaceMode() { + return _interfaceMode; + } + + public void setInterfaceMode(String mode) { + _interfaceMode = mode; + } + + public String getContent() { StringBuilder netBuilder = new StringBuilder(); - netBuilder.append("\n"); if (_netType == GuestNetType.BRIDGE) { netBuilder.append("\n"); } else if (_netType == GuestNetType.NETWORK) { @@ -1233,6 +1247,14 @@ public String toString() { if (_slot != null) { netBuilder.append(String.format("
\n", _slot)); } + return netBuilder.toString(); + } + + @Override + public String toString() { + StringBuilder netBuilder = new StringBuilder(); + netBuilder.append("\n"); + netBuilder.append(getContent()); netBuilder.append("\n"); return netBuilder.toString(); } diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/OvsVifDriver.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/OvsVifDriver.java index 8208530ce22d..7278012ef9d0 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/OvsVifDriver.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/OvsVifDriver.java @@ -87,12 +87,34 @@ public void getPifs() { s_logger.debug("done looking for pifs, no more bridges"); } + /** + * Plug interface with DPDK support: + * - Create a new port with DPDK support for the interface + * - Set the 'intf' path to the new port + */ + protected void plugDPDKInterface(InterfaceDef intf, String trafficLabel, Map extraConfig, + String vlanId, String guestOsType, NicTO nic, String nicAdapter) { + s_logger.debug("DPDK support enabled: configuring per traffic label " + trafficLabel); + String dpdkOvsPath = _libvirtComputingResource.dpdkOvsPath; + if (StringUtils.isBlank(dpdkOvsPath)) { + throw new CloudRuntimeException("DPDK is enabled on the host but no OVS path has been provided"); + } + String port = dpdkDriver.getNextDpdkPort(); + DPDKHelper.VHostUserMode dpdKvHostUserMode = dpdkDriver.getDPDKvHostUserMode(extraConfig); + dpdkDriver.addDpdkPort(_pifs.get(trafficLabel), port, vlanId, dpdKvHostUserMode, dpdkOvsPath); + String interfaceMode = dpdkDriver.getGuestInterfacesModeFromDPDKVhostUserMode(dpdKvHostUserMode); + intf.defDpdkNet(dpdkOvsPath, port, nic.getMac(), + getGuestNicModel(guestOsType, nicAdapter), 0, + dpdkDriver.getExtraDpdkProperties(extraConfig), + interfaceMode); + } + @Override public InterfaceDef plug(NicTO nic, String guestOsType, String nicAdapter, Map extraConfig) throws InternalErrorException, LibvirtException { s_logger.debug("plugging nic=" + nic); LibvirtVMDef.InterfaceDef intf = new LibvirtVMDef.InterfaceDef(); - if (!_libvirtComputingResource.dpdkSupport || nic.isDpdkDisabled()) { + if (!_libvirtComputingResource.dpdkSupport || !nic.isDpdkEnabled()) { // Let libvirt handle OVS ports creation when DPDK property is disabled or when it is enabled but disabled for the nic // For DPDK support, libvirt does not handle ports creation, invoke 'addDpdkPort' method intf.setVirtualPortType("openvswitch"); @@ -114,20 +136,8 @@ public InterfaceDef plug(NicTO nic, String guestOsType, String nicAdapter, Map dpdkPortsMapping = command.getDpdkInterfaceMapping(); + if (MapUtils.isNotEmpty(dpdkPortsMapping)) { + xmlDesc = replaceDpdkInterfaces(xmlDesc, dpdkPortsMapping); + } + dconn = libvirtUtilitiesHelper.retrieveQemuConnection(destinationUri); //run migration in thread so we can monitor it @@ -283,6 +289,76 @@ Use VIR_DOMAIN_XML_SECURE (value = 1) prior to v1.0.0. return new MigrateAnswer(command, result == null, result, null); } + /** + * Replace DPDK source path and target before migrations + */ + protected String replaceDpdkInterfaces(String xmlDesc, Map dpdkPortsMapping) throws TransformerException, ParserConfigurationException, IOException, SAXException { + InputStream in = IOUtils.toInputStream(xmlDesc); + + DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance(); + DocumentBuilder docBuilder = docFactory.newDocumentBuilder(); + Document doc = docBuilder.parse(in); + + // Get the root element + Node domainNode = doc.getFirstChild(); + + NodeList domainChildNodes = domainNode.getChildNodes(); + + for (int i = 0; i < domainChildNodes.getLength(); i++) { + Node domainChildNode = domainChildNodes.item(i); + + if ("devices".equals(domainChildNode.getNodeName())) { + NodeList devicesChildNodes = domainChildNode.getChildNodes(); + + for (int x = 0; x < devicesChildNodes.getLength(); x++) { + Node deviceChildNode = devicesChildNodes.item(x); + + if ("interface".equals(deviceChildNode.getNodeName())) { + Node interfaceNode = deviceChildNode; + NamedNodeMap attributes = interfaceNode.getAttributes(); + Node interfaceTypeAttr = attributes.getNamedItem("type"); + + if ("vhostuser".equals(interfaceTypeAttr.getNodeValue())) { + NodeList diskChildNodes = interfaceNode.getChildNodes(); + + String mac = null; + for (int y = 0; y < diskChildNodes.getLength(); y++) { + Node diskChildNode = diskChildNodes.item(y); + if (!"mac".equals(diskChildNode.getNodeName())) { + continue; + } + mac = diskChildNode.getAttributes().getNamedItem("address").getNodeValue(); + } + + if (StringUtils.isNotBlank(mac)) { + DPDKTO to = dpdkPortsMapping.get(mac); + + for (int z = 0; z < diskChildNodes.getLength(); z++) { + Node diskChildNode = diskChildNodes.item(z); + + if ("target".equals(diskChildNode.getNodeName())) { + Node targetNode = diskChildNode; + Node targetNodeAttr = targetNode.getAttributes().getNamedItem("dev"); + targetNodeAttr.setNodeValue(to.getPort()); + } else if ("source".equals(diskChildNode.getNodeName())) { + Node sourceNode = diskChildNode; + NamedNodeMap attrs = sourceNode.getAttributes(); + Node path = attrs.getNamedItem("path"); + path.setNodeValue(to.getPath() + "/" + to.getPort()); + Node mode = attrs.getNamedItem("mode"); + mode.setNodeValue(to.getMode()); + } + } + } + } + } + } + } + } + + return getXml(doc); + } + /** * In case of a local file, it deletes the file on the source host/storage pool. Otherwise (for instance iScsi) it disconnects the disk on the source storage pool.
* This method must be executed after a successful migration to a target storage pool, cleaning up the source storage. diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtPrepareForMigrationCommandWrapper.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtPrepareForMigrationCommandWrapper.java index 5c9980be86d1..1633926f2c50 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtPrepareForMigrationCommandWrapper.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtPrepareForMigrationCommandWrapper.java @@ -22,20 +22,26 @@ import com.cloud.agent.api.Answer; import com.cloud.agent.api.PrepareForMigrationAnswer; import com.cloud.agent.api.PrepareForMigrationCommand; +import com.cloud.agent.api.to.DPDKTO; import com.cloud.agent.api.to.DiskTO; import com.cloud.agent.api.to.NicTO; import com.cloud.agent.api.to.VirtualMachineTO; import com.cloud.exception.InternalErrorException; import com.cloud.hypervisor.kvm.resource.LibvirtComputingResource; +import com.cloud.hypervisor.kvm.resource.LibvirtVMDef; +import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.InterfaceDef.GuestNetType; import com.cloud.hypervisor.kvm.storage.KVMStoragePoolManager; import com.cloud.resource.CommandWrapper; import com.cloud.resource.ResourceWrapper; import com.cloud.storage.Volume; +import org.apache.commons.collections.MapUtils; import org.apache.log4j.Logger; import org.libvirt.Connect; import org.libvirt.LibvirtException; import java.net.URISyntaxException; +import java.util.HashMap; +import java.util.Map; @ResourceWrapper(handles = PrepareForMigrationCommand.class) public final class LibvirtPrepareForMigrationCommandWrapper extends CommandWrapper { @@ -63,8 +69,13 @@ public Answer execute(final PrepareForMigrationCommand command, final LibvirtCom final LibvirtUtilitiesHelper libvirtUtilitiesHelper = libvirtComputingResource.getLibvirtUtilitiesHelper(); final Connect conn = libvirtUtilitiesHelper.getConnectionByVmName(vm.getName()); + Map dpdkInterfaceMapping = new HashMap<>(); for (final NicTO nic : nics) { - libvirtComputingResource.getVifDriver(nic.getType(), nic.getName()).plug(nic, null, "", null); + LibvirtVMDef.InterfaceDef interfaceDef = libvirtComputingResource.getVifDriver(nic.getType(), nic.getName()).plug(nic, null, "", vm.getExtraConfig()); + if (interfaceDef != null && interfaceDef.getNetType() == GuestNetType.VHOSTUSER) { + DPDKTO to = new DPDKTO(interfaceDef.getDpdkOvsPath(), interfaceDef.getDpdkSourcePort(), interfaceDef.getInterfaceMode()); + dpdkInterfaceMapping.put(nic.getMac(), to); + } } /* setup disks, e.g for iso */ @@ -81,7 +92,11 @@ public Answer execute(final PrepareForMigrationCommand command, final LibvirtCom return new PrepareForMigrationAnswer(command, "failed to connect physical disks to host"); } - return new PrepareForMigrationAnswer(command); + PrepareForMigrationAnswer answer = new PrepareForMigrationAnswer(command); + if (MapUtils.isNotEmpty(dpdkInterfaceMapping)) { + answer.setDpdkInterfaceMapping(dpdkInterfaceMapping); + } + return answer; } catch (final LibvirtException e) { return new PrepareForMigrationAnswer(command, e.toString()); } catch (final InternalErrorException e) { diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtStartCommandWrapper.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtStartCommandWrapper.java index f3839f0fc761..9c97bd4770fc 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtStartCommandWrapper.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtStartCommandWrapper.java @@ -69,7 +69,6 @@ public Answer execute(final StartCommand command, final LibvirtComputingResource for (final NicTO nic : nics) { if (vmSpec.getType() != VirtualMachine.Type.User) { nic.setPxeDisable(true); - nic.setDpdkDisabled(true); } } diff --git a/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtMigrateCommandWrapperTest.java b/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtMigrateCommandWrapperTest.java index 5289481b66d9..1eff40dabe79 100644 --- a/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtMigrateCommandWrapperTest.java +++ b/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtMigrateCommandWrapperTest.java @@ -37,6 +37,7 @@ import org.junit.Assert; import org.junit.Before; +import com.cloud.agent.api.to.DPDKTO; import org.junit.Test; import org.junit.runner.RunWith; import org.libvirt.Connect; @@ -302,6 +303,146 @@ public class LibvirtMigrateCommandWrapperTest { " \n" + ""; + private String sourceDPDKVMToMigrate = + "\n" + + " i-2-33-VM\n" + + " 14c5c052-46cb-4301-a00a-28f6cc1dc605\n" + + " Other PV (64-bit)\n" + + " 9437184\n" + + " 9437184\n" + + " \n" + + " \n" + + " \n" + + " 2\n" + + " \n" + + " 4000\n" + + " \n" + + " \n" + + " /machine\n" + + " \n" + + " \n" + + " \n" + + " Apache Software Foundation\n" + + " CloudStack KVM Hypervisor\n" + + " 14c5c052-46cb-4301-a00a-28f6cc1dc605\n" + + " \n" + + " \n" + + " \n" + + " hvm\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " destroy\n" + + " restart\n" + + " destroy\n" + + " \n" + + " /usr/libexec/qemu-kvm\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " afb1d2e401fe4694940b\n" + + " \n" + + "
\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + "
\n" + + " \n" + + " \n" + + " \n" + + "
\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + "
\n" + + " \n" + + " \n" + + " \n" + + "
\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + "
\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + "
\n" + + " \n" + + " \n" + + " \n" + + "
\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + "