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/04/05 13:25:09 UTC

[2/8] git commit: updated refs/heads/master to 096d1b9

Refactoring the MigrateWithStorageCommand wrapper in order to cope with new design
   - Unit tests added: 30.1% coverage
   - It's a bit difficult to test the Xen API classes due to their static nature


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

Branch: refs/heads/master
Commit: 858b87f01c079f48ed557864be4842d6becaa55c
Parents: 240bcb8
Author: wilderrodrigues <wr...@schubergphilis.com>
Authored: Fri Apr 3 14:39:35 2015 +0200
Committer: wilderrodrigues <wr...@schubergphilis.com>
Committed: Sun Apr 5 09:23:09 2015 +0200

----------------------------------------------------------------------
 .../xenserver/resource/CitrixResourceBase.java  |   4 +
 .../resource/XenServer610Resource.java          |   6 +-
 .../resource/wrapper/CitrixRequestWrapper.java  |  10 +-
 ...rver610MigrateWithStorageCommandWrapper.java | 135 +++++++++++++++++++
 .../wrapper/XenServer610WrapperTest.java        |  84 ++++++++++++
 5 files changed, 234 insertions(+), 5 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/858b87f0/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/CitrixResourceBase.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/CitrixResourceBase.java b/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/CitrixResourceBase.java
index 7729636..bf0ea6c 100644
--- a/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/CitrixResourceBase.java
+++ b/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/CitrixResourceBase.java
@@ -2004,6 +2004,10 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
         return _host;
     }
 
