You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by ek...@apache.org on 2015/05/13 11:35:50 UTC
[08/41] git commit: updated refs/heads/master to 45c0fa2
Refactoring the LibvirtComputingResource
- Adding LibvirtMigrateCommandWrapper
- 1 unit tests added
- KVM hypervisor plugin with 10.9% coverage
Project: http://git-wip-us.apache.org/repos/asf/cloudstack/repo
Commit: http://git-wip-us.apache.org/repos/asf/cloudstack/commit/28e55462
Tree: http://git-wip-us.apache.org/repos/asf/cloudstack/tree/28e55462
Diff: http://git-wip-us.apache.org/repos/asf/cloudstack/diff/28e55462
Branch: refs/heads/master
Commit: 28e55462f15bdd8699e97b668c4ffc01735a533d
Parents: d730efb
Author: wilderrodrigues <wr...@schubergphilis.com>
Authored: Thu Apr 23 13:31:58 2015 +0200
Committer: wilderrodrigues <wr...@schubergphilis.com>
Committed: Wed May 6 19:20:41 2015 +0200
----------------------------------------------------------------------
.../kvm/resource/LibvirtComputingResource.java | 185 +++----------------
.../kvm/resource/MigrateKVMAsync.java | 38 ++++
.../wrapper/LibvirtMigrateCommandWrapper.java | 183 ++++++++++++++++++
.../resource/wrapper/LibvirtRequestWrapper.java | 2 +
.../resource/LibvirtComputingResourceTest.java | 75 ++++++++
5 files changed, 319 insertions(+), 164 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/28e55462/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java
index 69f291e..893f82d 100644
--- a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java
+++ b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java
@@ -47,14 +47,11 @@ import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.UUID;
-import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -119,8 +116,6 @@ import com.cloud.agent.api.MaintainAnswer;
import com.cloud.agent.api.MaintainCommand;
import com.cloud.agent.api.ManageSnapshotAnswer;
import com.cloud.agent.api.ManageSnapshotCommand;
-import com.cloud.agent.api.MigrateAnswer;
-import com.cloud.agent.api.MigrateCommand;
import com.cloud.agent.api.ModifySshKeysCommand;
import com.cloud.agent.api.ModifyStoragePoolAnswer;
import com.cloud.agent.api.ModifyStoragePoolCommand;
@@ -298,9 +293,6 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
private String _dcId;
private String _pod;
private String _clusterId;
- private int _migrateSpeed;
- private int _migrateDowntime;
- private int _migratePauseAfter;
private long _hvVersion;
private long _kernelVersion;
@@ -397,6 +389,22 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
return _storagePoolMgr;
}
+ public String getPrivateIp() {
+ return _privateIp;
+ }
+
+ public int getMigrateDowntime() {
+ return _migrateDowntime;
+ }
+
+ public int getMigratePauseAfter() {
+ return _migratePauseAfter;
+ }
+
+ public int getMigrateSpeed() {
+ return _migrateSpeed;
+ }
+
private static final class KeyValueInterpreter extends OutputInterpreter {
private final Map<String, String> map = new HashMap<String, String>();
@@ -459,6 +467,10 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
protected String _videoHw;
protected int _videoRam;
protected Pair<Integer,Integer> hostOsVersion;
+ protected int _migrateSpeed;
+ protected int _migrateDowntime;
+ protected int _migratePauseAfter;
+
private final Map <String, String> _pifs = new HashMap<String, String>();
private final Map<String, VmStats> _vmStats = new ConcurrentHashMap<String, VmStats>();
@@ -1299,9 +1311,7 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
}
try {
- if (cmd instanceof MigrateCommand) {
- return execute((MigrateCommand)cmd);
- } else if (cmd instanceof PingTestCommand) {
+ if (cmd instanceof PingTestCommand) {
return execute((PingTestCommand)cmd);
} else if (cmd instanceof CheckVirtualMachineCommand) {
return execute((CheckVirtualMachineCommand)cmd);
@@ -3054,159 +3064,6 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
return command.execute();
}
- private Answer execute(final MigrateCommand cmd) {
- final String vmName = cmd.getVmName();
-
- String result = null;
-
- List<InterfaceDef> ifaces = null;
- List<DiskDef> disks = null;
-
- Domain dm = null;
- Connect dconn = null;
- Domain destDomain = null;
- Connect conn = null;
- String xmlDesc = null;
- try {
- conn = LibvirtConnection.getConnectionByVmName(vmName);
- ifaces = getInterfaces(conn, vmName);
- disks = getDisks(conn, vmName);
- dm = conn.domainLookupByName(vmName);
- /*
- We replace the private IP address with the address of the destination host.
- This is because the VNC listens on the private IP address of the hypervisor,
- but that address is ofcourse different on the target host.
-
- MigrateCommand.getDestinationIp() returns the private IP address of the target
- hypervisor. So it's safe to use.
-
- The Domain.migrate method from libvirt supports passing a different XML
- description for the instance to be used on the target host.
-
- This is supported by libvirt-java from version 0.50.0
- */
- xmlDesc = dm.getXMLDesc(0).replace(_privateIp, cmd.getDestinationIp());
-
- dconn = new Connect("qemu+tcp://" + cmd.getDestinationIp() + "/system");
-
- //run migration in thread so we can monitor it
- s_logger.info("Live migration of instance " + vmName + " initiated");
- final ExecutorService executor = Executors.newFixedThreadPool(1);
- final Callable<Domain> worker = new MigrateKVMAsync(dm, dconn, xmlDesc, vmName, cmd.getDestinationIp());
- final Future<Domain> migrateThread = executor.submit(worker);
- executor.shutdown();
- long sleeptime = 0;
- while (!executor.isTerminated()) {
- Thread.sleep(100);
- sleeptime += 100;
- if (sleeptime == 1000) { // wait 1s before attempting to set downtime on migration, since I don't know of a VIR_DOMAIN_MIGRATING state
- if (_migrateDowntime > 0 ) {
- try {
- final int setDowntime = dm.migrateSetMaxDowntime(_migrateDowntime);
- if (setDowntime == 0 ) {
- s_logger.debug("Set max downtime for migration of " + vmName + " to " + String.valueOf(_migrateDowntime) + "ms");
- }
- } catch (final LibvirtException e) {
- s_logger.debug("Failed to set max downtime for migration, perhaps migration completed? Error: " + e.getMessage());
- }
- }
- }
- if (sleeptime % 1000 == 0) {
- s_logger.info("Waiting for migration of " + vmName + " to complete, waited " + sleeptime + "ms");
- }
-
- // pause vm if we meet the vm.migrate.pauseafter threshold and not already paused
- if (_migratePauseAfter > 0 && sleeptime > _migratePauseAfter && dm.getInfo().state == DomainState.VIR_DOMAIN_RUNNING ) {
- s_logger.info("Pausing VM " + vmName + " due to property vm.migrate.pauseafter setting to " + _migratePauseAfter+ "ms to complete migration");
- try {
- dm.suspend();
- } catch (final LibvirtException e) {
- // pause could be racy if it attempts to pause right when vm is finished, simply warn
- s_logger.info("Failed to pause vm " + vmName + " : " + e.getMessage());
- }
- }
- }
- s_logger.info("Migration thread for " + vmName + " is done");
-
- destDomain = migrateThread.get(10, TimeUnit.SECONDS);
-
- if (destDomain != null) {
- for (final DiskDef disk : disks) {
- cleanupDisk(disk);
- }
- }
- } catch (final LibvirtException e) {
- s_logger.debug("Can't migrate domain: " + e.getMessage());
- result = e.getMessage();
- } catch (final InterruptedException e) {
- s_logger.debug("Interrupted while migrating domain: " + e.getMessage());
- result = e.getMessage();
- } catch (final ExecutionException e) {
- s_logger.debug("Failed to execute while migrating domain: " + e.getMessage());
- result = e.getMessage();
- } catch (final TimeoutException e) {
- s_logger.debug("Timed out while migrating domain: " + e.getMessage());
- result = e.getMessage();
- } finally {
- try {
- if (dm != null) {
- if (dm.isPersistent() == 1) {
- dm.undefine();
- }
- dm.free();
- }
- if (dconn != null) {
- dconn.close();
- }
- if (destDomain != null) {
- destDomain.free();
- }
- } catch (final LibvirtException e) {
- s_logger.trace("Ignoring libvirt error.", e);
- }
- }
-
- if (result != null) {
- } else {
- destroyNetworkRulesForVM(conn, vmName);
- for (final InterfaceDef iface : ifaces) {
- // We don't know which "traffic type" is associated with
- // each interface at this point, so inform all vif drivers
- for (final VifDriver vifDriver : getAllVifDrivers()) {
- vifDriver.unplug(iface);
- }
- }
- }
-
- return new MigrateAnswer(cmd, result == null, result, null);
- }
-
- private class MigrateKVMAsync implements Callable<Domain> {
- Domain dm = null;
- Connect dconn = null;
- String dxml = "";
- String vmName = "";
- String destIp = "";
-
- MigrateKVMAsync(final Domain dm, final Connect dconn, final String dxml, final String vmName, final String destIp) {
- this.dm = dm;
- this.dconn = dconn;
- this.dxml = dxml;
- this.vmName = vmName;
- this.destIp = destIp;
- }
-
- @Override
- public Domain call() throws LibvirtException {
- // set compression flag for migration if libvirt version supports it
- if (dconn.getLibVirVersion() < 1003000) {
- return dm.migrate(dconn, 1 << 0, dxml, vmName, "tcp:" + destIp, _migrateSpeed);
- } else {
- return dm.migrate(dconn, 1 << 0|1 << 11, dxml, vmName, "tcp:" + destIp, _migrateSpeed);
- }
- }
- }
-
public String networkUsage(final String privateIpAddress, final String option, final String vif) {
final Script getUsage = new Script(_routerProxyPath, s_logger);
getUsage.add("netusage.sh");
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/28e55462/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/MigrateKVMAsync.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/MigrateKVMAsync.java b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/MigrateKVMAsync.java
new file mode 100644
index 0000000..fdec032
--- /dev/null
+++ b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/MigrateKVMAsync.java
@@ -0,0 +1,38 @@
+package com.cloud.hypervisor.kvm.resource;
+
+import java.util.concurrent.Callable;
+
+import org.libvirt.Connect;
+import org.libvirt.Domain;
+import org.libvirt.LibvirtException;
+
+public class MigrateKVMAsync implements Callable<Domain> {
+
+ private final LibvirtComputingResource libvirtComputingResource;
+
+ private Domain dm = null;
+ private Connect dconn = null;
+ private String dxml = "";
+ private String vmName = "";
+ private String destIp = "";
+
+ public MigrateKVMAsync(final LibvirtComputingResource libvirtComputingResource, final Domain dm, final Connect dconn, final String dxml, final String vmName, final String destIp) {
+ this.libvirtComputingResource = libvirtComputingResource;
+
+ this.dm = dm;
+ this.dconn = dconn;
+ this.dxml = dxml;
+ this.vmName = vmName;
+ this.destIp = destIp;
+ }
+
+ @Override
+ public Domain call() throws LibvirtException {
+ // set compression flag for migration if libvirt version supports it
+ if (dconn.getLibVirVersion() < 1003000) {
+ return dm.migrate(dconn, 1 << 0, dxml, vmName, "tcp:" + destIp, libvirtComputingResource.getMigrateSpeed());
+ } else {
+ return dm.migrate(dconn, 1 << 0|1 << 11, dxml, vmName, "tcp:" + destIp, libvirtComputingResource.getMigrateSpeed());
+ }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/28e55462/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtMigrateCommandWrapper.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtMigrateCommandWrapper.java b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtMigrateCommandWrapper.java
new file mode 100644
index 0000000..d3637e6
--- /dev/null
+++ b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtMigrateCommandWrapper.java
@@ -0,0 +1,183 @@
+//
+// 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.kvm.resource.wrapper;
+
+import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+import org.apache.log4j.Logger;
+import org.libvirt.Connect;
+import org.libvirt.Domain;
+import org.libvirt.DomainInfo.DomainState;
+import org.libvirt.LibvirtException;
+
+import com.cloud.agent.api.Answer;
+import com.cloud.agent.api.MigrateAnswer;
+import com.cloud.agent.api.MigrateCommand;
+import com.cloud.hypervisor.kvm.resource.LibvirtComputingResource;
+import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.DiskDef;
+import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.InterfaceDef;
+import com.cloud.hypervisor.kvm.resource.MigrateKVMAsync;
+import com.cloud.hypervisor.kvm.resource.VifDriver;
+import com.cloud.resource.CommandWrapper;
+
+public final class LibvirtMigrateCommandWrapper extends CommandWrapper<MigrateCommand, Answer, LibvirtComputingResource> {
+
+ private static final Logger s_logger = Logger.getLogger(LibvirtMigrateCommandWrapper.class);
+
+ @Override
+ public Answer execute(final MigrateCommand command, final LibvirtComputingResource libvirtComputingResource) {
+ final String vmName = command.getVmName();
+
+ String result = null;
+
+ List<InterfaceDef> ifaces = null;
+ List<DiskDef> disks = null;
+
+ Domain dm = null;
+ Connect dconn = null;
+ Domain destDomain = null;
+ Connect conn = null;
+ String xmlDesc = null;
+ try {
+ final LibvirtConnectionWrapper libvirtConnectionWrapper = libvirtComputingResource.getLibvirtConnectionWrapper();
+
+ conn = libvirtConnectionWrapper.getConnectionByVmName(vmName);
+ ifaces = libvirtComputingResource.getInterfaces(conn, vmName);
+ disks = libvirtComputingResource.getDisks(conn, vmName);
+ dm = conn.domainLookupByName(vmName);
+ /*
+ We replace the private IP address with the address of the destination host.
+ This is because the VNC listens on the private IP address of the hypervisor,
+ but that address is ofcourse different on the target host.
+
+ MigrateCommand.getDestinationIp() returns the private IP address of the target
+ hypervisor. So it's safe to use.
+
+ The Domain.migrate method from libvirt supports passing a different XML
+ description for the instance to be used on the target host.
+
+ This is supported by libvirt-java from version 0.50.0
+ */
+ xmlDesc = dm.getXMLDesc(0).replace(libvirtComputingResource.getPrivateIp(), command.getDestinationIp());
+
+ dconn = new Connect("qemu+tcp://" + command.getDestinationIp() + "/system");
+
+ //run migration in thread so we can monitor it
+ s_logger.info("Live migration of instance " + vmName + " initiated");
+ final ExecutorService executor = Executors.newFixedThreadPool(1);
+ final Callable<Domain> worker = new MigrateKVMAsync(libvirtComputingResource, dm, dconn, xmlDesc, vmName, command.getDestinationIp());
+ final Future<Domain> migrateThread = executor.submit(worker);
+ executor.shutdown();
+ long sleeptime = 0;
+ while (!executor.isTerminated()) {
+ Thread.sleep(100);
+ sleeptime += 100;
+ if (sleeptime == 1000) { // wait 1s before attempting to set downtime on migration, since I don't know of a VIR_DOMAIN_MIGRATING state
+ final int migrateDowntime = libvirtComputingResource.getMigrateDowntime();
+ if (migrateDowntime > 0 ) {
+ try {
+ final int setDowntime = dm.migrateSetMaxDowntime(migrateDowntime);
+ if (setDowntime == 0 ) {
+ s_logger.debug("Set max downtime for migration of " + vmName + " to " + String.valueOf(migrateDowntime) + "ms");
+ }
+ } catch (final LibvirtException e) {
+ s_logger.debug("Failed to set max downtime for migration, perhaps migration completed? Error: " + e.getMessage());
+ }
+ }
+ }
+ if (sleeptime % 1000 == 0) {
+ s_logger.info("Waiting for migration of " + vmName + " to complete, waited " + sleeptime + "ms");
+ }
+
+ // pause vm if we meet the vm.migrate.pauseafter threshold and not already paused
+ final int migratePauseAfter = libvirtComputingResource.getMigratePauseAfter();
+ if (migratePauseAfter > 0 && sleeptime > migratePauseAfter && dm.getInfo().state == DomainState.VIR_DOMAIN_RUNNING ) {
+ s_logger.info("Pausing VM " + vmName + " due to property vm.migrate.pauseafter setting to " + migratePauseAfter+ "ms to complete migration");
+ try {
+ dm.suspend();
+ } catch (final LibvirtException e) {
+ // pause could be racy if it attempts to pause right when vm is finished, simply warn
+ s_logger.info("Failed to pause vm " + vmName + " : " + e.getMessage());
+ }
+ }
+ }
+ s_logger.info("Migration thread for " + vmName + " is done");
+
+ destDomain = migrateThread.get(10, TimeUnit.SECONDS);
+
+ if (destDomain != null) {
+ for (final DiskDef disk : disks) {
+ libvirtComputingResource.cleanupDisk(disk);
+ }
+ }
+ } catch (final LibvirtException e) {
+ s_logger.debug("Can't migrate domain: " + e.getMessage());
+ result = e.getMessage();
+ } catch (final InterruptedException e) {
+ s_logger.debug("Interrupted while migrating domain: " + e.getMessage());
+ result = e.getMessage();
+ } catch (final ExecutionException e) {
+ s_logger.debug("Failed to execute while migrating domain: " + e.getMessage());
+ result = e.getMessage();
+ } catch (final TimeoutException e) {
+ s_logger.debug("Timed out while migrating domain: " + e.getMessage());
+ result = e.getMessage();
+ } finally {
+ try {
+ if (dm != null) {
+ if (dm.isPersistent() == 1) {
+ dm.undefine();
+ }
+ dm.free();
+ }
+ if (dconn != null) {
+ dconn.close();
+ }
+ if (destDomain != null) {
+ destDomain.free();
+ }
+ } catch (final LibvirtException e) {
+ s_logger.trace("Ignoring libvirt error.", e);
+ }
+ }
+
+ if (result != null) {
+ } else {
+ libvirtComputingResource.destroyNetworkRulesForVM(conn, vmName);
+ for (final InterfaceDef iface : ifaces) {
+ // We don't know which "traffic type" is associated with
+ // each interface at this point, so inform all vif drivers
+ final List<VifDriver> allVifDrivers = libvirtComputingResource.getAllVifDrivers();
+ for (final VifDriver vifDriver : allVifDrivers) {
+ vifDriver.unplug(iface);
+ }
+ }
+ }
+
+ return new MigrateAnswer(command, result == null, result, null);
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/28e55462/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtRequestWrapper.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtRequestWrapper.java b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtRequestWrapper.java
index d8ca27f..ee444b8 100644
--- a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtRequestWrapper.java
+++ b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtRequestWrapper.java
@@ -26,6 +26,7 @@ import com.cloud.agent.api.Command;
import com.cloud.agent.api.GetHostStatsCommand;
import com.cloud.agent.api.GetVmDiskStatsCommand;
import com.cloud.agent.api.GetVmStatsCommand;
+import com.cloud.agent.api.MigrateCommand;
import com.cloud.agent.api.PrepareForMigrationCommand;
import com.cloud.agent.api.RebootCommand;
import com.cloud.agent.api.RebootRouterCommand;
@@ -60,6 +61,7 @@ public class LibvirtRequestWrapper extends RequestWrapper {
linbvirtCommands.put(GetHostStatsCommand.class, new LibvirtGetHostStatsCommandWrapper());
linbvirtCommands.put(CheckHealthCommand.class, new LibvirtCheckHealthCommandWrapper());
linbvirtCommands.put(PrepareForMigrationCommand.class, new LibvirtPrepareForMigrationCommandWrapper());
+ linbvirtCommands.put(MigrateCommand.class, new LibvirtMigrateCommandWrapper());
resources.put(LibvirtComputingResource.class, linbvirtCommands);
}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/28e55462/plugins/hypervisors/kvm/test/com/cloud/hypervisor/kvm/resource/LibvirtComputingResourceTest.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/kvm/test/com/cloud/hypervisor/kvm/resource/LibvirtComputingResourceTest.java b/plugins/hypervisors/kvm/test/com/cloud/hypervisor/kvm/resource/LibvirtComputingResourceTest.java
index 9b4b421..4aa249e 100644
--- a/plugins/hypervisors/kvm/test/com/cloud/hypervisor/kvm/resource/LibvirtComputingResourceTest.java
+++ b/plugins/hypervisors/kvm/test/com/cloud/hypervisor/kvm/resource/LibvirtComputingResourceTest.java
@@ -23,6 +23,7 @@ import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -66,6 +67,7 @@ import com.cloud.agent.api.CheckHealthCommand;
import com.cloud.agent.api.GetHostStatsCommand;
import com.cloud.agent.api.GetVmDiskStatsCommand;
import com.cloud.agent.api.GetVmStatsCommand;
+import com.cloud.agent.api.MigrateCommand;
import com.cloud.agent.api.PrepareForMigrationCommand;
import com.cloud.agent.api.RebootCommand;
import com.cloud.agent.api.RebootRouterCommand;
@@ -668,4 +670,77 @@ public class LibvirtComputingResourceTest {
verify(vm, times(1)).getDisks();
verify(diskTO, times(1)).getType();
}
+
+ @Test(expected = UnsatisfiedLinkError.class)
+ public void testMigrateCommand() {
+ // The Connect constructor used inside the LibvirtMigrateCommandWrapper has a call to native methods, which
+ // makes difficult to test it now.
+ // Will keep it expecting the UnsatisfiedLinkError and fix later.
+
+ final Connect conn = Mockito.mock(Connect.class);
+ final LibvirtConnectionWrapper libvirtConnectionWrapper = Mockito.mock(LibvirtConnectionWrapper.class);
+
+ final String vmName = "Test";
+ final String destIp = "10.1.1.100";
+ final boolean isWindows = false;
+ final VirtualMachineTO vmTO = Mockito.mock(VirtualMachineTO.class);
+ final boolean executeInSequence = false;
+
+ final MigrateCommand command = new MigrateCommand(vmName, destIp, isWindows, vmTO, executeInSequence );
+
+ when(libvirtComputingResource.getLibvirtConnectionWrapper()).thenReturn(libvirtConnectionWrapper);
+ try {
+ when(libvirtConnectionWrapper.getConnectionByVmName(vmName)).thenReturn(conn);
+ } catch (final LibvirtException e) {
+ fail(e.getMessage());
+ }
+
+ final InterfaceDef interfaceDef = Mockito.mock(InterfaceDef.class);
+ final List<InterfaceDef> ifaces = new ArrayList<InterfaceDef>();
+ ifaces.add(interfaceDef);
+
+ when(libvirtComputingResource.getInterfaces(conn, vmName)).thenReturn(ifaces);
+
+ final DiskDef diskDef = Mockito.mock(DiskDef.class);
+ final List<DiskDef> disks = new ArrayList<DiskDef>();
+ disks.add(diskDef);
+
+ when(libvirtComputingResource.getDisks(conn, vmName)).thenReturn(disks);
+ final Domain dm = Mockito.mock(Domain.class);
+ try {
+ when(conn.domainLookupByName(vmName)).thenReturn(dm);
+
+ when(libvirtComputingResource.getPrivateIp()).thenReturn("192.168.1.10");
+ when(dm.getXMLDesc(0)).thenReturn("host_domain");
+ when(dm.isPersistent()).thenReturn(1);
+ doNothing().when(dm).undefine();
+
+ } catch (final LibvirtException e) {
+ fail(e.getMessage());
+ } catch (final Exception e) {
+ fail(e.getMessage());
+ }
+
+ final LibvirtRequestWrapper wrapper = LibvirtRequestWrapper.getInstance();
+ assertNotNull(wrapper);
+
+ final Answer answer = wrapper.execute(command, libvirtComputingResource);
+ assertFalse(answer.getResult());
+
+ verify(libvirtComputingResource, times(1)).getLibvirtConnectionWrapper();
+ try {
+ verify(libvirtConnectionWrapper, times(1)).getConnectionByVmName(vmName);
+ } catch (final LibvirtException e) {
+ fail(e.getMessage());
+ }
+
+ verify(libvirtComputingResource, times(1)).getInterfaces(conn, vmName);
+ verify(libvirtComputingResource, times(1)).getDisks(conn, vmName);
+ try {
+ verify(conn, times(1)).domainLookupByName(vmName);
+ verify(dm, times(1)).getXMLDesc(0);
+ } catch (final LibvirtException e) {
+ fail(e.getMessage());
+ }
+ }
}
\ No newline at end of file