| // 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. |
| using System; |
| using CloudStack.Plugin.WmiWrappers.ROOT.VIRTUALIZATION; |
| using System.Management; |
| using Newtonsoft.Json.Linq; |
| using Newtonsoft.Json; |
| using System.IO; |
| using log4net; |
| using HypervResource; |
| using CloudStack.Plugin.AgentShell; |
| using System.Collections.Generic; |
| using System.Xml; |
| using Xunit; |
| |
| namespace ServerResource.Tests |
| { |
| public class HypervResourceControllerTest |
| { |
| protected static string testCifsUrl = AgentSettings.Default.testCifsUrl; |
| protected static string testCifsPath = AgentSettings.Default.testCifsPath; |
| protected static String testPrimaryDataStoreHost = HypervResourceController.config.StorageIpAddress; |
| protected static String testS3TemplateName = AgentSettings.Default.testS3TemplateName; |
| protected static String testCifsTemplateName = AgentSettings.Default.testS3TemplateName; |
| protected static String testSystemVMTemplateName = AgentSettings.Default.testSystemVMTemplateName; |
| protected static String testSystemVMTemplateNameNoExt = AgentSettings.Default.testSystemVMTemplateNameNoExt; |
| protected static String testLocalStoreUUID = "5fe2bad3-d785-394e-9949-89786b8a63d2"; |
| protected static String testLocalStorePath = Path.Combine(AgentSettings.Default.hyperv_plugin_root, "var", "test", "storagepool"); |
| protected static String testSecondaryStoreLocalPath = Path.Combine(AgentSettings.Default.hyperv_plugin_root, "var", "test", "secondary"); |
| |
| // TODO: differentiate between NFS and HTTP template URLs. |
| protected static String testSampleTemplateUUID = "TestCopiedLocalTemplate.vhdx"; |
| protected static String testSampleTemplateURL = testSampleTemplateUUID; |
| |
| // test volumes are both a minimal size vhdx. Changing the extension to .vhd makes on corrupt. |
| protected static String testSampleVolumeWorkingUUID = "TestVolumeLegit.vhdx"; |
| protected static String testSampleVolumeCorruptUUID = "TestVolumeCorrupt.vhd"; |
| protected static String testSampleVolumeTempUUID = "TestVolumeTemp.vhdx"; |
| protected static String testSampleVolumeTempUUIDNoExt = "TestVolumeTemp"; |
| protected static String testSampleVolumeWorkingURIJSON; |
| protected static String testSampleVolumeCorruptURIJSON; |
| protected static String testSampleVolumeTempURIJSON; |
| |
| protected static String testSampleTemplateURLJSON; |
| protected static String testLocalStorePathJSON; |
| |
| protected static WmiCallsV2 wmiCallsV2 = new WmiCallsV2(); |
| |
| private static ILog s_logger = LogManager.GetLogger(typeof(HypervResourceControllerTest)); |
| |
| /// <summary> |
| /// Test WmiCalls to which incoming HTTP POST requests are dispatched. |
| /// |
| /// TODO: revise beyond first approximation |
| /// First approximation is a quick port of the existing Java tests for Hyper-V server resource. |
| /// A second approximation would use the AgentShell settings files directly. |
| /// A third approximation would look to invoke ServerResource methods via an HTTP request |
| /// </summary> |
| public HypervResourceControllerTest() |
| { |
| AgentService.ConfigServerResource(); |
| HypervResourceController.config.PrivateMacAddress = AgentSettings.Default.private_mac_address; |
| HypervResourceController.config.PrivateNetmask = AgentSettings.Default.private_ip_netmask; |
| HypervResourceController.config.StorageIpAddress = HypervResourceController.config.PrivateIpAddress; |
| HypervResourceController.config.StorageMacAddress = HypervResourceController.config.PrivateMacAddress; |
| HypervResourceController.config.StorageNetmask = HypervResourceController.config.PrivateNetmask; |
| |
| |
| // Used to create existing StoragePool in preparation for the ModifyStoragePool |
| testLocalStoreUUID = AgentSettings.Default.local_storage_uuid.ToString(); |
| |
| // Make sure secondary store is available. |
| string fullPath = Path.GetFullPath(testSecondaryStoreLocalPath); |
| s_logger.Info("Test secondary storage in " + fullPath); |
| DirectoryInfo testSecondarStoreDir = new DirectoryInfo(fullPath); |
| if (!testSecondarStoreDir.Exists) |
| { |
| try |
| { |
| testSecondarStoreDir.Create(); |
| } |
| catch (System.IO.IOException ex) |
| { |
| throw new NotImplementedException("Need to be able to create the folder " + testSecondarStoreDir.FullName + " failed due to " + ex.Message); |
| } |
| } |
| |
| // Convert to secondary storage string to canonical path |
| testSecondaryStoreLocalPath = testSecondarStoreDir.FullName; |
| AgentSettings.Default.local_secondary_storage_path = testSecondaryStoreLocalPath; |
| |
| // Make sure local primary storage is available |
| DirectoryInfo testPoolDir = new DirectoryInfo(testLocalStorePath); |
| Assert.True(testPoolDir.Exists, "To simulate local file system Storage Pool, you need folder at " + testPoolDir.FullName); |
| |
| // Convert to local primary storage string to canonical path |
| testLocalStorePath = testPoolDir.FullName; |
| AgentSettings.Default.local_storage_path = testLocalStorePath; |
| |
| // Clean up old test files in local storage folder |
| FileInfo testVolWorks = new FileInfo(Path.Combine(testLocalStorePath, testSampleVolumeWorkingUUID)); |
| Assert.True(testVolWorks.Exists, "Create a working virtual disk at " + testVolWorks.FullName); |
| |
| |
| // Delete all temporary files in local folder save the testVolWorks |
| foreach (var file in testPoolDir.GetFiles()) |
| { |
| if (file.FullName == testVolWorks.FullName) |
| { |
| continue; |
| } |
| file.Delete(); |
| file.Refresh(); |
| Assert.False(file.Exists, "removed file from previous test called " + file.FullName); |
| } |
| |
| // Recreate starting point files for test, and record JSON encoded paths for each ... |
| testSampleVolumeTempURIJSON = CreateTestDiskImageFromExistingImage(testVolWorks, testLocalStorePath, testSampleVolumeTempUUID); |
| s_logger.Info("Created " + testSampleVolumeTempURIJSON); |
| testSampleVolumeCorruptURIJSON = CreateTestDiskImageFromExistingImage(testVolWorks, testLocalStorePath, testSampleVolumeCorruptUUID); |
| s_logger.Info("Created " + testSampleVolumeCorruptURIJSON); |
| CreateTestDiskImageFromExistingImage(testVolWorks, testLocalStorePath, testSampleTemplateUUID); |
| testSampleTemplateURLJSON = JsonConvert.SerializeObject(testSampleTemplateUUID); |
| s_logger.Info("Created " + testSampleTemplateURLJSON + " in local storage."); |
| |
| // ... including a secondary storage template: |
| CreateTestDiskImageFromExistingImage(testVolWorks, testSecondarStoreDir.FullName, "af39aa7f-2b12-37e1-86d3-e23f2f005101.vhdx"); |
| s_logger.Info("Created " + "af39aa7f-2b12-37e1-86d3-e23f2f005101.vhdx" + " in secondary (NFS) storage."); |
| |
| |
| // Capture other JSON encoded paths |
| testSampleVolumeWorkingURIJSON = Newtonsoft.Json.JsonConvert.SerializeObject(testVolWorks.FullName); |
| testLocalStorePathJSON = JsonConvert.SerializeObject(testLocalStorePath); |
| |
| // TODO: may need to initialise the server resource in future. |
| // s_hypervresource.initialize(); |
| |
| // Verify sample template is in place storage pool |
| s_logger.Info("setUp complete, sample StoragePool at " + testLocalStorePathJSON |
| + " sample template at " + testSampleTemplateURLJSON); |
| } |
| |
| private String CreateTestDiskImageFromExistingImage(FileInfo srcFile, |
| String dstPath, |
| String dstFileName) |
| { |
| var newFullname = Path.Combine(dstPath, dstFileName); |
| var newFileInfo = new FileInfo(newFullname); |
| if (!newFileInfo.Exists) |
| { |
| newFileInfo = srcFile.CopyTo(newFullname); |
| } |
| newFileInfo.Refresh(); |
| Assert.True(newFileInfo.Exists, "Attempted to create " + newFullname + " from " + newFileInfo.FullName); |
| |
| return JsonConvert.SerializeObject(newFileInfo.FullName); |
| } |
| |
| [Fact(Skip="these are functional tests")] |
| public void TestPrimaryStorageDownloadCommandHTTP() |
| { |
| string downloadURI = "https://s3-eu-west-1.amazonaws.com/cshv3eu/SmallDisk.vhdx"; |
| corePrimaryStorageDownloadCommandTestCycle(downloadURI); |
| } |
| |
| private void corePrimaryStorageDownloadCommandTestCycle(string downloadURI) |
| { |
| // Arrange |
| HypervResourceController rsrcServer = new HypervResourceController(); |
| dynamic jsonPSDCmd = JsonConvert.DeserializeObject(samplePrimaryDownloadCommand()); |
| jsonPSDCmd.url = downloadURI; |
| |
| // Act |
| dynamic jsonResult = rsrcServer.PrimaryStorageDownloadCommand(jsonPSDCmd); |
| |
| // Assert |
| JObject ansAsProperty = jsonResult[0]; |
| dynamic ans = ansAsProperty.GetValue(CloudStackTypes.PrimaryStorageDownloadAnswer); |
| Assert.True((bool)ans.result, "PrimaryStorageDownloadCommand did not succeed " + ans.details); |
| |
| // Test that URL of downloaded template works for file creation. |
| dynamic jsonCreateCmd = JsonConvert.DeserializeObject(CreateCommandSample()); |
| jsonCreateCmd.templateUrl = ans.installPath; |
| dynamic jsonAns2 = rsrcServer.CreateCommand(jsonCreateCmd); |
| JObject ansAsProperty2 = jsonAns2[0]; |
| dynamic ans2 = ansAsProperty2.GetValue(CloudStackTypes.CreateAnswer); |
| |
| Assert.True((bool)ans2.result, (string)ans2.details); |
| |
| FileInfo newFile = new FileInfo((string)ans2.volume.path); |
| Assert.True(newFile.Length > 0, "The new file should have a size greater than zero"); |
| newFile.Delete(); |
| } |
| |
| private string samplePrimaryDownloadCommand() |
| { |
| String cmdJson = "{\"localPath\":" + testLocalStorePathJSON + |
| ",\"poolUuid\":\"" + testLocalStoreUUID + "\",\"poolId\":201," + |
| "\"secondaryStorageUrl\":\"nfs://10.70.176.36/mnt/cshv3/secondarystorage\"," + |
| "\"primaryStorageUrl\":\"nfs://" + HypervResourceController.config.StorageIpAddress + "E:\\\\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}"; |
| return cmdJson; |
| } |
| |
| public string CreateCommandSample() |
| { |
| String sample = "{\"volId\":17,\"pool\":{\"id\":201,\"uuid\":\"" + testLocalStoreUUID + "\",\"host\":\"" + HypervResourceController.config.StorageIpAddress + "\"" + |
| ",\"path\":" + 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\":" + testSampleTemplateURLJSON + ",\"wait\":0}"; |
| return sample; |
| } |
| |
| [Fact(Skip="these are functional tests")] |
| public void TestDestroyCommand() |
| { |
| // Arrange |
| String sampleVolume = getSampleVolumeObjectTO(); |
| String destroyCmd = //"{\"volume\":" + getSampleVolumeObjectTO() + "}"; |
| "{\"volume\":{\"name\":\"" + testSampleVolumeTempUUIDNoExt |
| + "\",\"storagePoolType\":\"Filesystem\"," |
| + "\"mountPoint\":" |
| + testLocalStorePathJSON |
| + ",\"path\":" + testSampleVolumeTempURIJSON |
| + ",\"storagePoolUuid\":\"" + testLocalStoreUUID |
| + "\"," |
| + "\"type\":\"ROOT\",\"id\":9,\"size\":0}}"; |
| |
| HypervResourceController rsrcServer = new HypervResourceController(); |
| dynamic jsonDestroyCmd = JsonConvert.DeserializeObject(destroyCmd); |
| |
| // Act |
| dynamic destroyAns = rsrcServer.DestroyCommand(jsonDestroyCmd); |
| |
| // Assert |
| JObject ansAsProperty2 = destroyAns[0]; |
| dynamic ans = ansAsProperty2.GetValue(CloudStackTypes.Answer); |
| String path = jsonDestroyCmd.volume.path; |
| Assert.True((bool)ans.result, "DestroyCommand did not succeed " + ans.details); |
| Assert.True(!File.Exists(path), "Failed to delete file " + path); |
| } |
| |
| [Fact(Skip="these are functional tests")] |
| public void TestCreateCommand() |
| { |
| // TODO: Need sample to update the test. |
| // Arrange |
| String createCmd = "{\"volId\":10,\"pool\":{\"id\":201,\"uuid\":\"" + testLocalStoreUUID + "\",\"host\":\"" + HypervResourceController.config.StorageIpAddress + "\"" + |
| ",\"path\":" + 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\":" + testSampleTemplateURLJSON + ",\"contextMap\":{},\"wait\":0}"; |
| dynamic jsonCreateCmd = JsonConvert.DeserializeObject(createCmd); |
| HypervResourceController rsrcServer = new HypervResourceController(); |
| |
| Assert.True(Directory.Exists(testLocalStorePath)); |
| string filePath = Path.Combine(testLocalStorePath, (string)JsonConvert.DeserializeObject(testSampleTemplateURLJSON)); |
| Assert.True(File.Exists(filePath), "The template we make volumes from is missing from path " + filePath); |
| int fileCount = Directory.GetFiles(testLocalStorePath).Length; |
| s_logger.Debug(" test local store has " + fileCount + "files"); |
| |
| // Act |
| // Test requires there to be a template at the tempalteUrl, which is its location in the local file system. |
| dynamic jsonResult = rsrcServer.CreateCommand(jsonCreateCmd); |
| |
| JObject ansAsProperty2 = jsonResult[0]; |
| dynamic ans = ansAsProperty2.GetValue(CloudStackTypes.CreateAnswer); |
| Assert.NotNull(ans); |
| Assert.True((bool)ans.result, "Failed to CreateCommand due to " + (string)ans.result); |
| Assert.Equal(Directory.GetFiles(testLocalStorePath).Length, fileCount + 1); |
| FileInfo newFile = new FileInfo((string)ans.volume.path); |
| Assert.True(newFile.Length > 0, "The new file should have a size greater than zero"); |
| newFile.Delete(); |
| } |
| |
| /// <summary> |
| /// Possible additional tests: place an ISO in the drive |
| /// </summary> |
| [Fact(Skip="these are functional tests")] |
| public void TestStartStopCommand() |
| { |
| string vmName = TestStartCommand(); |
| TestStopCommand(vmName); |
| } |
| |
| public static String getSamplePrimaryDataStoreInfo() |
| { |
| String samplePrimaryDataStoreInfo = |
| "{\"org.apache.cloudstack.storage.to.PrimaryDataStoreTO\":" + |
| "{\"uuid\":\"" + testLocalStoreUUID + "\"," + |
| "\"id\":201," + |
| "\"host\":\"" + testPrimaryDataStoreHost + "\"," + |
| "\"type\":\"Filesystem\"," + // Not used in PrimaryDataStoreTO |
| "\"poolType\":\"Filesystem\"," + // Not used in PrimaryDataStoreTO |
| "\"path\":" + 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\":\"" + testSampleVolumeTempUUIDNoExt + "\"," + |
| "\"size\":52428800," + |
| "\"volumeId\":10," + |
| // "\"vmName\":\"i-3-5-VM\"," + // TODO: do we have to fill in the vmName? |
| "\"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; |
| } |
| |
| |
| [Fact(Skip="these are functional tests")] |
| public void TestCopyCommandFromCifs() |
| { |
| // Arrange |
| string sampleCopyCommandForTemplateDownload = |
| #region string_literal |
| // org.apache.cloudstack.storage.command.CopyCommand |
| "{\"srcTO\":" + |
| "{\"org.apache.cloudstack.storage.to.TemplateObjectTO\":" + |
| "{\"path\":\"" + testCifsPath + "\"," + |
| "\"origUrl\":\"http://10.147.28.7/templates/5d67394c-4efd-4b62-966b-51aa53b35277.vhd.bz2\"," + |
| "\"uuid\":\"7e4ca941-cb1b-4113-ab9e-043960d0fb10\"," + |
| "\"id\":206," + |
| "\"format\":\"VHDX\"," + |
| "\"accountId\":2," + |
| "\"checksum\":\"4b31e2846cc67fc10ea7281986519a54\"," + |
| "\"hvm\":true," + |
| "\"displayText\":\"OS031\"," + |
| "\"imageDataStore\":" + |
| "{\"com.cloud.agent.api.to.NfsTO\":" + |
| "{\"_url\":\"" + testCifsUrl + "\"," + // Unique item here |
| "\"_role\":\"Image\"}" + |
| "}," + // end of imageDataStore |
| "\"hypervisorType\":\"Hyperv\"," + |
| "\"name\":\"" + testS3TemplateName + "\"}" + |
| "}," + // end of srcTO |
| "\"destTO\":" + |
| "{\"org.apache.cloudstack.storage.to.TemplateObjectTO\":" + |
| "{" + |
| "\"origUrl\":\"http://10.147.28.7/templates/5d67394c-4efd-4b62-966b-51aa53b35277.vhd.bz2\"," + |
| "\"uuid\":\"7e4ca941-cb1b-4113-ab9e-043960d0fb10\"," + |
| "\"id\":206," + |
| "\"format\":\"VHDX\"," + |
| "\"accountId\":2," + |
| "\"checksum\":\"4b31e2846cc67fc10ea7281986519a54\"," + |
| "\"hvm\":true," + |
| "\"displayText\":\"Test of CIFS Download\"," + |
| "\"imageDataStore\":" + getSamplePrimaryDataStoreInfo() + "," + // end of imageDataStore |
| "\"name\":\"" + testS3TemplateName + "\"," + |
| "\"hypervisorType\":\"Hyperv\"}" + |
| "}," +// end of destTO |
| "\"wait\":10800}"; // end of CopyCommand |
| #endregion |
| |
| HypervResourceController rsrcServer; |
| dynamic jsonDownloadCopyCmd; |
| string dwnldDest; |
| dynamic jsonCloneCopyCmd; |
| string newVolName; |
| CopyCommandTestSetupCifs(null, sampleCopyCommandForTemplateDownload, out rsrcServer, out jsonDownloadCopyCmd, out dwnldDest, out jsonCloneCopyCmd, out newVolName); |
| |
| // Act & Assert |
| DownloadTemplateToPrimaryStorage(rsrcServer, jsonDownloadCopyCmd, dwnldDest); |
| |
| // Repeat to verify ability to detect existing file. |
| DownloadTemplateToPrimaryStorage(rsrcServer, jsonDownloadCopyCmd, dwnldDest); |
| |
| File.Delete(dwnldDest); |
| } |
| |
| [Fact(Skip="these are functional tests")] |
| public void TestCopyCommand() |
| { |
| // Arrange |
| string sampleCopyCommandToCreateVolumeFromTemplate = |
| #region string_literal |
| // org.apache.cloudstack.storage.command.CopyCommand |
| "{\"srcTO\":" + |
| "{\"org.apache.cloudstack.storage.to.TemplateObjectTO\":" + |
| "{" + |
| "\"origUrl\":\"http://people.apache.org/~bhaisaab/vms/ttylinux_pv.vhd\"," + |
| "\"uuid\":\"9873f1c0-bdcc-11e2-8baa-ea85dab5fcd0\"," + |
| "\"id\":5," + |
| "\"format\":\"VHDX\"," + |
| "\"accountId\":1," + |
| "\"checksum\":\"4b31e2846cc67fc10ea7281986519a54\"," + |
| "\"hvm\":false," + |
| "\"displayText\":\"tiny Linux\"," + |
| "\"imageDataStore\":" + getSamplePrimaryDataStoreInfo() + "," + |
| "\"name\":\"" + testS3TemplateName + "\"}" + |
| "}," + // end of srcTO |
| "\"destTO\":" + |
| "{\"org.apache.cloudstack.storage.to.VolumeObjectTO\":" + |
| "{\"uuid\":\"19ae8e67-cb2c-4ab4-901e-e0b864272b59\"," + |
| "\"volumeType\":\"ROOT\"," + |
| "\"dataStore\":" + getSamplePrimaryDataStoreInfo() + "," + |
| "\"name\":\"ROOT-5\"," + |
| "\"size\":52428800," + |
| "\"volumeId\":10," + |
| "\"vmName\":\"i-3-5-VM\"," + |
| "\"accountId\":3," + |
| "\"id\":10 }" + |
| "}," + // end of destTO |
| "\"wait\":0}"; // end of Copy Command |
| #endregion |
| //"name":"ROOT-8","size":140616708,"volumeId":8,"vmName":"s-8-VM","accountId":1,"id":8}},"contextMap":{},"wait":0} |
| |
| string sampleCopyCommandForTemplateDownload = |
| #region string_literal |
| // org.apache.cloudstack.storage.command.CopyCommand |
| "{\"srcTO\":" + |
| "{\"org.apache.cloudstack.storage.to.TemplateObjectTO\":" + |
| "{\"path\":\"" + testS3TemplateName + ".vhdx" + "\"," + |
| "\"origUrl\":\"http://10.147.28.7/templates/5d67394c-4efd-4b62-966b-51aa53b35277.vhd.bz2\"," + |
| "\"uuid\":\"7e4ca941-cb1b-4113-ab9e-043960d0fb10\"," + |
| "\"id\":206," + |
| "\"format\":\"VHDX\"," + |
| "\"accountId\":2," + |
| "\"checksum\":\"4b31e2846cc67fc10ea7281986519a54\"," + |
| "\"hvm\":true," + |
| "\"displayText\":\"OS031\"," + |
| "\"imageDataStore\":" + |
| "{\"com.cloud.agent.api.to.S3TO\":" + |
| "{\"id\":1," + |
| "\"uuid\":\"95a64c8f-2128-4502-b5b4-0d7aa77406d2\"," + |
| "\"accessKey\":\"" + AgentSettings.Default.testS3AccessKey + "\"," + |
| "\"secretKey\":\"" + AgentSettings.Default.testS3SecretKey + "\"," + |
| "\"endPoint\":\"" + AgentSettings.Default.testS3Endpoint + "\"," + |
| "\"bucketName\":\"" + AgentSettings.Default.testS3Bucket + "\"," + |
| "\"httpsFlag\":false," + |
| "\"created\":\"May 19, 2013 4:17:25 PM\"}" + |
| "}," + // end of imageDataStore |
| "\"name\":\"" + testS3TemplateName + "\"}" + |
| "}," + // end of srcTO |
| "\"destTO\":" + |
| "{\"org.apache.cloudstack.storage.to.TemplateObjectTO\":" + |
| "{" + |
| "\"origUrl\":\"http://10.147.28.7/templates/5d67394c-4efd-4b62-966b-51aa53b35277.vhd.bz2\"," + |
| "\"uuid\":\"7e4ca941-cb1b-4113-ab9e-043960d0fb10\"," + |
| "\"id\":206," + |
| "\"format\":\"VHDX\"," + |
| "\"accountId\":2," + |
| "\"checksum\":\"4b31e2846cc67fc10ea7281986519a54\"," + |
| "\"hvm\":true," + |
| "\"displayText\":\"OS031\"," + |
| "\"imageDataStore\":" + getSamplePrimaryDataStoreInfo() + "," + // end of imageDataStore |
| "\"name\":\"" + testS3TemplateName + "\"}" + |
| "}," +// end of destTO |
| "\"wait\":10800}"; // end of CopyCommand |
| #endregion |
| |
| HypervResourceController rsrcServer; |
| dynamic jsonDownloadCopyCmd; |
| string dwnldDest; |
| dynamic jsonCloneCopyCmd; |
| string newVolName; |
| CopyCommandTestSetup(sampleCopyCommandToCreateVolumeFromTemplate, sampleCopyCommandForTemplateDownload, out rsrcServer, out jsonDownloadCopyCmd, out dwnldDest, out jsonCloneCopyCmd, out newVolName); |
| |
| // Act & Assert |
| DownloadTemplateToPrimaryStorage(rsrcServer, jsonDownloadCopyCmd, dwnldDest); |
| CreateVolumeFromTemplate(rsrcServer, jsonCloneCopyCmd, newVolName); |
| |
| // Repeat to verify ability to detect existing file. |
| DownloadTemplateToPrimaryStorage(rsrcServer, jsonDownloadCopyCmd, dwnldDest); |
| |
| File.Delete(dwnldDest); |
| File.Delete(newVolName); |
| } |
| |
| private static void CreateVolumeFromTemplate(HypervResourceController rsrcServer, dynamic jsonCloneCopyCmd, string newVolName) |
| { |
| dynamic copyResult = rsrcServer.CopyCommand(jsonCloneCopyCmd); |
| |
| // Assert |
| Assert.NotNull(copyResult[0][CloudStackTypes.CopyCmdAnswer]); |
| Assert.True((bool)copyResult[0][CloudStackTypes.CopyCmdAnswer].result, "CopyCommand did not succeed " + copyResult[0][CloudStackTypes.CopyCmdAnswer].details); |
| Assert.True(File.Exists(newVolName), "CopyCommand failed to generate " + newVolName); |
| } |
| |
| private static void DownloadTemplateToPrimaryStorage(HypervResourceController rsrcServer, dynamic jsonDownloadCopyCmd, string dwnldDest) |
| { |
| dynamic dwnldResult = rsrcServer.CopyCommand(jsonDownloadCopyCmd); |
| |
| // Assert |
| Assert.NotNull(dwnldResult[0][CloudStackTypes.CopyCmdAnswer]); |
| Assert.True((bool)dwnldResult[0][CloudStackTypes.CopyCmdAnswer].result, "CopyCommand did not succeed " + dwnldResult[0][CloudStackTypes.CopyCmdAnswer].details); |
| Assert.True(File.Exists(dwnldDest), "CopyCommand failed to generate " + dwnldDest); |
| } |
| |
| [Fact(Skip="these are functional tests")] |
| public void TestCopyCommandBz2Img() |
| { |
| // Arrange |
| string sampleCopyCommandToCreateVolumeFromTemplate = |
| #region string_literal |
| // org.apache.cloudstack.storage.command.CopyCommand |
| "{\"srcTO\":" + |
| "{\"org.apache.cloudstack.storage.to.TemplateObjectTO\":" + |
| "{" + |
| "\"origUrl\":\"http://people.apache.org/~bhaisaab/vms/ttylinux_pv.vhd\"," + |
| "\"uuid\":\"9873f1c0-bdcc-11e2-8baa-ea85dab5fcd0\"," + |
| "\"id\":5," + |
| "\"format\":\"VHD\"," + |
| "\"accountId\":1," + |
| "\"checksum\":\"f613f38c96bf039f2e5cbf92fa8ad4f8\"," + |
| "\"hvm\":false," + |
| "\"displayText\":\"tiny Linux\"," + |
| "\"imageDataStore\":" + getSamplePrimaryDataStoreInfo() + "," + |
| "\"name\":\"" + testSystemVMTemplateNameNoExt + "\"}" + |
| "}," + // end of srcTO |
| "\"destTO\":" + |
| "{\"org.apache.cloudstack.storage.to.VolumeObjectTO\":" + |
| "{\"uuid\":\"19ae8e67-cb2c-4ab4-901e-e0b864272b59\"," + |
| "\"volumeType\":\"ROOT\"," + |
| "\"dataStore\":" + getSamplePrimaryDataStoreInfo() + "," + |
| "\"name\":\"ROOT-5\"," + |
| "\"size\":52428800," + |
| "\"volumeId\":10," + |
| "\"vmName\":\"i-3-5-VM\"," + |
| "\"accountId\":1," + |
| "\"id\":10}" + |
| "}," + // end of destTO |
| "\"wait\":0}"; // end of Copy Command |
| #endregion |
| |
| string sampleCopyCommandForTemplateDownload = |
| #region string_literal |
| // org.apache.cloudstack.storage.command.CopyCommand |
| "{\"srcTO\":" + |
| "{\"org.apache.cloudstack.storage.to.TemplateObjectTO\":" + |
| "{\"path\":\"" + testSystemVMTemplateName + "\"," + |
| "\"origUrl\":\"http://10.147.28.7/templates/5d67394c-4efd-4b62-966b-51aa53b35277.vhd.bz2\"," + |
| "\"uuid\":\"7e4ca941-cb1b-4113-ab9e-043960d0fb10\"," + |
| "\"id\":206," + |
| "\"format\":\"VHD\"," + |
| "\"accountId\":1," + |
| "\"checksum\": \"f613f38c96bf039f2e5cbf92fa8ad4f8\"," + |
| "\"hvm\":true," + |
| "\"displayText\":\"OS031\"," + |
| "\"imageDataStore\":" + |
| "{\"com.cloud.agent.api.to.S3TO\":" + |
| "{\"id\":1," + |
| "\"uuid\":\"95a64c8f-2128-4502-b5b4-0d7aa77406d2\"," + |
| "\"accessKey\":\"" + AgentSettings.Default.testS3AccessKey + "\"," + |
| "\"secretKey\":\"" + AgentSettings.Default.testS3SecretKey + "\"," + |
| "\"endPoint\":\"" + AgentSettings.Default.testS3Endpoint + "\"," + |
| "\"bucketName\":\"" + AgentSettings.Default.testS3Bucket + "\"," + |
| "\"httpsFlag\":false," + |
| "\"created\":\"May 19, 2013 4:17:25 PM\"}" + |
| "}," + // end of imageDataStore |
| "\"name\":\"" + testSystemVMTemplateNameNoExt + "\"}" + |
| "}," + // end of srcTO |
| "\"destTO\":" + |
| "{\"org.apache.cloudstack.storage.to.TemplateObjectTO\":" + |
| "{" + |
| "\"origUrl\":\"http://10.147.28.7/templates/5d67394c-4efd-4b62-966b-51aa53b35277.vhd.bz2\"," + |
| "\"uuid\":\"7e4ca941-cb1b-4113-ab9e-043960d0fb10\"," + |
| "\"id\":206," + |
| "\"format\":\"VHD\"," + |
| "\"accountId\":1," + |
| "\"checksum\": \"f613f38c96bf039f2e5cbf92fa8ad4f8\"," + |
| "\"hvm\":true," + |
| "\"displayText\":\"OS031\"," + |
| "\"imageDataStore\":" + getSamplePrimaryDataStoreInfo() + "," + // end of imageDataStore |
| "\"name\":\"" + testSystemVMTemplateNameNoExt + "\"}" + |
| "}," +// end of destTO |
| "\"wait\":10800}"; // end of CopyCommand |
| #endregion |
| |
| HypervResourceController rsrcServer; |
| dynamic jsonDownloadCopyCmd; |
| string dwnldDest; |
| dynamic jsonCloneCopyCmd; |
| string newVolName; |
| CopyCommandTestSetup(sampleCopyCommandToCreateVolumeFromTemplate, sampleCopyCommandForTemplateDownload, out rsrcServer, out jsonDownloadCopyCmd, out dwnldDest, out jsonCloneCopyCmd, out newVolName); |
| |
| // Act & Assert |
| DownloadTemplateToPrimaryStorage(rsrcServer, jsonDownloadCopyCmd, dwnldDest); |
| CreateVolumeFromTemplate(rsrcServer, jsonCloneCopyCmd, newVolName); |
| |
| File.Delete(dwnldDest); |
| File.Delete(newVolName); |
| } |
| |
| private static void CopyCommandTestSetup(string sampleCopyCommandToCreateVolumeFromTemplate, string sampleCopyCommandForTemplateDownload, out HypervResourceController rsrcServer, out dynamic jsonDownloadCopyCmd, out string dwnldDest, out dynamic jsonCloneCopyCmd, out string newVolName) |
| { |
| rsrcServer = new HypervResourceController(); |
| jsonDownloadCopyCmd = JsonConvert.DeserializeObject(sampleCopyCommandForTemplateDownload); |
| TemplateObjectTO dwnldTemplate = TemplateObjectTO.ParseJson(jsonDownloadCopyCmd.destTO); |
| dwnldDest = dwnldTemplate.FullFileName; |
| |
| jsonCloneCopyCmd = JsonConvert.DeserializeObject(sampleCopyCommandToCreateVolumeFromTemplate); |
| VolumeObjectTO newVol = VolumeObjectTO.ParseJson(jsonCloneCopyCmd.destTO); |
| newVol.format = dwnldTemplate.format; |
| newVolName = dwnldTemplate.FullFileName; |
| |
| if (File.Exists(dwnldDest)) |
| { |
| File.Delete(dwnldDest); |
| } |
| if (File.Exists(newVolName)) |
| { |
| File.Delete(newVolName); |
| } |
| } |
| |
| private static void CopyCommandTestSetupCifs(string sampleCopyCommandToCreateVolumeFromTemplate, string sampleCopyCommandForTemplateDownload, out HypervResourceController rsrcServer, out dynamic jsonDownloadCopyCmd, out string dwnldDest, out dynamic jsonCloneCopyCmd, out string newVolName) |
| { |
| rsrcServer = new HypervResourceController(); |
| jsonDownloadCopyCmd = JsonConvert.DeserializeObject(sampleCopyCommandForTemplateDownload); |
| TemplateObjectTO dwnldTemplate = TemplateObjectTO.ParseJson(jsonDownloadCopyCmd.destTO); |
| dwnldDest = dwnldTemplate.FullFileName; |
| |
| if (File.Exists(dwnldDest)) |
| { |
| File.Delete(dwnldDest); |
| } |
| newVolName = null; |
| jsonCloneCopyCmd = null; |
| } |
| |
| [Fact(Skip="these are functional tests")] |
| public void TestModifyStoragePoolCommand() |
| { |
| // Create dummy folder |
| String folderName = Path.Combine(".", "Dummy"); |
| if (!Directory.Exists(folderName)) |
| { |
| Directory.CreateDirectory(folderName); |
| } |
| |
| var pool = new |
| { // From java class StorageFilerTO |
| type = Enum.GetName(typeof(StoragePoolType), StoragePoolType.Filesystem), |
| host = "127.0.0.1", |
| port = -1, |
| path = folderName, |
| uuid = Guid.NewGuid().ToString(), |
| userInfo = string.Empty // Used in future to hold credential |
| }; |
| |
| var cmd = new |
| { |
| add = true, |
| pool = pool, |
| localPath = folderName |
| }; |
| JToken tok = JToken.FromObject(cmd); |
| HypervResourceController controller = new HypervResourceController(); |
| |
| // Act |
| dynamic jsonResult = controller.ModifyStoragePoolCommand(tok); |
| |
| // Assert |
| dynamic ans = jsonResult[0][CloudStackTypes.ModifyStoragePoolAnswer]; |
| Assert.True((bool)ans.result, (string)ans.details); // always succeeds |
| |
| // Clean up |
| var cmd2 = new |
| { |
| pool = pool, |
| localPath = folderName |
| }; |
| JToken tok2 = JToken.FromObject(cmd); |
| |
| // Act |
| dynamic jsonResult2 = controller.DeleteStoragePoolCommand(tok2); |
| |
| // Assert |
| dynamic ans2 = jsonResult2[0][CloudStackTypes.Answer]; |
| Assert.True((bool)ans2.result, (string)ans2.details); // always succeeds |
| } |
| |
| [Fact(Skip="these are functional tests")] |
| public void CreateStoragePoolCommand() |
| { |
| var cmd = new { localPath = "NULL" }; |
| JToken tok = JToken.FromObject(cmd); |
| HypervResourceController controller = new HypervResourceController(); |
| |
| // Act |
| dynamic jsonResult = controller.CreateStoragePoolCommand(tok); |
| |
| // Assert |
| dynamic ans = jsonResult[0][CloudStackTypes.Answer]; |
| Assert.True((bool)ans.result, (string)ans.details); // always succeeds |
| } |
| |
| [Fact(Skip="these are functional tests")] |
| public void MaintainCommand() |
| { |
| // Omit HostEnvironment object, as this is a series of settings currently not used. |
| var cmd = new { }; |
| JToken tok = JToken.FromObject(cmd); |
| HypervResourceController controller = new HypervResourceController(); |
| |
| // Act |
| dynamic jsonResult = controller.MaintainCommand(tok); |
| |
| // Assert |
| dynamic ans = jsonResult[0][CloudStackTypes.MaintainAnswer]; |
| Assert.True((bool)ans.result, (string)ans.details); // always succeeds |
| } |
| |
| [Fact(Skip="these are functional tests")] |
| public void SetupCommand() |
| { |
| // Omit HostEnvironment object, as this is a series of settings currently not used. |
| var cmd = new { multipath = false, needSetup = true }; |
| JToken tok = JToken.FromObject(cmd); |
| HypervResourceController controller = new HypervResourceController(); |
| |
| // Act |
| dynamic jsonResult = controller.SetupCommand(tok); |
| |
| // Assert |
| dynamic ans = jsonResult[0][CloudStackTypes.SetupAnswer]; |
| Assert.True((bool)ans.result, (string)ans.details); // always succeeds |
| } |
| |
| [Fact(Skip="these are functional tests")] |
| public void TestPassingUserdataToVm() |
| { |
| // Sample data |
| String key = "cloudstack-vm-userdata"; |
| String value = "username=root;password=1pass@word1"; |
| |
| // Find the VM |
| List<String> vmNames = wmiCallsV2.GetVmElementNames(); |
| |
| // Get associated WMI object |
| var vm = wmiCallsV2.GetComputerSystem(AgentSettings.Default.testKvpVmName); |
| |
| // Get existing KVP |
| var vmSettings = wmiCallsV2.GetVmSettings(vm); |
| var kvpInfo = wmiCallsV2.GetKvpSettings(vmSettings); |
| |
| // HostExchangesItems are embedded objects in the sense that the object value is stored and not a reference to the object. |
| string[] kvpProps = kvpInfo.HostExchangeItems; |
| |
| // If the value already exists, delete it |
| foreach (var item in kvpProps) |
| { |
| String wmiObjectXml = item; |
| String existingKey; |
| String existingValue; |
| ParseKVP(wmiObjectXml, out existingKey, out existingValue); |
| |
| if (existingKey == key) |
| { |
| wmiCallsV2.DeleteHostKvpItem(vm, existingKey); |
| break; |
| } |
| } |
| |
| // Add new user data |
| wmiCallsV2.AddUserData(vm, value); |
| |
| // Verify key added to subsystem |
| kvpInfo = wmiCallsV2.GetKvpSettings(vmSettings); |
| |
| // HostExchangesItems are embedded objects in the sense that the object value is stored and not a reference to the object. |
| kvpProps = kvpInfo.HostExchangeItems; |
| |
| // If the value already exists, delete it |
| bool userDataInPlace = false; |
| foreach (var item in kvpProps) |
| { |
| String wmiObjectXml = item; |
| String existingKey; |
| String existingValue; |
| ParseKVP(wmiObjectXml, out existingKey, out existingValue); |
| |
| if (existingKey == key && existingValue == value) |
| { |
| // wmiCallsV2.DeleteHostKvpItem(vm, existingKey); |
| userDataInPlace = true; |
| break; |
| } |
| } |
| |
| Assert.True(userDataInPlace, "User data key / value did no save properly"); |
| } |
| |
| private static void ParseKVP(String wmiObjectXml, out String existingKey, out String existingValue) |
| { |
| // Reference: http://blogs.msdn.com/b/virtual_pc_guy/archive/2008/12/05/enumerating-parent-kvp-data.aspx |
| |
| // Create XML parser |
| var xmlDoc = new XmlDocument(); |
| |
| // Load WMI object |
| xmlDoc.LoadXml(wmiObjectXml); |
| |
| // Use xpath to get name and value |
| var namePropXpath = "/INSTANCE/PROPERTY[@NAME='Name']/VALUE"; |
| var nameNode = xmlDoc.SelectSingleNode(namePropXpath); |
| existingKey = nameNode.InnerText; |
| var dataPropXpath = "/INSTANCE/PROPERTY[@NAME='Data']/VALUE"; |
| var dataNode = xmlDoc.SelectSingleNode(dataPropXpath); |
| existingValue = dataNode.InnerText; |
| } |
| |
| [Fact(Skip="these are functional tests")] |
| public void GetVmStatsCommandFail() |
| { |
| // Use WMI to find existing VMs |
| List<String> vmNames = new List<String>(); |
| vmNames.Add("FakeVM"); |
| |
| var cmd = new |
| { |
| hostGuid = "FAKEguid", |
| hostName = AgentSettings.Default.host, |
| vmNames = vmNames |
| }; |
| JToken tok = JToken.FromObject(cmd); |
| HypervResourceController controller = new HypervResourceController(); |
| |
| // Act |
| dynamic jsonResult = controller.GetVmStatsCommand(tok); |
| |
| // Assert |
| dynamic ans = jsonResult[0][CloudStackTypes.GetVmStatsAnswer]; |
| Assert.True((bool)ans.result, (string)ans.details); // always succeeds, fake VM means no answer for the named VM |
| } |
| |
| [Fact(Skip="these are functional tests")] |
| public void GetVmStatsCommand() |
| { |
| // Use WMI to find existing VMs |
| List<String> vmNames = wmiCallsV2.GetVmElementNames(); |
| |
| var cmd = new |
| { |
| hostGuid = "FAKEguid", |
| hostName = AgentSettings.Default.host, |
| vmNames = vmNames |
| }; |
| JToken tok = JToken.FromObject(cmd); |
| HypervResourceController controller = new HypervResourceController(); |
| |
| // Act |
| dynamic jsonResult = controller.GetVmStatsCommand(tok); |
| |
| // Assert |
| dynamic ans = jsonResult[0][CloudStackTypes.GetVmStatsAnswer]; |
| Assert.True((bool)ans.result, (string)ans.details); |
| } |
| |
| [Fact(Skip="these are functional tests")] |
| public void GetStorageStatsCommand() |
| { |
| // TODO: Update sample data to unsure it is using correct info. |
| String sample = String.Format( |
| #region string_literal |
| "{{\"" + |
| "id\":{0}," + |
| "\"localPath\":{1}," + |
| "\"pooltype\":\"Filesystem\"," + |
| "\"contextMap\":{{}}," + |
| "\"wait\":0}}", |
| JsonConvert.SerializeObject(AgentSettings.Default.testLocalStoreUUID), |
| JsonConvert.SerializeObject(AgentSettings.Default.testLocalStorePath) |
| ); |
| #endregion |
| var cmd = JsonConvert.DeserializeObject(sample); |
| JToken tok = JToken.FromObject(cmd); |
| HypervResourceController controller = new HypervResourceController(); |
| |
| // Act |
| dynamic jsonResult = controller.GetStorageStatsCommand(tok); |
| |
| // Assert |
| dynamic ans = jsonResult[0][CloudStackTypes.GetStorageStatsAnswer]; |
| Assert.True((bool)ans.result, (string)ans.details); |
| Assert.True((long)ans.used <= (long)ans.capacity); // TODO: verify that capacity is indeed capacity and not used. |
| } |
| |
| // TODO: can we speed up this command? The logic takes over a second. |
| [Fact(Skip="these are functional tests")] |
| public void GetHostStatsCommand() |
| { |
| // Arrange |
| long hostIdVal = 5; |
| HypervResourceController controller = new HypervResourceController(); |
| string sample = string.Format( |
| #region string_literal |
| "{{" + |
| "\"hostGuid\":\"B4AE5970-FCBF-4780-9F8A-2D2E04FECC34-HypervResource\"," + |
| "\"hostName\":\"CC-SVR11\"," + |
| "\"hostId\":{0}," + |
| "\"contextMap\":{{}}," + |
| "\"wait\":0}}", |
| JsonConvert.SerializeObject(hostIdVal)); |
| #endregion |
| var cmd = JsonConvert.DeserializeObject(sample); |
| JToken tok = JToken.FromObject(cmd); |
| |
| // Act |
| dynamic jsonResult = controller.GetHostStatsCommand(tok); |
| |
| // Assert |
| dynamic ans = jsonResult[0][CloudStackTypes.GetHostStatsAnswer]; |
| Assert.True((bool)ans.result); |
| Assert.True(hostIdVal == (long)ans.hostStats.hostId); |
| Assert.True(0.0 < (double)ans.hostStats.totalMemoryKBs); |
| Assert.True(0.0 < (double)ans.hostStats.freeMemoryKBs); |
| Assert.True(0.0 <= (double)ans.hostStats.networkReadKBs); |
| Assert.True(0.0 <= (double)ans.hostStats.networkWriteKBs); |
| Assert.True(0.0 <= (double)ans.hostStats.cpuUtilization); |
| Assert.True(100.0 >= (double)ans.hostStats.cpuUtilization); |
| Assert.True("host".Equals((string)ans.hostStats.entityType)); |
| Assert.True(String.IsNullOrEmpty((string)ans.details)); |
| } |
| |
| [Fact(Skip="these are functional tests")] |
| public void GetHostStatsCommandFail() |
| { |
| // Arrange |
| HypervResourceController controller = new HypervResourceController(); |
| var cmd = new { GetHostStatsCommand = new { hostId = "badvalueType" } }; |
| JToken tokFail = JToken.FromObject(cmd); |
| |
| // Act |
| dynamic jsonResult = controller.GetHostStatsCommand(tokFail); |
| |
| // Assert |
| dynamic ans = jsonResult[0][CloudStackTypes.GetHostStatsAnswer]; |
| Assert.False((bool)ans.result); |
| Assert.Null((string)ans.hostStats); |
| Assert.NotNull(ans.details); |
| } |
| |
| [Fact(Skip="these are functional tests")] |
| public void TestStartupCommand() |
| { |
| // Arrange |
| HypervResourceController controller = new HypervResourceController(); |
| String sampleStartupRoutingCommand = |
| #region string_literal |
| "[{\"" + CloudStackTypes.StartupRoutingCommand + "\":{" + |
| "\"cpus\":0," + |
| "\"speed\":0," + |
| "\"memory\":0," + |
| "\"dom0MinMemory\":0," + |
| "\"poolSync\":false," + |
| "\"vms\":{}," + |
| "\"hypervisorType\":\"Hyperv\"," + |
| "\"hostDetails\":{" + |
| "\"com.cloud.network.Networks.RouterPrivateIpStrategy\":\"HostLocal\"" + |
| "}," + |
| "\"type\":\"Routing\"," + |
| "\"dataCenter\":\"1\"," + |
| "\"pod\":\"1\"," + |
| "\"cluster\":\"1\"," + |
| "\"guid\":\"16f85622-4508-415e-b13a-49a39bb14e4d\"," + |
| "\"name\":\"localhost\"," + |
| "\"version\":\"4.2.0\"," + |
| "\"privateIpAddress\":\"1\"," + |
| "\"storageIpAddress\":\"1\"," + |
| "\"contextMap\":{}," + |
| "\"wait\":0}}]"; |
| #endregion |
| |
| uint cores; |
| uint mhz; |
| wmiCallsV2.GetProcessorResources(out cores, out mhz); |
| ulong memory_mb; |
| ulong freememory; |
| wmiCallsV2.GetMemoryResources(out memory_mb, out freememory); |
| memory_mb *= 1024; |
| long capacityBytes; |
| long availableBytes; |
| HypervResourceController.GetCapacityForLocalPath(wmiCallsV2.GetDefaultVirtualDiskFolder(), |
| out capacityBytes, out availableBytes); |
| var DefaultVirtualDiskFolder = JsonConvert.SerializeObject(wmiCallsV2.GetDefaultVirtualDiskFolder()); |
| string expected = |
| #region string_literal |
| "[{\"" + CloudStackTypes.StartupRoutingCommand + "\":{" + |
| "\"cpus\":" + cores + "," + |
| "\"speed\":" + mhz + "," + |
| "\"memory\":" + memory_mb + "," + |
| "\"dom0MinMemory\":" + (AgentSettings.Default.dom0MinMemory * 1024 * 1024) + "," + |
| "\"poolSync\":false," + |
| "\"vms\":{}," + |
| "\"hypervisorType\":\"Hyperv\"," + |
| "\"hostDetails\":{" + |
| "\"com.cloud.network.Networks.RouterPrivateIpStrategy\":\"HostLocal\"" + |
| "}," + |
| "\"type\":\"Routing\"," + |
| "\"dataCenter\":\"1\"," + |
| "\"pod\":\"1\"," + |
| "\"cluster\":\"1\"," + |
| "\"guid\":\"16f85622-4508-415e-b13a-49a39bb14e4d\"," + |
| "\"name\":\"localhost\"," + |
| "\"version\":\"4.2.0\"," + |
| "\"privateIpAddress\":\"" + AgentSettings.Default.private_ip_address + "\"," + |
| "\"storageIpAddress\":\"" + AgentSettings.Default.private_ip_address + "\"," + |
| "\"contextMap\":{}," + |
| "\"wait\":0," + |
| "\"privateNetmask\":\"" + AgentSettings.Default.private_ip_netmask + "\"," + |
| "\"privateMacAddress\":\"" + AgentSettings.Default.private_mac_address + "\"," + |
| "\"storageNetmask\":\"" + AgentSettings.Default.private_ip_netmask + "\"," + |
| "\"storageMacAddress\":\"" + AgentSettings.Default.private_mac_address + "\"," + |
| "\"gatewayIpAddress\":\"" + AgentSettings.Default.gateway_ip_address + "\"" + |
| ",\"caps\":\"hvm\"" + |
| "}}," + |
| "{\"com.cloud.agent.api.StartupStorageCommand\":{" + |
| "\"poolInfo\":{" + |
| "\"uuid\":\"16f85622-4508-415e-b13a-49a39bb14e4d\"," + |
| "\"host\":\"" + AgentSettings.Default.private_ip_address + "\"," + |
| "\"localPath\":" + DefaultVirtualDiskFolder + "," + |
| "\"hostPath\":" + DefaultVirtualDiskFolder + "," + |
| "\"poolType\":\"Filesystem\"," + |
| "\"capacityBytes\":" + capacityBytes + "," + |
| "\"availableBytes\":" + availableBytes + "," + |
| "\"details\":null" + |
| "}," + |
| "\"guid\":\"16f85622-4508-415e-b13a-49a39bb14e4d\"," + |
| "\"dataCenter\":\"1\"," + |
| "\"resourceType\":\"STORAGE_POOL\"" + |
| "}}]"; |
| #endregion |
| |
| dynamic jsonArray = JsonConvert.DeserializeObject(sampleStartupRoutingCommand); |
| |
| // Act |
| dynamic jsonResult = controller.StartupCommand(jsonArray); |
| |
| // Assert |
| string actual = JsonConvert.SerializeObject(jsonResult); |
| Assert.Equal(expected, actual); |
| } |
| |
| |
| private static string TestStartCommand() |
| { |
| // Arrange |
| HypervResourceController rsrcServer = new HypervResourceController(); |
| String sample = getSampleStartCommand(); |
| |
| |
| dynamic jsonStartCmd = JsonConvert.DeserializeObject(sample); |
| |
| // Act |
| dynamic startAns = rsrcServer.StartCommand(jsonStartCmd); |
| |
| // Assert |
| Assert.NotNull(startAns[0][CloudStackTypes.StartAnswer]); |
| Assert.True((bool)startAns[0][CloudStackTypes.StartAnswer].result, "StartCommand did not succeed " + startAns[0][CloudStackTypes.StartAnswer].details); |
| string vmCmdName = jsonStartCmd.vm.name.Value; |
| var vm = wmiCallsV2.GetComputerSystem(vmCmdName); |
| var vmSettings = wmiCallsV2.GetVmSettings(vm); |
| var memSettings = wmiCallsV2.GetMemSettings(vmSettings); |
| var procSettings = wmiCallsV2.GetProcSettings(vmSettings); |
| dynamic jsonObj = JsonConvert.DeserializeObject(sample); |
| var vmInfo = jsonObj.vm; |
| string vmName = vmInfo.name; |
| var nicInfo = vmInfo.nics; |
| int vcpus = vmInfo.cpus; |
| int memSize = vmInfo.maxRam / 1048576; |
| Assert.True((long)memSettings.VirtualQuantity == memSize); |
| Assert.True((long)memSettings.Reservation == memSize); |
| Assert.True((long)memSettings.Limit == memSize); |
| Assert.True((int)procSettings.VirtualQuantity == vcpus); |
| Assert.True((int)procSettings.Reservation == vcpus); |
| Assert.True((int)procSettings.Limit == 100000); |
| |
| // examine NIC for correctness |
| var nicSettingsViaVm = wmiCallsV2.GetEthernetPortSettings(vm); |
| Assert.True(nicSettingsViaVm.Length > 0, "Should be at least one ethernet port on VM"); |
| string expectedMac = (string)jsonStartCmd.vm.nics[0].mac; |
| string strippedExpectedMac = expectedMac.Replace(":", string.Empty); |
| Assert.Equal(nicSettingsViaVm[0].Address.ToLower(), strippedExpectedMac.ToLower()); |
| |
| // Assert switchport has correct VLAN |
| var ethernetConnections = wmiCallsV2.GetEthernetConnections(vm); |
| var vlanSettings = wmiCallsV2.GetVlanSettings(ethernetConnections[0]); |
| string isolationUri = (string)jsonStartCmd.vm.nics[0].isolationUri; |
| string vlan = isolationUri.Replace("vlan://", string.Empty); |
| Assert.Equal(vlanSettings.AccessVlanId.ToString(), vlan); |
| |
| return vmName; |
| } |
| |
| private static void TestStopCommand(string vmName) |
| { |
| // Arrange |
| HypervResourceController rsrcServer = new HypervResourceController(); |
| String sampleStop = "{\"isProxy\":false,\"vmName\":\"i-2-17-VM\",\"contextMap\":{},\"wait\":0}"; |
| dynamic jsonStopCmd = JsonConvert.DeserializeObject(sampleStop); |
| |
| // Act |
| dynamic stopAns = rsrcServer.StopCommand(jsonStopCmd); |
| |
| // Assert VM is gone! |
| Assert.NotNull(stopAns[0][CloudStackTypes.StopAnswer]); |
| Assert.True((bool)stopAns[0][CloudStackTypes.StopAnswer].result, "StopCommand did not succeed " + stopAns[0][CloudStackTypes.StopAnswer].details); |
| var finalVm = wmiCallsV2.GetComputerSystem(vmName); |
| Assert.True(wmiCallsV2.GetComputerSystem(vmName) == null); |
| } |
| } |
| } |