+    public int getMigrateWait() {
+        return _migratewait;
+    }
+
     protected boolean getHostInfo(final Connection conn) throws IllegalArgumentException {
         try {
             final Host myself = Host.getByUuid(conn, _host.getUuid());

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/858b87f0/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/XenServer610Resource.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/XenServer610Resource.java b/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/XenServer610Resource.java
index b372ef7..7f5dfdb 100644
--- a/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/XenServer610Resource.java
+++ b/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/XenServer610Resource.java
@@ -68,9 +68,7 @@ public class XenServer610Resource extends XenServer600Resource {
 
     @Override
     public Answer executeRequest(final Command cmd) {
-        if (cmd instanceof MigrateWithStorageCommand) {
-            return execute((MigrateWithStorageCommand)cmd);
-        } else if (cmd instanceof MigrateWithStorageReceiveCommand) {
+        if (cmd instanceof MigrateWithStorageReceiveCommand) {
             return execute((MigrateWithStorageReceiveCommand)cmd);
         } else if (cmd instanceof MigrateWithStorageSendCommand) {
             return execute((MigrateWithStorageSendCommand)cmd);
@@ -83,7 +81,7 @@ public class XenServer610Resource extends XenServer600Resource {
         }
     }
 
-    private List<VolumeObjectTO> getUpdatedVolumePathsOfMigratedVm(final Connection connection, final VM migratedVm, final DiskTO[] volumes) throws CloudRuntimeException {
+    public List<VolumeObjectTO> getUpdatedVolumePathsOfMigratedVm(final Connection connection, final VM migratedVm, final DiskTO[] volumes) throws CloudRuntimeException {
         final List<VolumeObjectTO> volumeToList = new ArrayList<VolumeObjectTO>();
 
         try {

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/858b87f0/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/wrapper/CitrixRequestWrapper.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/wrapper/CitrixRequestWrapper.java b/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/wrapper/CitrixRequestWrapper.java
index e7e238f..59d1a5f 100644
--- a/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/wrapper/CitrixRequestWrapper.java
+++ b/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/wrapper/CitrixRequestWrapper.java
@@ -44,6 +44,7 @@ import com.cloud.agent.api.GetVmStatsCommand;
 import com.cloud.agent.api.GetVncPortCommand;
 import com.cloud.agent.api.MaintainCommand;
 import com.cloud.agent.api.MigrateCommand;
+import com.cloud.agent.api.MigrateWithStorageCommand;
 import com.cloud.agent.api.ModifySshKeysCommand;
 import com.cloud.agent.api.ModifyStoragePoolCommand;
 import com.cloud.agent.api.NetworkRulesSystemVmCommand;
@@ -87,6 +88,8 @@ import com.cloud.agent.api.storage.ResizeVolumeCommand;
 import com.cloud.hypervisor.xenserver.resource.CitrixResourceBase;
 import com.cloud.hypervisor.xenserver.resource.XenServer56FP1Resource;
 import com.cloud.hypervisor.xenserver.resource.XenServer56Resource;
+import com.cloud.hypervisor.xenserver.resource.XenServer610Resource;
+import com.cloud.hypervisor.xenserver.resource.XenServer620SP1Resource;
 import com.cloud.resource.CommandWrapper;
 import com.cloud.resource.RequestWrapper;
 import com.cloud.resource.ServerResource;
@@ -187,7 +190,12 @@ public class CitrixRequestWrapper extends RequestWrapper {
         // XenServer620SP1Resource commands
         final Hashtable<Class<? extends Command>, CommandWrapper> xenServer620SP1Commands = new Hashtable<Class<? extends Command>, CommandWrapper>();
         xenServer620SP1Commands.put(GetGPUStatsCommand.class, new XenServer620SP1GetGPUStatsCommandWrapper());
-        resources.put(XenServer56FP1Resource.class, xenServer620SP1Commands);
+        resources.put(XenServer620SP1Resource.class, xenServer620SP1Commands);
+
+        // XenServer610Resource commands
+        final Hashtable<Class<? extends Command>, CommandWrapper> xenServer610Commands = new Hashtable<Class<? extends Command>, CommandWrapper>();
+        xenServer610Commands.put(MigrateWithStorageCommand.class, new XenServer610MigrateWithStorageCommandWrapper());
+        resources.put(XenServer610Resource.class, xenServer610Commands);
     }
 
     public static CitrixRequestWrapper getInstance() {

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/858b87f0/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/wrapper/XenServer610MigrateWithStorageCommandWrapper.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/wrapper/XenServer610MigrateWithStorageCommandWrapper.java b/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/wrapper/XenServer610MigrateWithStorageCommandWrapper.java
new file mode 100644
index 0000000..0d1cac4
--- /dev/null
+++ b/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/wrapper/XenServer610MigrateWithStorageCommandWrapper.java
@@ -0,0 +1,135 @@
+//
+// 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.xenserver.resource.wrapper;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.cloudstack.storage.to.VolumeObjectTO;
+import org.apache.log4j.Logger;
+
+import com.cloud.agent.api.Answer;
+import com.cloud.agent.api.MigrateWithStorageAnswer;
+import com.cloud.agent.api.MigrateWithStorageCommand;
+import com.cloud.agent.api.to.NicTO;
+import com.cloud.agent.api.to.StorageFilerTO;
+import com.cloud.agent.api.to.VirtualMachineTO;
+import com.cloud.agent.api.to.VolumeTO;
+import com.cloud.hypervisor.xenserver.resource.XenServer610Resource;
+import com.cloud.hypervisor.xenserver.resource.XsHost;
+import com.cloud.hypervisor.xenserver.resource.XsLocalNetwork;
+import com.cloud.network.Networks.TrafficType;
+import com.cloud.resource.CommandWrapper;
+import com.cloud.utils.exception.CloudRuntimeException;
+import com.xensource.xenapi.Connection;
+import com.xensource.xenapi.Host;
+import com.xensource.xenapi.Network;
+import com.xensource.xenapi.SR;
+import com.xensource.xenapi.Task;
+import com.xensource.xenapi.Types;
+import com.xensource.xenapi.VDI;
+import com.xensource.xenapi.VIF;
+import com.xensource.xenapi.VM;
+
+public final class XenServer610MigrateWithStorageCommandWrapper extends CommandWrapper<MigrateWithStorageCommand, Answer, XenServer610Resource> {
+
+    private static final Logger s_logger = Logger.getLogger(XenServer610MigrateWithStorageCommandWrapper.class);
+
+    @Override
+    public Answer execute(final MigrateWithStorageCommand command, final XenServer610Resource xenServer610Resource) {
+        final Connection connection = xenServer610Resource.getConnection();
+        final VirtualMachineTO vmSpec = command.getVirtualMachine();
+        final Map<VolumeTO, StorageFilerTO> volumeToFiler = command.getVolumeToFiler();
+        final String vmName = vmSpec.getName();
+        Task task = null;
+
+        final XsHost xsHost = xenServer610Resource.getHost();
+        final String uuid = xsHost.getUuid();
+        try {
+            xenServer610Resource.prepareISO(connection, vmName);
+
+            // Get the list of networks and recreate VLAN, if required.
+            for (final NicTO nicTo : vmSpec.getNics()) {
+                xenServer610Resource.getNetwork(connection, nicTo);
+            }
+
+            final Map<String, String> other = new HashMap<String, String>();
+            other.put("live", "true");
+
+            final XsLocalNetwork nativeNetworkForTraffic = xenServer610Resource.getNativeNetworkForTraffic(connection, TrafficType.Storage, null);
+            final Network networkForSm = nativeNetworkForTraffic.getNetwork();
+
+            // Create the vif map. The vm stays in the same cluster so we have to pass an empty vif map.
+            final Map<VIF, Network> vifMap = new HashMap<VIF, Network>();
+            final Map<VDI, SR> vdiMap = new HashMap<VDI, SR>();
+            for (final Map.Entry<VolumeTO, StorageFilerTO> entry : volumeToFiler.entrySet()) {
+                vdiMap.put(xenServer610Resource.getVDIbyUuid(connection, entry.getKey().getPath()), xenServer610Resource.getStorageRepository(connection, entry.getValue().getUuid()));
+            }
+
+            // Get the vm to migrate.
+            final Set<VM> vms = VM.getByNameLabel(connection, vmSpec.getName());
+            final VM vmToMigrate = vms.iterator().next();
+
+            // Check migration with storage is possible.
+            final Host host = Host.getByUuid(connection, uuid);
+            final Map<String, String> token = host.migrateReceive(connection, networkForSm, other);
+            task = vmToMigrate.assertCanMigrateAsync(connection, token, true, vdiMap, vifMap, other);
+            try {
+                // poll every 1 seconds
+                final long timeout = xenServer610Resource.getMigrateWait() * 1000L;
+                xenServer610Resource.waitForTask(connection, task, 1000, timeout);
+                xenServer610Resource.checkForSuccess(connection, task);
+            } catch (final Types.HandleInvalid e) {
+                s_logger.error("Error while checking if vm " + vmName + " can be migrated to the destination host " + host, e);
+                throw new CloudRuntimeException("Error while checking if vm " + vmName + " can be migrated to the " + "destination host " + host, e);
+            }
+
+            // Migrate now.
+            task = vmToMigrate.migrateSendAsync(connection, token, true, vdiMap, vifMap, other);
+            try {
+                // poll every 1 seconds.
+                final long timeout = xenServer610Resource.getMigrateWait() * 1000L;
+                xenServer610Resource.waitForTask(connection, task, 1000, timeout);
+                xenServer610Resource.checkForSuccess(connection, task);
+            } catch (final Types.HandleInvalid e) {
+                s_logger.error("Error while migrating vm " + vmName + " to the destination host " + host, e);
+                throw new CloudRuntimeException("Error while migrating vm " + vmName + " to the destination host " + host, e);
+            }
+
+            // Volume paths would have changed. Return that information.
+            final List<VolumeObjectTO> volumeToList = xenServer610Resource.getUpdatedVolumePathsOfMigratedVm(connection, vmToMigrate, vmSpec.getDisks());
+            vmToMigrate.setAffinity(connection, host);
+            return new MigrateWithStorageAnswer(command, volumeToList);
+        } catch (final Exception e) {
+            s_logger.warn("Catch Exception " + e.getClass().getName() + ". Storage motion failed due to " + e.toString(), e);
+            return new MigrateWithStorageAnswer(command, e);
+        } finally {
+            if (task != null) {
+                try {
+                    task.destroy(connection);
+                } catch (final Exception e) {
+                    s_logger.debug("Unable to destroy task " + task.toString() + " on host " + uuid + " due to " + e.toString());
+                }
+            }
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/858b87f0/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/wrapper/XenServer610WrapperTest.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/wrapper/XenServer610WrapperTest.java b/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/wrapper/XenServer610WrapperTest.java
index e8a64de..a708684 100644
--- a/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/wrapper/XenServer610WrapperTest.java
+++ b/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/wrapper/XenServer610WrapperTest.java
@@ -17,25 +17,47 @@
 package com.cloud.hypervisor.xenserver.resource.wrapper;
 
 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.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
 
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
+import org.apache.xmlrpc.XmlRpcException;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
 import org.mockito.Mockito;
+import org.powermock.core.classloader.annotations.PrepareForTest;
 import org.powermock.modules.junit4.PowerMockRunner;
 
 import com.cloud.agent.api.Answer;
 import com.cloud.agent.api.CheckNetworkCommand;
+import com.cloud.agent.api.MigrateWithStorageCommand;
 import com.cloud.agent.api.SetupCommand;
+import com.cloud.agent.api.to.NicTO;
+import com.cloud.agent.api.to.StorageFilerTO;
+import com.cloud.agent.api.to.VirtualMachineTO;
+import com.cloud.agent.api.to.VolumeTO;
 import com.cloud.host.HostEnvironment;
 import com.cloud.hypervisor.xenserver.resource.XenServer610Resource;
+import com.cloud.hypervisor.xenserver.resource.XsHost;
+import com.cloud.hypervisor.xenserver.resource.XsLocalNetwork;
+import com.cloud.network.Networks.TrafficType;
 import com.cloud.network.PhysicalNetworkSetupInfo;
+import com.xensource.xenapi.Connection;
+import com.xensource.xenapi.Host;
+import com.xensource.xenapi.Network;
+import com.xensource.xenapi.Types.XenAPIException;
 
 @RunWith(PowerMockRunner.class)
+@PrepareForTest({Host.class})
 public class XenServer610WrapperTest {
 
     @Mock
@@ -69,4 +91,66 @@ public class XenServer610WrapperTest {
 
         assertFalse(answer.getResult());
     }
+
+    @Test
+    public void testMigrateWithStorageCommand() {
+        final String vmName = "small";
+        final String uuid = "206b21a7-c6ec-40e2-b5e2-f861b9612f04";
+
+        final Connection conn = Mockito.mock(Connection.class);
+        final VirtualMachineTO vmSpec = Mockito.mock(VirtualMachineTO.class);
+        final Map<VolumeTO, StorageFilerTO> volumeToFiler = new  HashMap<VolumeTO, StorageFilerTO>();
+
+        final NicTO nicTO1 = Mockito.mock(NicTO.class);
+        final NicTO nicTO2 = Mockito.mock(NicTO.class);
+        final NicTO nicTO3 = Mockito.mock(NicTO.class);
+        final NicTO [] nicTOs = {nicTO1, nicTO2, nicTO3};
+
+        final XsLocalNetwork nativeNetworkForTraffic = Mockito.mock(XsLocalNetwork.class);
+        final Network networkForSm = Mockito.mock(Network.class);
+
+        final XsHost xsHost = Mockito.mock(XsHost.class);
+        final Host host = Mockito.mock(Host.class);
+
+        final MigrateWithStorageCommand gpuStats = new MigrateWithStorageCommand(vmSpec, volumeToFiler);
+
+        final CitrixRequestWrapper wrapper = CitrixRequestWrapper.getInstance();
+        assertNotNull(wrapper);
+
+        when(xenServer610Resource.getConnection()).thenReturn(conn);
+        when(vmSpec.getName()).thenReturn(vmName);
+        when(vmSpec.getNics()).thenReturn(nicTOs);
+
+        try {
+            when(xenServer610Resource.getHost()).thenReturn(xsHost);
+            when(xsHost.getUuid()).thenReturn(uuid);
+
+            when(xenServer610Resource.getNativeNetworkForTraffic(conn, TrafficType.Storage, null)).thenReturn(nativeNetworkForTraffic);
+            when(nativeNetworkForTraffic.getNetwork()).thenReturn(networkForSm);
+        } catch (final XenAPIException e) {
+            fail(e.getMessage());
+        } catch (final XmlRpcException e) {
+            fail(e.getMessage());
+        }
+
+        final Answer answer = wrapper.execute(gpuStats, xenServer610Resource);
+
+        verify(xenServer610Resource, times(1)).getConnection();
+
+        try {
+            verify(xenServer610Resource, times(1)).prepareISO(conn, vmName);
+            verify(xenServer610Resource, times(1)).getNetwork(conn, nicTO1);
+            verify(xenServer610Resource, times(1)).getNetwork(conn, nicTO2);
+            verify(xenServer610Resource, times(1)).getNetwork(conn, nicTO3);
+
+            verify(xenServer610Resource, times(1)).getNativeNetworkForTraffic(conn, TrafficType.Storage, null);
+            verify(nativeNetworkForTraffic, times(1)).getNetwork();
+        } catch (final XenAPIException e) {
+            fail(e.getMessage());
+        } catch (final XmlRpcException e) {
+            fail(e.getMessage());
+        }
+
+        assertFalse(answer.getResult());
+    }
 }
\ No newline at end of file