Updated Branches:
  refs/heads/master f25354dca -> a196fbc83

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/f9f196a4/plugins/hypervisors/hyperv/test/com/cloud/hypervisor/hyperv/test/HypervDirectConnectResourceTest.java
----------------------------------------------------------------------
diff --git 
a/plugins/hypervisors/hyperv/test/com/cloud/hypervisor/hyperv/test/HypervDirectConnectResourceTest.java
 
b/plugins/hypervisors/hyperv/test/com/cloud/hypervisor/hyperv/test/HypervDirectConnectResourceTest.java
new file mode 100644
index 0000000..fddd23a
--- /dev/null
+++ 
b/plugins/hypervisors/hyperv/test/com/cloud/hypervisor/hyperv/test/HypervDirectConnectResourceTest.java
@@ -0,0 +1,938 @@
+// 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.hyperv.test;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.FilenameFilter;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.net.URL;
+import java.nio.channels.Channels;
+import java.nio.channels.ReadableByteChannel;
+import java.nio.file.Files;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+import javax.naming.ConfigurationException;
+
+import org.apache.log4j.Logger;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.google.gson.Gson;
+
+import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
+
+import com.cloud.agent.api.Answer;
+import com.cloud.agent.api.Command;
+import com.cloud.agent.api.CreateStoragePoolCommand;
+import com.cloud.agent.api.DeleteStoragePoolCommand;
+import com.cloud.agent.api.GetHostStatsAnswer;
+import com.cloud.agent.api.GetHostStatsCommand;
+import com.cloud.agent.api.GetStorageStatsAnswer;
+import com.cloud.agent.api.GetStorageStatsCommand;
+import com.cloud.agent.api.GetVmStatsAnswer;
+import com.cloud.agent.api.GetVmStatsCommand;
+import com.cloud.agent.api.ModifyStoragePoolCommand;
+import com.cloud.agent.api.StartAnswer;
+import com.cloud.agent.api.StartCommand;
+import com.cloud.agent.api.StartupCommand;
+import com.cloud.agent.api.StartupRoutingCommand;
+import com.cloud.agent.api.StartupRoutingCommand.VmState;
+import com.cloud.agent.api.StartupStorageCommand;
+import com.cloud.agent.api.StopAnswer;
+import com.cloud.agent.api.StopCommand;
+import com.cloud.agent.api.storage.CreateAnswer;
+import com.cloud.agent.api.storage.CreateCommand;
+import com.cloud.agent.api.storage.DestroyCommand;
+import com.cloud.agent.api.storage.PrimaryStorageDownloadAnswer;
+import com.cloud.agent.api.storage.PrimaryStorageDownloadCommand;
+import com.cloud.hypervisor.Hypervisor;
+import com.cloud.hypervisor.hyperv.resource.HypervDirectConnectResource;
+import com.cloud.network.Networks.RouterPrivateIpStrategy;
+import com.cloud.serializer.GsonHelper;
+import com.cloud.storage.Storage;
+import com.cloud.storage.Storage.StoragePoolType;
+import com.cloud.utils.PropertiesUtil;
+import com.cloud.utils.exception.CloudRuntimeException;
+
+/**
+ * Functional test suit for Hyper-V plugin.
+ *
+ * mvn clean build -DskipTests=false
+ **/
+public class HypervDirectConnectResourceTest {
+
+    private static final Logger s_logger = Logger
+            .getLogger(HypervDirectConnectResourceTest.class.getName());
+
+    // TODO: make this a config parameter
+    private static final String sampleLegitDiskImageURL = 
"http://s3-eu-west-1.amazonaws.com/cshv3eu/SmallDisk.vhdx";;
+    private static final Gson s_gson = GsonHelper.getGson();
+    private static final HypervDirectConnectResource s_hypervresource =
+            new HypervDirectConnectResource();
+
+    private static String s_testLocalStoreUUID =
+            "5fe2bad3-d785-394e-9949-89786b8a63d2";
+    private static String s_testLocalStorePath = "." + File.separator
+            + "var" + File.separator + "test" + File.separator + "storagepool";
+    private static String s_testSecondaryStoreLocalPath = "."
+            + File.separator
+            + "var" + File.separator + "test" + File.separator + "secondary";
+
+    // TODO: differentiate between NFS and HTTP template URLs.
+    private static String s_testSampleTemplateUUID =
+            "TestCopiedLocalTemplate.vhdx";
+    private static String s_testSampleTemplateURL = s_testSampleTemplateUUID;
+
+    // test volumes are both a minimal size vhdx. Changing the extension to 
.vhd
+    // makes on corrupt.
+    private static String s_testSampleVolumeWorkingUUID =
+            "TestVolumeLegit.vhdx";
+    private static String s_testSampleVolumeWorkingUUIDNoExt =
+            "TestVolumeLegit";
+    private static String s_testSampleVolumeCorruptUUID =
+            "TestVolumeCorrupt.vhd";
+    private static String s_testSampleVolumeTempUUID =
+            "TestVolumeTemp.vhdx";
+    private static String s_testSampleVolumeWorkingURIJSON;
+    private static String s_testSampleVolumeCorruptURIJSON;
+    private static String s_testSampleVolumeTempURIJSON;
+
+    private static String s_testSampleTemplateURLJSON;
+    private static String s_testLocalStorePathJSON;
+    private static String s_agentExecutable;
+    private static Process s_agentProc;
+    private static String s_testPrimaryDataStoreHost;
+
+    public HypervDirectConnectResourceTest() {
+    }
+
+    /**
+     * Prep test environment.
+     **/
+    @Before
+    public final void setUp() throws ConfigurationException {
+        // Obtain script locations from agent.properties
+        final Map<String, Object> params =
+                PropertiesUtil.toMap(loadProperties());
+        // Used to create existing StoragePool in preparation for the
+        // ModifyStoragePool
+        params.put("local.storage.uuid", s_testLocalStoreUUID);
+
+        // Make sure secondary store is available.
+        File testSecondarStoreDir = new File(s_testSecondaryStoreLocalPath);
+        if (!testSecondarStoreDir.exists()) {
+            testSecondarStoreDir.mkdirs();
+        }
+        Assert.assertTrue("Need to be able to create the folder "
+                + s_testSecondaryStoreLocalPath,
+                testSecondarStoreDir.exists());
+        try {
+            params.put("local.secondary.storage.path",
+                    testSecondarStoreDir.getCanonicalPath());
+        } catch (IOException e1) {
+            // TODO Auto-generated catch block
+            Assert.fail("No canonical path for "
+                    + testSecondarStoreDir.getAbsolutePath());
+        }
+
+        // Clean up old test files in local storage folder:
+        File testPoolDir = new File(s_testLocalStorePath);
+        if (!testPoolDir.exists()) {
+            testPoolDir.mkdirs();
+        }
+        Assert.assertTrue(
+                "To simulate local file system Storage Pool, "
+                        + " you need folder at "
+                        + testPoolDir.getPath(), testPoolDir.exists()
+                        && testPoolDir.isDirectory());
+        try {
+            s_testLocalStorePath = testPoolDir.getCanonicalPath();
+        } catch (IOException e) {
+            Assert.fail("No canonical path for "
+                    + testPoolDir.getAbsolutePath());
+        }
+        params.put("local.storage.path", s_testLocalStorePath);
+
+        File testVolWorks =
+                new File(s_testLocalStorePath + File.separator
+                        + s_testSampleVolumeWorkingUUID);
+        if (!testVolWorks.exists()) {
+            ReadableByteChannel rbc;
+            try {
+                URL sampleLegitDiskImageURL = new 
URL("http://s3-eu-west-1.amazonaws.com/cshv3eu/SmallDisk.vhdx";);
+                rbc = 
Channels.newChannel(sampleLegitDiskImageURL.openStream());
+                FileOutputStream fos = new FileOutputStream(testVolWorks);
+                fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
+            } catch (IOException e) {
+                // TODO Auto-generated catch block
+                e.printStackTrace();
+            }
+               }
+        Assert.assertTrue(
+                "Need to put a sample working virtual disk at "
+                        + testVolWorks.getPath(), testVolWorks.exists());
+        try {
+            s_testSampleVolumeWorkingURIJSON =
+                    s_gson.toJson(testVolWorks.getCanonicalPath());
+        } catch (IOException e) {
+            Assert.fail("No canonical path for "
+                    + testPoolDir.getAbsolutePath());
+        }
+
+        FilenameFilter vhdsFilt = new FilenameFilter() {
+            @Override
+            public boolean accept(final File directory, final String fileName) 
{
+                return fileName.endsWith(".vhdx") || fileName.endsWith(".vhd");
+            }
+        };
+        for (File file : testPoolDir.listFiles(vhdsFilt)) {
+            if (file.getName().equals(testVolWorks.getName())) {
+                continue;
+            }
+            Assert.assertTrue("Should have deleted file " + file.getPath(),
+                    file.delete());
+            s_logger.info("Cleaned up by delete file " + file.getPath());
+        }
+
+        s_testSampleVolumeTempURIJSON =
+                createTestDiskImageFromExistingImage(testVolWorks,
+                        s_testLocalStorePath, s_testSampleVolumeTempUUID);
+        s_logger.info("Created " + s_testSampleVolumeTempURIJSON);
+        s_testSampleVolumeCorruptURIJSON =
+                createTestDiskImageFromExistingImage(testVolWorks,
+                        s_testLocalStorePath, s_testSampleVolumeCorruptUUID);
+        s_logger.info("Created " + s_testSampleVolumeCorruptURIJSON);
+        createTestDiskImageFromExistingImage(testVolWorks,
+                s_testLocalStorePath,
+                s_testSampleTemplateUUID);
+        s_testSampleTemplateURLJSON = s_testSampleTemplateUUID;
+        s_logger.info("Created " + s_testSampleTemplateURLJSON
+                + " in local storage.");
+
+        // Create secondary storage template:
+        createTestDiskImageFromExistingImage(testVolWorks,
+                testSecondarStoreDir.getAbsolutePath(),
+                "af39aa7f-2b12-37e1-86d3-e23f2f005101.vhdx");
+        s_logger.info("Created " + "af39aa7f-2b12-37e1-86d3-e23f2f005101.vhdx"
+                + " in secondary (NFS) storage.");
+
+        s_testLocalStorePathJSON = s_gson.toJson(s_testLocalStorePath);
+
+        String agentIp = (String) params.get("ipaddress");
+        s_logger.info("Test using agent IP address " + agentIp);
+        params.put("agentIp", agentIp);
+        setTestJsonResult(params);
+        s_hypervresource.configure("hypervresource", params);
+        // Verify sample template is in place storage pool
+        s_logger.info("setUp complete, sample StoragePool at "
+                + s_testLocalStorePathJSON
+                + " sample template at " + s_testSampleTemplateURLJSON);
+
+        s_agentExecutable = (String) params.get("agent.executable");
+        s_testPrimaryDataStoreHost = (String) params.get("ipaddress");
+        agentCreation();
+    }
+
+    private String createTestDiskImageFromExistingImage(final File srcFile,
+            final String dstPath,
+            final String dstFileName) {
+        String newFileURIJSON = null;
+        File testVolTemp = new File(dstPath + File.separator + dstFileName);
+        try {
+            Files.copy(srcFile.toPath(), testVolTemp.toPath());
+        } catch (IOException e) {
+            ; // NOP
+        }
+        Assert.assertTrue(
+                "Should be a temporary file created from the valid volume) at "
+                        + testVolTemp.getPath(), testVolTemp.exists());
+        try {
+            newFileURIJSON = s_gson.toJson(testVolTemp.getCanonicalPath());
+        } catch (IOException e) {
+            Assert.fail("No file at " + testVolTemp.getAbsolutePath());
+        }
+        return newFileURIJSON;
+    }
+
+    @Test
+    public final void testGetVmStatsCommand() {
+        // Sample GetVmStatsCommand
+        List<String> vmNames = new ArrayList<String>();
+        vmNames.add("i-2-11-VM");
+        GetVmStatsCommand cmd =
+                new GetVmStatsCommand(vmNames, "1", "localhost");
+
+        s_hypervresource.executeRequest(cmd);
+        GetVmStatsAnswer ans =
+                (GetVmStatsAnswer) s_hypervresource.executeRequest(cmd);
+        Assert.assertTrue(ans.getDetails(), ans.getResult());
+    }
+
+    public final void testStartupCommand() {
+        StartupRoutingCommand defaultStartRoutCmd = new StartupRoutingCommand(
+                0, 0, 0, 0, null, Hypervisor.HypervisorType.Hyperv,
+                RouterPrivateIpStrategy.HostLocal,
+                new HashMap<String, VmState>());
+
+        // Identity within the data centre is decided by CloudStack kernel,
+        // and passed via ServerResource.configure()
+        defaultStartRoutCmd.setDataCenter("1");
+        defaultStartRoutCmd.setPod("1");
+        defaultStartRoutCmd.setCluster("1");
+        defaultStartRoutCmd.setGuid("1");
+        defaultStartRoutCmd.setName("1");
+        defaultStartRoutCmd.setPrivateIpAddress("1");
+        defaultStartRoutCmd.setStorageIpAddress("1");
+        defaultStartRoutCmd.setCpus(12);
+
+        // TODO: does version need to be hard coded.
+        defaultStartRoutCmd.setVersion("4.2.0");
+
+        StartupCommand scmd = defaultStartRoutCmd;
+
+        Command[] cmds = {scmd};
+        String cmdsStr = s_gson.toJson(cmds);
+        s_logger.debug("Commands[] toJson is " + cmdsStr);
+
+        Command[] result = s_gson.fromJson(cmdsStr, Command[].class);
+        s_logger.debug("Commands[] fromJson is " + s_gson.toJson(result));
+        s_logger.debug("Commands[] first element has type"
+                + result[0].toString());
+    }
+
+    // @Test
+    public final void testJson() {
+        StartupStorageCommand sscmd = null;
+        com.cloud.agent.api.StoragePoolInfo pi =
+                new com.cloud.agent.api.StoragePoolInfo(
+                        "test123", "192.168.0.1", "c:\\", "c:\\",
+                        StoragePoolType.Filesystem, 100L, 50L);
+
+        sscmd = new StartupStorageCommand();
+        sscmd.setPoolInfo(pi);
+        sscmd.setGuid(pi.getUuid());
+        sscmd.setDataCenter("foo");
+        sscmd.setResourceType(Storage.StorageResourceType.STORAGE_POOL);
+        s_logger.debug("StartupStorageCommand fromJson is "
+                + s_gson.toJson(sscmd));
+    }
+
+    @Test
+    public final void testBadGetVmStatsCommand() {
+        // Sample GetVmStatsCommand
+        List<String> vmNames = new ArrayList<String>();
+        vmNames.add("FakeVM");
+        GetVmStatsCommand vmStatsCmd =
+                new GetVmStatsCommand(vmNames, "1", "localhost");
+        GetVmStatsAnswer ans =
+                (GetVmStatsAnswer) s_hypervresource.executeRequest(vmStatsCmd);
+        Assert.assertTrue(ans.getDetails(), ans.getResult());
+    }
+
+    @Test
+    public final void testCreateStoragePoolCommand() {
+        String folderName = "." + File.separator + "Dummy";
+        StoragePoolVO pool = createTestStoragePoolVO(folderName);
+
+        CreateStoragePoolCommand cmd = new CreateStoragePoolCommand(true, 
pool);
+        s_logger.debug("TestCreateStoragePoolCommand sending "
+                + s_gson.toJson(cmd));
+
+        Answer ans = s_hypervresource.executeRequest(cmd);
+        Assert.assertTrue(ans.getResult());
+    }
+
+    @Test
+    public final void testModifyStoragePoolCommand() {
+        // Create dummy folder
+        String folderName = "." + File.separator + "Dummy";
+        StoragePoolVO pool = createTestStoragePoolVO(folderName);
+
+        ModifyStoragePoolCommand cmd = new ModifyStoragePoolCommand(
+                true, pool, folderName);
+        Answer ans = s_hypervresource.executeRequest(cmd);
+        Assert.assertTrue(ans.getResult());
+
+        DeleteStoragePoolCommand delCmd =
+                new DeleteStoragePoolCommand(pool, folderName);
+        Answer ans2 = s_hypervresource.executeRequest(delCmd);
+        Assert.assertTrue(ans2.getResult());
+    }
+
+    // Check
+    @Test
+    public final void testModifyStoragePoolCommand2() {
+        // Should return existing pool
+        // Create dummy folder
+        String folderName = "." + File.separator + "Dummy";
+        File folder = new File(folderName);
+        if (!folder.exists()) {
+            if (!folder.mkdir()) {
+                Assert.assertTrue(false);
+            }
+        }
+
+        // Use same spec for pool
+        s_logger.info("Createing pool at : " + folderName);
+
+        StoragePoolVO pool = new StoragePoolVO(StoragePoolType.Filesystem,
+                "127.0.0.1", -1, folderName);
+        pool.setUuid(s_testLocalStoreUUID);
+
+        ModifyStoragePoolCommand cmd = new ModifyStoragePoolCommand(
+                true, pool, folderName);
+        Answer ans = s_hypervresource.executeRequest(cmd);
+        Assert.assertTrue(ans.getResult());
+
+        DeleteStoragePoolCommand delCmd =
+                new DeleteStoragePoolCommand(pool, folderName);
+        Answer ans2 = s_hypervresource.executeRequest(delCmd);
+        Assert.assertTrue(ans2.getResult());
+    }
+
+    public final StoragePoolVO createTestStoragePoolVO(
+            final String folderName) {
+        File folder = new File(folderName);
+        if (!folder.exists()) {
+            if (!folder.mkdir()) {
+                Assert.assertTrue(false);
+            }
+        }
+
+        // Use same spec for pool
+        s_logger.info("Createing pool at : " + folderName);
+
+        StoragePoolVO pool = new StoragePoolVO(StoragePoolType.Filesystem,
+                "127.0.0.1", -1, folderName);
+        return pool;
+    }
+
+    @Test
+    public final void testInitialize() {
+        StartupCommand[] startCmds = s_hypervresource.initialize();
+        Command[] cmds = new Command[] {startCmds[0], startCmds[1]};
+        String result = s_gson.toJson(cmds);
+        if (result == null) {
+            result = "NULL";
+        }
+        s_logger.debug("TestInitialize returned " + result);
+        s_logger.debug("TestInitialize expected " + _setTestJsonResultStr);
+        Assert.assertTrue("StartupCommand[] not what we expected",
+                _setTestJsonResultStr.equals(result));
+        return;
+    }
+
+    @Test
+    public final void testPrimaryStorageDownloadCommandHTTP() {
+        PrimaryStorageDownloadCommand cmd = samplePrimaryDownloadCommand();
+        cmd.setUrl("http://s3-eu-west-1.amazonaws.com/cshv3eu/SmallDisk.vhdx";);
+        corePrimaryStorageDownloadCommandTestCycle(cmd);
+    }
+
+    private void corePrimaryStorageDownloadCommandTestCycle(
+            final PrimaryStorageDownloadCommand cmd) {
+        PrimaryStorageDownloadAnswer ans =
+                (PrimaryStorageDownloadAnswer) s_hypervresource
+                        .executeRequest(cmd);
+        if (!ans.getResult()) {
+            s_logger.error(ans.getDetails());
+        } else {
+            s_logger.debug(ans.getDetails());
+        }
+
+        Assert.assertTrue(ans.getDetails(), ans.getResult());
+        // Test that returned URL works.
+        // CreateCommand createCmd = CreateCommandSample();
+        // CreateCommand testCreateCmd = new
+        // CreateCommand(createCmd.getDiskCharacteristics(),
+        // ans.getInstallPath(), createCmd.getPool());
+        // CreateAnswer ans2 =
+        // (CreateAnswer)s_hypervresource.executeRequest(testCreateCmd);
+        // Assert.assertTrue(ans2.getDetails(), ans2.getResult());
+    }
+
+    private PrimaryStorageDownloadCommand samplePrimaryDownloadCommand() {
+        String cmdJson =
+                "{\"localPath\":"
+                        + s_testLocalStorePathJSON
+                        + ",\"poolUuid\":\""
+                        + s_testLocalStoreUUID
+                        + "\",\"poolId\":201,"
+                        + "\"secondaryStorageUrl\":"
+                        + "\"nfs://10.70.176.36/mnt/cshv3/secondarystorage\","
+                        + "\"primaryStorageUrl\":"
+                        + "\"nfs://10.70.176.29E:\\\\Disks\\\\Disks\","
+                        + "\"url\":"
+                        + 
"\"nfs://10.70.176.36/mnt/cshv3/secondarystorage/template/tmpl//2/204//af39aa7f-2b12-37e1-86d3-e23f2f005101.vhdx\","
+                        + "\"format\":\"VHDX\",\"accountId\":2,"
+                        + "\"name\":"
+                        + "\"204-2-5a1db1ac-932b-3e7e-a0e8-5684c72cb862\""
+                        + ",\"contextMap\":{},\"wait\":10800}";
+        PrimaryStorageDownloadCommand cmd = s_gson.fromJson(cmdJson,
+                PrimaryStorageDownloadCommand.class);
+        return cmd;
+    }
+
+    public final CreateCommand createCommandSample() {
+        String sample =
+                "{\"volId\":17,\"pool\":{\"id\":201,\"uuid\":\""
+                        + s_testLocalStoreUUID
+                        + "\",\"host\":\"10.70.176.29\""
+                        + ",\"path\":"
+                        + s_testLocalStorePathJSON
+                        + ",\"port\":0,\"type\":\"Filesystem\"},"
+                        + "\"diskCharacteristics\":{\"size\":0,"
+                        + "\"tags\":[],\"type\":\"ROOT\",\"name\":\"ROOT-15\","
+                        + "\"useLocalStorage\":true,\"recreatable\":true,"
+                        + "\"diskOfferingId\":11,"
+                        + "\"volumeId\":17,\"hyperType\":\"Hyperv\"},"
+                        + "\"templateUrl\":"
+                        + s_testSampleTemplateURLJSON + ",\"wait\":0}";
+        CreateCommand cmd = s_gson.fromJson(sample, CreateCommand.class);
+        return cmd;
+    }
+
+    @Test
+    public final void testCreateCommand() {
+        String sample =
+                "{\"volId\":10,\"pool\":{\"id\":201,\"uuid\":\""
+                        + s_testLocalStoreUUID
+                        + "\",\"host\":\"10.70.176.29\""
+                        + ",\"path\":"
+                        + s_testLocalStorePathJSON
+                        + ",\"port\":0,\"type\":\"Filesystem\"},"
+                        + "\"diskCharacteristics\":{\"size\":0,"
+                        + "\"tags\":[],\"type\":\"ROOT\",\"name\":\"ROOT-9\","
+                        + "\"useLocalStorage\":true,\"recreatable\":true,"
+                        + "\"diskOfferingId\":11,"
+                        + "\"volumeId\":10,\"hyperType\":\"Hyperv\"},"
+                        + "\"templateUrl\":"
+                        + s_testSampleTemplateURLJSON
+                        + ",\"contextMap\":{},\"wait\":0}";
+
+        File destDir = new File(s_testLocalStorePath);
+        Assert.assertTrue(destDir.isDirectory());
+        File testSampleTemplateURLFile =
+                new File(s_testLocalStorePath
+                        + File.separator
+                        + s_gson.fromJson(s_testSampleTemplateURLJSON,
+                                String.class));
+        Assert.assertTrue(
+                "The template that create should make"
+                        + " volumes from is missing from path "
+                        + testSampleTemplateURLFile.getPath(),
+                testSampleTemplateURLFile.exists());
+
+        int fileCount = destDir.listFiles().length;
+        s_logger.debug(" test local store has " + fileCount + "files");
+        // Test requires there to be a template at the tempalteUrl, which is 
its
+        // location in the local file system.
+        CreateCommand cmd = s_gson.fromJson(sample, CreateCommand.class);
+        CreateAnswer ans = (CreateAnswer) s_hypervresource.executeRequest(cmd);
+        Assert.assertTrue(ans.getDetails(), ans.getResult());
+        Assert.assertTrue("CreateCommand should add a file to the folder",
+                fileCount + 1 == destDir.listFiles().length);
+        File newFile = new File(ans.getVolume().getPath());
+        Assert.assertTrue("The new file should have a size greater than zero",
+                newFile.length() > 0);
+        newFile.delete();
+    }
+
+    @Test
+    public final void testStartCommandCorruptDiskImage() {
+        String sampleStart =
+                "{\"vm\":{\"id\":16,\"name\":\"i-3-17-VM\","
+                        + "\"type\":\"User\",\"cpus\":1,\"speed\":500,"
+                        + "\"minRam\":536870912,\"maxRam\":536870912,"
+                        + "\"arch\":\"x86_64\","
+                        + "\"os\":\"CentOS 6.0 (64-bit)\","
+                        + "\"bootArgs\":\"\",\"rebootOnCrash\":false,"
+                        + "\"enableHA\":false,"
+                        + "\"limitCpuUse\":false,"
+                        + "\"vncPassword\":\"31f82f29aff646eb\","
+                        + "\"params\":{},"
+                        + "\"uuid\":\"8b030b6a-0243-440a-8cc5-45d08815ca11\""
+                        + ",\"disks\":["
+                        + "{\"id\":18,\"name\":\""
+                        + s_testSampleVolumeCorruptUUID
+                        + "\","
+                        + "\"mountPoint\":"
+                        + s_testSampleVolumeCorruptURIJSON
+                        + ","
+                        + "\"path\":"
+                        + s_testSampleVolumeCorruptURIJSON
+                        + ",\"size\":0,"
+                        + "\"type\":\"ROOT\","
+                        + "\"storagePoolType\":\"Filesystem\","
+                        + "\"storagePoolUuid\":\""
+                        + s_testLocalStoreUUID
+                        + "\""
+                        + ",\"deviceId\":0},"
+                        + "{\"id\":16,\"name\":\"Hyper-V Sample2\",\"size\":0,"
+                        + "\"type\":\"ISO\",\"storagePoolType\":\"ISO\","
+                        + "\"deviceId\":3}],"
+                        + "\"nics\":["
+                        + "{\"deviceId\":0,\"networkRateMbps\":100,"
+                        + "\"defaultNic\":true,"
+                        + "\"uuid\":\"99cb4813-23af-428c-a87a-2d1899be4f4b\","
+                        + "\"ip\":\"10.1.1.67\",\"netmask\":\"255.255.255.0\","
+                        + "\"gateway\":\"10.1.1.1\","
+                        + "\"mac\":\"02:00:51:2c:00:0e\",\"dns1\":\"4.4.4.4\","
+                        + "\"broadcastType\":\"Vlan\",\"type\":\"Guest\","
+                        + "\"broadcastUri\":\"vlan://261\","
+                        + "\"isolationUri\":\"vlan://261\","
+                        + "\"isSecurityGroupEnabled\":false}"
+                        + "]},\"contextMap\":{},\"wait\":0}";
+
+        StartCommand cmd = s_gson.fromJson(sampleStart, StartCommand.class);
+        StartAnswer ans =
+                (StartAnswer) s_hypervresource.executeRequest(cmd);
+        Assert.assertFalse(ans.getDetails(), ans.getResult());
+    }
+
+    @Test
+    public final void testStartStopCommand() {
+        String sample = getSampleStartCommand();
+        StartAnswer sans = simpleVmStart(sample);
+        Assert.assertTrue(sans.getDetails(), sans.getResult());
+        StopAnswer stopAns = simpleVmStop();
+        Assert.assertTrue(stopAns.getDetails(), stopAns.getResult());
+    }
+
+    @Test
+    public final void testStartStartCommand() {
+        String sample = getSampleStartCommand();
+
+        StartAnswer sans = simpleVmStart(sample);
+        Assert.assertTrue(sans.getDetails(), sans.getResult());
+        simpleVmStart(sample);
+
+        StopAnswer ans = simpleVmStop();
+        Assert.assertTrue(ans.getDetails(), ans.getResult());
+    }
+
+    private StopAnswer simpleVmStop() {
+        String sampleStop =
+                "{\"isProxy\":false,\"vmName\":\"i-2-17-VM\","
+                        + "\"contextMap\":{},\"wait\":0}";
+        StopCommand cmd = s_gson.fromJson(sampleStop, StopCommand.class);
+        StopAnswer ans = (StopAnswer) s_hypervresource.executeRequest(cmd);
+        return ans;
+    }
+
+    private StartAnswer simpleVmStart(final String sample) {
+        StartCommand cmd = s_gson.fromJson(sample, StartCommand.class);
+        s_logger.info("StartCommand sample " + s_gson.toJson(cmd));
+        StartAnswer ans =
+                (StartAnswer) s_hypervresource.executeRequest(cmd);
+        return ans;
+    }
+
+    @Test
+    public final void testDestroyCommand() {
+        // TODO: how does the command vary when we are only deleting a vm 
versus
+        // deleting a volume?
+
+//        String sample2 = "{\"volume\":" + getSampleVolumeObjectTO() + "}";
+
+        String sample2 =
+                "{\"volume\":{\"name\":\"" + s_testSampleVolumeWorkingUUIDNoExt
+                        + "\",\"storagePoolType\":\"Filesystem\","
+                        + "\"mountPoint\":"
+                        + s_testLocalStorePathJSON
+                        + ",\"path\":" + s_testSampleVolumeTempURIJSON
+                        + ",\"storagePoolUuid\":\"" + s_testLocalStoreUUID
+                        + "\","
+                        + "\"type\":\"ROOT\",\"id\":9,\"size\":0}}";
+        DestroyCommand cmd = s_gson.fromJson(sample2, DestroyCommand.class);
+        Answer ans = (Answer) s_hypervresource.executeRequest(cmd);
+        Assert.assertTrue(ans.getDetails(), ans.getResult());
+    }
+
+    @Test
+    public final void testGetStorageStatsCommand() {
+        // TODO: Update sample data to unsure it is using correct info.
+        String sample =
+                "{\"id\":\""
+                        + s_testLocalStoreUUID
+                        + "\",\"localPath\":"
+                        + s_testLocalStorePathJSON
+                        + ","
+                        + "\"pooltype\":\"Filesystem\","
+                        + "\"contextMap\":{},\"wait\":0}";
+
+        s_logger.info("Sample JSON: " + sample);
+
+        GetStorageStatsCommand cmd =
+                s_gson.fromJson(sample, GetStorageStatsCommand.class);
+        s_hypervresource.executeRequest(cmd);
+        GetStorageStatsAnswer ans =
+                (GetStorageStatsAnswer) s_hypervresource.executeRequest(cmd);
+        Assert.assertTrue(ans.getDetails(), ans.getResult());
+        Assert.assertTrue(ans.getByteUsed() != ans.getCapacityBytes());
+    }
+
+    @After
+    public final void agentTerminate() {
+        // Write carriage return line feed to script's stdin
+        OutputStream scriptInput = s_agentProc.getOutputStream();
+        OutputStreamWriter siw = new OutputStreamWriter(scriptInput);
+        try {
+            BufferedWriter writer = new BufferedWriter(siw);
+            writer.write("\r\n");
+            writer.flush();
+            writer.close();
+        } catch (IOException ex) {
+            s_logger.debug("Error closing agent at " + s_agentExecutable
+                    + " message " + ex.getMessage());
+        }
+    }
+
+    private void agentCreation() {
+        // Launch script
+        try {
+            List<String> exeArgs = new ArrayList<String>();
+
+            exeArgs.add(s_agentExecutable);
+            exeArgs.add("--console");
+
+            // when we launch from the shell, we need to use Cygwin's path to
+            // the exe
+            ProcessBuilder builder = new ProcessBuilder(exeArgs);
+            builder.redirectErrorStream(true);
+            s_agentProc = builder.start();
+            Thread.sleep(4000);
+        } catch (Exception ex) {
+            s_logger.debug("Error calling starting aget at "
+                    + s_agentExecutable
+                    + " message " + ex.getMessage());
+        }
+    }
+
+    @Test
+    public final void testGetHostStatsCommand() {
+        // Arrange
+        long hostIdVal = 123;
+        GetHostStatsCommand cmd = new GetHostStatsCommand("1", "testHost",
+                hostIdVal);
+
+        // Act
+        GetHostStatsAnswer ans = (GetHostStatsAnswer) s_hypervresource
+                .executeRequest(cmd);
+
+        // Assert
+        Assert.assertTrue(ans.getResult());
+        Assert.assertTrue(0.0 < ans.getTotalMemoryKBs());
+        Assert.assertTrue(0.0 < ans.getFreeMemoryKBs());
+        Assert.assertTrue(0.0 <= ans.getNetworkReadKBs());
+        Assert.assertTrue(0.0 <= ans.getNetworkWriteKBs());
+        Assert.assertTrue(0.0 <= ans.getCpuUtilization());
+        Assert.assertTrue(100 >= ans.getCpuUtilization());
+        Assert.assertTrue(ans.getEntityType().equals("host"));
+        Assert.assertTrue(ans.getDetails() == null);
+    }
+
+    public static Properties loadProperties() throws ConfigurationException {
+        Properties properties = new Properties();
+        final File file = PropertiesUtil.findConfigFile("agent.properties");
+        if (file == null) {
+            throw new ConfigurationException(
+                    "Unable to find agent.properties.");
+        }
+
+        s_logger.info("agent.properties found at " + file.getAbsolutePath());
+
+        try {
+            properties.load(new FileInputStream(file));
+        } catch (final FileNotFoundException ex) {
+            throw new CloudRuntimeException("Cannot find the file: "
+                    + file.getAbsolutePath(), ex);
+        } catch (final IOException ex) {
+            throw new CloudRuntimeException("IOException in reading "
+                    + file.getAbsolutePath(), ex);
+        }
+        return properties;
+    }
+
+    private String _setTestJsonResultStr = null;
+
+    public final void setTestJsonResult(final Map<String, Object> params) {
+        File dir = new File((String) params.get("DefaultVirtualDiskFolder"));
+        long usableCapacity = dir.getUsableSpace() - 4294967296L;
+        long totalSpace = dir.getTotalSpace() - 4294967296L;
+
+        // TODO: add test to verify capacity statistics change
+        _setTestJsonResultStr =
+                String.format(
+                        "[{\"com.cloud.agent.api.StartupRoutingCommand\":{"
+                            + "\"cpus\":%s,"
+                    + "\"speed\":%s,"
+                    + "\"memory\":%s,"
+                    + "\"dom0MinMemory\":%s,"
+                    + "\"poolSync\":false,"
+                    + "\"vms\":{},"
+                    + "\"caps\":\"hvm\","
+                    + "\"hypervisorType\":\"Hyperv\","
+                    + "\"hostDetails\":{"
+                    + "\"com.cloud.network.Networks.RouterPrivateIpStrategy\":"
+                    + "\"HostLocal\""
+                    + "},"
+                    + "\"type\":\"Routing\","
+                    + "\"dataCenter\":%s,"
+                    + "\"pod\":%s,"
+                    + "\"cluster\":%s,"
+                    + "\"guid\":\"16f85622-4508-415e-b13a-49a39bb14e4d\","
+                    + "\"name\":\"hypervresource\","
+                    + "\"version\":\"4.2.0\","
+                    + "\"privateIpAddress\":%s,"
+                    + "\"privateMacAddress\":%s,"
+                    + "\"privateNetmask\":%s,"
+                    + "\"storageIpAddress\":%s,"
+                    + "\"storageNetmask\":%s,"
+                    + "\"storageMacAddress\":%s,"
+                    + "\"gatewayIpAddress\":%s,"
+                    + "\"contextMap\":{},"
+                    + "\"wait\":0"
+                    + "}},"
+                    + "{\"com.cloud.agent.api.StartupStorageCommand\":{"
+                    + "\"totalSize\":0,"
+                    + "\"poolInfo\":{"
+                    + "\"uuid\":\"16f85622-4508-415e-b13a-49a39bb14e4d\","
+                    + "\"host\":%s,"
+                    + "\"localPath\":%s,"
+                    + "\"hostPath\":%s,"
+                    + "\"poolType\":\"Filesystem\","
+                    + "\"capacityBytes\":%s,"
+                    + "\"availableBytes\":%s"
+                    + "},"
+                    + "\"resourceType\":\"STORAGE_POOL\","
+                    + "\"hostDetails\":{},"
+                    + "\"type\":\"Storage\","
+                    + "\"dataCenter\":\"1\","
+                    + "\"guid\":"
+                    + "\"16f85622-4508-415e-b13a-49a39bb14e4d\","
+                    + "\"contextMap\":{},"
+                    + "\"wait\":0"
+                    + "}}]",
+                        params.get("TestCoreCount"),
+                        params.get("TestCoreMhz"),
+                        params.get("TestMemoryMb"),
+                        params.get("TestDom0MinMemoryMb"),
+                        s_gson.toJson((String) params.get("zone")),
+                        s_gson.toJson((String) params.get("pod")),
+                        s_gson.toJson((String) params.get("cluster")),
+                        s_gson.toJson((String) params.get("ipaddress")),
+                        s_gson.toJson((String) params
+                                .get("private.mac.address")),
+                        s_gson.toJson((String) params.get(
+                                "private.ip.netmask")),
+                        s_gson.toJson((String) params.get("ipaddress")),
+                        s_gson.toJson((String) params.get(
+                                "private.ip.netmask")),
+                        s_gson.toJson((String) params
+                                .get("private.mac.address")),
+                        s_gson.toJson((String) params.get(
+                                "gateway.ip.address")),
+                        s_gson.toJson((String) params.get("ipaddress")),
+                        s_gson.toJson((String) params
+                                .get("DefaultVirtualDiskFolder")),
+                        s_gson.toJson((String) params
+                                .get("DefaultVirtualDiskFolder")),
+                        s_gson.toJson(totalSpace),
+                        s_gson.toJson(usableCapacity)
+                        );
+    }
+
+    public static String getSamplePrimaryDataStoreInfo() {
+        String samplePrimaryDataStoreInfo =
+                "{\"org.apache.cloudstack.storage.to.PrimaryDataStoreTO\":"
+                        + "{\"uuid\":\"" + s_testLocalStoreUUID + "\","
+                        + "\"id\":201,"
+                        + "\"host\":\"" + s_testPrimaryDataStoreHost + "\","
+                        + "\"type\":\"Filesystem\"," // Not used in
+                                                     // PrimaryDataStoreTO
+                        + "\"poolType\":\"Filesystem\"," // Not used in
+                        // PrimaryDataStoreTO
+                        + "\"path\":" + s_testLocalStorePathJSON + ","
+                        + "\"port\":0}"
+                        + "}";
+        return samplePrimaryDataStoreInfo;
+    }
+
+    public static String getSampleVolumeObjectTO() {
+        String sampleVolumeObjectTO =
+                "{\"org.apache.cloudstack.storage.to.VolumeObjectTO\":"
+                        + "{\"uuid\":\"19ae8e67-cb2c-4ab4-901e-e0b864272b59\","
+                        + "\"volumeType\":\"ROOT\","
+                        + "\"format\":\"VHDX\","
+                        + "\"dataStore\":" + getSamplePrimaryDataStoreInfo()
+                        + ","
+                        + "\"name\":\"" + s_testSampleVolumeWorkingUUIDNoExt + 
"\","
+                        + "\"size\":52428800,"
+                        + "\"volumeId\":10,"
+                        // "\"vmName\":\"i-3-5-VM\"," + // TODO: required?
+                        + "\"accountId\":3,\"id\":10}"
+                        + "}"; // end of destTO
+        return sampleVolumeObjectTO;
+    }
+
+    public static String getSampleStartCommand() {
+        String sample =
+                "{\"vm\":{\"id\":17,\"name\":\"i-2-17-VM\","
+                        + "\"type\":\"User\",\"cpus\":1,\"speed\":500,"
+                        + "\"minRam\":536870912,\"maxRam\":536870912,"
+                        + "\"arch\":\"x86_64\","
+                        + "\"os\":\"CentOS 6.0 (64-bit)\","
+                        + "\"bootArgs\":\"\",\"rebootOnCrash\":false,"
+                        + "\"enableHA\":false,\"limitCpuUse\":false,"
+                        + "\"vncPassword\":\"31f82f29aff646eb\","
+                        + "\"params\":{},"
+                        + "\"uuid\":\"8b030b6a-0243-440a-8cc5-45d08815ca11\""
+                        + ",\"disks\":["
+                        + "{\"data\":"
+                        + getSampleVolumeObjectTO()
+                        + ",\"diskSeq\":0,\"type\":\"ROOT\"},"
+                        + "{\"diskSeq\":1,\"type\":\"ISO\"}"
+                        + "],"
+                        + "\"nics\":["
+                        + "{\"deviceId\":0,\"networkRateMbps\":100,"
+                        + "\"defaultNic\":true,"
+                        + "\"uuid\":\"99cb4813-23af-428c-a87a-2d1899be4f4b\","
+                        + "\"ip\":\"10.1.1.67\","
+                        + "\"netmask\":\"255.255.255.0\","
+                        + "\"gateway\":\"10.1.1.1\","
+                        + "\"mac\":\"02:00:51:2c:00:0e\",\"dns1\":\"4.4.4.4\","
+                        + "\"broadcastType\":\"Vlan\",\"type\":\"Guest\","
+                        + "\"broadcastUri\":\"vlan://261\","
+                        + "\"isolationUri\":\"vlan://261\","
+                        + "\"isSecurityGroupEnabled\":false}"
+                        + "]},\"contextMap\":{},\"wait\":0}";
+        return sample;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/f9f196a4/plugins/pom.xml
----------------------------------------------------------------------
diff --git a/plugins/pom.xml b/plugins/pom.xml
index e33ebd8..a707719 100755
--- a/plugins/pom.xml
+++ b/plugins/pom.xml
@@ -40,6 +40,7 @@
     <module>event-bus/rabbitmq</module>
     <module>hypervisors/baremetal</module>
     <module>hypervisors/ucs</module>
+    <module>hypervisors/hyperv</module>
     <module>network-elements/elastic-loadbalancer</module>
     <module>network-elements/ovs</module>
     <module>network-elements/juniper-contrail</module>
@@ -120,6 +121,17 @@
       </modules>
     </profile>
     <profile>
+      <id>hyperV</id>
+      <activation>
+        <property>
+          <name>hyperV</name>
+        </property>
+      </activation>
+      <modules>
+          <module>hypervisors/hyperv</module>
+      </modules>
+    </profile>
+    <profile>
       <id>f5</id>
       <activation>
         <property>

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/f9f196a4/server/src/com/cloud/ha/HighAvailabilityManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/ha/HighAvailabilityManagerImpl.java 
b/server/src/com/cloud/ha/HighAvailabilityManagerImpl.java
index 59337c0..d6feaf3 100755
--- a/server/src/com/cloud/ha/HighAvailabilityManagerImpl.java
+++ b/server/src/com/cloud/ha/HighAvailabilityManagerImpl.java
@@ -206,8 +206,8 @@ public class HighAvailabilityManagerImpl extends 
ManagerBase implements HighAvai
             return;
         }
 
-        if(host.getHypervisorType() == HypervisorType.VMware) {
-            s_logger.info("Don't restart for VMs on host " + host.getId() + " 
as the host is VMware host");
+        if(host.getHypervisorType() == HypervisorType.VMware || 
host.getHypervisorType() == HypervisorType.Hyperv) {
+            s_logger.info("Don't restart for VMs on host " + host.getId() + " 
as the host is VMware host or on Hyperv Host");
             return;
         }
 
@@ -302,6 +302,11 @@ public class HighAvailabilityManagerImpl extends 
ManagerBase implements HighAvai
             return;
         }
 
+        if(vm.getHypervisorType() == HypervisorType.VMware || 
vm.getHypervisorType() == HypervisorType.Hyperv) {
+            s_logger.info("Skip HA for VMware VM or Hyperv VM" + 
vm.getInstanceName());
+            return;
+        }
+
         if (!investigate) {
             if (s_logger.isDebugEnabled()) {
                 s_logger.debug("VM does not require investigation so I'm 
marking it as Stopped: " + vm.toString());

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/f9f196a4/server/src/com/cloud/network/guru/ControlNetworkGuru.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/network/guru/ControlNetworkGuru.java 
b/server/src/com/cloud/network/guru/ControlNetworkGuru.java
index 1943e16..a5b7c88 100755
--- a/server/src/com/cloud/network/guru/ControlNetworkGuru.java
+++ b/server/src/com/cloud/network/guru/ControlNetworkGuru.java
@@ -133,7 +133,9 @@ public class ControlNetworkGuru extends PodBasedNetworkGuru 
implements NetworkGu
     InsufficientAddressCapacityException {
         assert nic.getTrafficType() == TrafficType.Control;
 
-        if (dest.getHost().getHypervisorType() == HypervisorType.VMware && 
isRouterVm(vm)) {
+        // we have to get management/private ip for the control nic for 
vmware/hyperv due ssh issues.
+         HypervisorType hType = dest.getHost().getHypervisorType(); 
+        if ( ( (hType == HypervisorType.VMware) || (hType == 
HypervisorType.Hyperv) )&& isRouterVm(vm)) {
             if(dest.getDataCenter().getNetworkType() != NetworkType.Basic) {
                 super.reserve(nic, config, vm, dest, context);
 

Reply via email to