diff --git a/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/HypervResourceController.cs b/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/HypervResourceController.cs index 37f5f5304b7..0ad95b8704a 100644 --- a/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/HypervResourceController.cs +++ b/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/HypervResourceController.cs @@ -1,112 +1,112 @@ -// 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 Amazon; -using Amazon.S3; -using Amazon.S3.Model; -using log4net; -using Microsoft.CSharp.RuntimeBinder; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; -using System; -using System.Collections; -using System.Collections.Specialized; -using System.Collections.Generic; -using System.Configuration; -using System.IO; -using System.Linq; -using System.Net; -using System.Net.Http; -using System.Text; -using System.Security.Cryptography; -using System.Security.Principal; -using System.Web.Http; -using CloudStack.Plugin.WmiWrappers.ROOT.VIRTUALIZATION.V2; - -namespace HypervResource -{ - - public struct HypervResourceControllerConfig - { - private string privateIpAddress; - private static ILog logger = LogManager.GetLogger(typeof(HypervResourceControllerConfig)); - - public string PrivateIpAddress - { - get - { - return privateIpAddress; - } - set - { - ValidateIpAddress(value); - privateIpAddress = value; - System.Net.NetworkInformation.NetworkInterface nic = HypervResourceController.GetNicInfoFromIpAddress(privateIpAddress, out PrivateNetmask); - PrivateMacAddress = nic.GetPhysicalAddress().ToString(); - } - } - - private static void ValidateIpAddress(string value) - { - // Convert to IP address - IPAddress ipAddress; - if (!IPAddress.TryParse(value, out ipAddress)) - { - String errMsg = "Invalid PrivateIpAddress: " + value; - logger.Error(errMsg); - throw new ArgumentException(errMsg); - } - } - public string GatewayIpAddress; - public string PrivateMacAddress; - public string PrivateNetmask; - public string StorageNetmask; - public string StorageMacAddress; - public string StorageIpAddress; - public long RootDeviceReservedSpaceBytes; - public string RootDeviceName; - public ulong ParentPartitionMinMemoryMb; - public string LocalSecondaryStoragePath; - public string systemVmIso; - - private string getPrimaryKey(string id) - { - return "primary_storage_" + id; - } - - public string getPrimaryStorage(string id) - { - NameValueCollection settings = ConfigurationManager.AppSettings; - return settings.Get(getPrimaryKey(id)); - } - - public void setPrimaryStorage(string id, string path) - { - Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None); - KeyValueConfigurationCollection settings = config.AppSettings.Settings; - string key = getPrimaryKey(id); - if (settings[key] != null) - { - settings.Remove(key); - } - settings.Add(key, path); - config.Save(ConfigurationSaveMode.Modified); - ConfigurationManager.RefreshSection("appSettings"); - } +// 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 Amazon; +using Amazon.S3; +using Amazon.S3.Model; +using log4net; +using Microsoft.CSharp.RuntimeBinder; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using System; +using System.Collections; +using System.Collections.Specialized; +using System.Collections.Generic; +using System.Configuration; +using System.IO; +using System.Linq; +using System.Net; +using System.Net.Http; +using System.Text; +using System.Security.Cryptography; +using System.Security.Principal; +using System.Web.Http; +using CloudStack.Plugin.WmiWrappers.ROOT.VIRTUALIZATION.V2; + +namespace HypervResource +{ + + public struct HypervResourceControllerConfig + { + private string privateIpAddress; + private static ILog logger = LogManager.GetLogger(typeof(HypervResourceControllerConfig)); + + public string PrivateIpAddress + { + get + { + return privateIpAddress; + } + set + { + ValidateIpAddress(value); + privateIpAddress = value; + System.Net.NetworkInformation.NetworkInterface nic = HypervResourceController.GetNicInfoFromIpAddress(privateIpAddress, out PrivateNetmask); + PrivateMacAddress = nic.GetPhysicalAddress().ToString(); + } + } + + private static void ValidateIpAddress(string value) + { + // Convert to IP address + IPAddress ipAddress; + if (!IPAddress.TryParse(value, out ipAddress)) + { + String errMsg = "Invalid PrivateIpAddress: " + value; + logger.Error(errMsg); + throw new ArgumentException(errMsg); + } + } + public string GatewayIpAddress; + public string PrivateMacAddress; + public string PrivateNetmask; + public string StorageNetmask; + public string StorageMacAddress; + public string StorageIpAddress; + public long RootDeviceReservedSpaceBytes; + public string RootDeviceName; + public ulong ParentPartitionMinMemoryMb; + public string LocalSecondaryStoragePath; + public string systemVmIso; + + private string getPrimaryKey(string id) + { + return "primary_storage_" + id; + } + + public string getPrimaryStorage(string id) + { + NameValueCollection settings = ConfigurationManager.AppSettings; + return settings.Get(getPrimaryKey(id)); + } + + public void setPrimaryStorage(string id, string path) + { + Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None); + KeyValueConfigurationCollection settings = config.AppSettings.Settings; + string key = getPrimaryKey(id); + if (settings[key] != null) + { + settings.Remove(key); + } + settings.Add(key, path); + config.Save(ConfigurationSaveMode.Modified); + ConfigurationManager.RefreshSection("appSettings"); + } public List getAllPrimaryStorages() { @@ -122,671 +122,671 @@ namespace HypervResource } return poolPaths; } - } - - /// - /// Supports one HTTP GET and multiple HTTP POST URIs - /// - /// - /// - /// POST takes dynamic to allow it to receive JSON without concern for what is the underlying object. - /// E.g. http://stackoverflow.com/questions/14071715/passing-dynamic-json-object-to-web-api-newtonsoft-example - /// and http://stackoverflow.com/questions/3142495/deserialize-json-into-c-sharp-dynamic-object - /// Use ActionName attribute to allow multiple POST URLs, one for each supported command - /// E.g. http://stackoverflow.com/a/12703423/939250 - /// Strictly speaking, this goes against the purpose of an ApiController, which is to provide one GET/POST/PUT/DELETE, etc. - /// However, it reduces the amount of code by removing the need for a switch according to the incoming command type. - /// http://weblogs.asp.net/fredriknormen/archive/2012/06/11/asp-net-web-api-exception-handling.aspx - /// - /// - /// Exceptions handled on command by command basis rather than globally to allow details of the command - /// to be reflected in the response. Default error handling is in the catch for Exception, but - /// other exception types may be caught where the feedback would be different. - /// NB: global alternatives discussed at - /// http://weblogs.asp.net/fredriknormen/archive/2012/06/11/asp-net-web-api-exception-handling.aspx - /// - /// - public class HypervResourceController : ApiController - { - public static void Configure(HypervResourceControllerConfig config) - { - HypervResourceController.config = config; - wmiCallsV2 = new WmiCallsV2(); - } - - public static HypervResourceControllerConfig config = new HypervResourceControllerConfig(); - - private static ILog logger = LogManager.GetLogger(typeof(HypervResourceController)); - private string systemVmIso = ""; - Dictionary contextMap = new Dictionary(); - - public static void Initialize() - { - } - - public static IWmiCallsV2 wmiCallsV2 { get; set;} - - // GET api/HypervResource - public string Get() - { - using (log4net.NDC.Push(Guid.NewGuid().ToString())) - { - return "HypervResource controller running, use POST to send JSON encoded RPCs"; ; - } - } - - /// - /// NOP - placeholder for future setup, e.g. delete existing VMs or Network ports - /// POST api/HypervResource/SetupCommand - /// - /// - /// - /// TODO: produce test - [HttpPost] - [ActionName(CloudStackTypes.SetupCommand)] - public JContainer SetupCommand([FromBody]dynamic cmd) - { - using (log4net.NDC.Push(Guid.NewGuid().ToString())) - { + } + + /// + /// Supports one HTTP GET and multiple HTTP POST URIs + /// + /// + /// + /// POST takes dynamic to allow it to receive JSON without concern for what is the underlying object. + /// E.g. http://stackoverflow.com/questions/14071715/passing-dynamic-json-object-to-web-api-newtonsoft-example + /// and http://stackoverflow.com/questions/3142495/deserialize-json-into-c-sharp-dynamic-object + /// Use ActionName attribute to allow multiple POST URLs, one for each supported command + /// E.g. http://stackoverflow.com/a/12703423/939250 + /// Strictly speaking, this goes against the purpose of an ApiController, which is to provide one GET/POST/PUT/DELETE, etc. + /// However, it reduces the amount of code by removing the need for a switch according to the incoming command type. + /// http://weblogs.asp.net/fredriknormen/archive/2012/06/11/asp-net-web-api-exception-handling.aspx + /// + /// + /// Exceptions handled on command by command basis rather than globally to allow details of the command + /// to be reflected in the response. Default error handling is in the catch for Exception, but + /// other exception types may be caught where the feedback would be different. + /// NB: global alternatives discussed at + /// http://weblogs.asp.net/fredriknormen/archive/2012/06/11/asp-net-web-api-exception-handling.aspx + /// + /// + public class HypervResourceController : ApiController + { + public static void Configure(HypervResourceControllerConfig config) + { + HypervResourceController.config = config; + wmiCallsV2 = new WmiCallsV2(); + } + + public static HypervResourceControllerConfig config = new HypervResourceControllerConfig(); + + private static ILog logger = LogManager.GetLogger(typeof(HypervResourceController)); + private string systemVmIso = ""; + Dictionary contextMap = new Dictionary(); + + public static void Initialize() + { + } + + public static IWmiCallsV2 wmiCallsV2 { get; set;} + + // GET api/HypervResource + public string Get() + { + using (log4net.NDC.Push(Guid.NewGuid().ToString())) + { + return "HypervResource controller running, use POST to send JSON encoded RPCs"; ; + } + } + + /// + /// NOP - placeholder for future setup, e.g. delete existing VMs or Network ports + /// POST api/HypervResource/SetupCommand + /// + /// + /// + /// TODO: produce test + [HttpPost] + [ActionName(CloudStackTypes.SetupCommand)] + public JContainer SetupCommand([FromBody]dynamic cmd) + { + using (log4net.NDC.Push(Guid.NewGuid().ToString())) + { logger.Info(CloudStackTypes.SetupCommand + Utils.CleanString(cmd.ToString())); - - string details = null; - bool result = false; - - try - { - result = true; - } - catch (Exception sysEx) - { - details = CloudStackTypes.SetupCommand + " failed due to " + sysEx.Message; - logger.Error(details, sysEx); - } - - object ansContent = new - { - result = result, - details = "success - NOP", - _reconnect = false, - contextMap = contextMap - }; - - return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.SetupAnswer); - } - } - - // POST api/HypervResource/AttachCommand - [HttpPost] - [ActionName(CloudStackTypes.AttachCommand)] - public JContainer AttachCommand([FromBody]dynamic cmd) - { - using (log4net.NDC.Push(Guid.NewGuid().ToString())) - { - logger.Info(CloudStackTypes.AttachCommand + Utils.CleanString(cmd.ToString())); - - string details = null; - bool result = false; - - try - { - string vmName = (string)cmd.vmName; - DiskTO disk = DiskTO.ParseJson(cmd.disk); - - if (disk.type.Equals("ISO")) - { - TemplateObjectTO dataStore = disk.templateObjectTO; - NFSTO share = dataStore.nfsDataStoreTO; - Utils.ConnectToRemote(share.UncPath, share.Domain, share.User, share.Password); - string diskPath = Utils.NormalizePath(Path.Combine(share.UncPath, dataStore.path)); - wmiCallsV2.AttachIso(vmName, diskPath); - result = true; - } - else if (disk.type.Equals("DATADISK")) - { - VolumeObjectTO volume = disk.volumeObjectTO; - PrimaryDataStoreTO primary = volume.primaryDataStore; - if (!primary.isLocal) - { - Utils.ConnectToRemote(primary.UncPath, primary.Domain, primary.User, primary.Password); - } - string diskPath = Utils.NormalizePath(volume.FullFileName); - wmiCallsV2.AttachDisk(vmName, diskPath, disk.diskSequence); - result = true; - } - else - { - details = "Invalid disk type to be attached to vm " + vmName; - } - } - catch (Exception sysEx) - { - details = CloudStackTypes.AttachCommand + " failed due to " + sysEx.Message; - logger.Error(details, sysEx); - } - - object ansContent = new - { - result = result, - details = details, - disk = cmd.disk, - contextMap = contextMap - }; - - return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.AttachAnswer); - } - } - - // POST api/HypervResource/DetachCommand - [HttpPost] - [ActionName(CloudStackTypes.DettachCommand)] - public JContainer DetachCommand([FromBody]dynamic cmd) - { - using (log4net.NDC.Push(Guid.NewGuid().ToString())) - { - logger.Info(CloudStackTypes.DettachCommand + Utils.CleanString(cmd.ToString())); - - string details = null; - bool result = false; - - try - { - string vmName = (string)cmd.vmName; - DiskTO disk = DiskTO.ParseJson(cmd.disk); - - if (disk.type.Equals("ISO")) - { - TemplateObjectTO dataStore = disk.templateObjectTO; - NFSTO share = dataStore.nfsDataStoreTO; - string diskPath = Utils.NormalizePath(Path.Combine(share.UncPath, dataStore.path)); - wmiCallsV2.DetachDisk(vmName, diskPath); - result = true; - } - else if (disk.type.Equals("DATADISK")) - { - VolumeObjectTO volume = disk.volumeObjectTO; - string diskPath = Utils.NormalizePath(volume.FullFileName); - wmiCallsV2.DetachDisk(vmName, diskPath); - result = true; - } - else - { - details = "Invalid disk type to be dettached from vm " + vmName; - } - } - catch (Exception sysEx) - { - details = CloudStackTypes.DettachCommand + " failed due to " + sysEx.Message; - logger.Error(details, sysEx); - } - - object ansContent = new - { - result = result, - details = details, - contextMap = contextMap - }; - - return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.DettachAnswer); - } - } - - // POST api/HypervResource/RebootCommand - [HttpPost] - [ActionName(CloudStackTypes.RebootCommand)] - public JContainer RebootCommand([FromBody]dynamic cmd) - { - using (log4net.NDC.Push(Guid.NewGuid().ToString())) - { + + string details = null; + bool result = false; + + try + { + result = true; + } + catch (Exception sysEx) + { + details = CloudStackTypes.SetupCommand + " failed due to " + sysEx.Message; + logger.Error(details, sysEx); + } + + object ansContent = new + { + result = result, + details = "success - NOP", + _reconnect = false, + contextMap = contextMap + }; + + return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.SetupAnswer); + } + } + + // POST api/HypervResource/AttachCommand + [HttpPost] + [ActionName(CloudStackTypes.AttachCommand)] + public JContainer AttachCommand([FromBody]dynamic cmd) + { + using (log4net.NDC.Push(Guid.NewGuid().ToString())) + { + logger.Info(CloudStackTypes.AttachCommand + Utils.CleanString(cmd.ToString())); + + string details = null; + bool result = false; + + try + { + string vmName = (string)cmd.vmName; + DiskTO disk = DiskTO.ParseJson(cmd.disk); + + if (disk.type.Equals("ISO")) + { + TemplateObjectTO dataStore = disk.templateObjectTO; + NFSTO share = dataStore.nfsDataStoreTO; + Utils.ConnectToRemote(share.UncPath, share.Domain, share.User, share.Password); + string diskPath = Utils.NormalizePath(Path.Combine(share.UncPath, dataStore.path)); + wmiCallsV2.AttachIso(vmName, diskPath); + result = true; + } + else if (disk.type.Equals("DATADISK")) + { + VolumeObjectTO volume = disk.volumeObjectTO; + PrimaryDataStoreTO primary = volume.primaryDataStore; + if (!primary.isLocal) + { + Utils.ConnectToRemote(primary.UncPath, primary.Domain, primary.User, primary.Password); + } + string diskPath = Utils.NormalizePath(volume.FullFileName); + wmiCallsV2.AttachDisk(vmName, diskPath, disk.diskSequence); + result = true; + } + else + { + details = "Invalid disk type to be attached to vm " + vmName; + } + } + catch (Exception sysEx) + { + details = CloudStackTypes.AttachCommand + " failed due to " + sysEx.Message; + logger.Error(details, sysEx); + } + + object ansContent = new + { + result = result, + details = details, + disk = cmd.disk, + contextMap = contextMap + }; + + return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.AttachAnswer); + } + } + + // POST api/HypervResource/DetachCommand + [HttpPost] + [ActionName(CloudStackTypes.DettachCommand)] + public JContainer DetachCommand([FromBody]dynamic cmd) + { + using (log4net.NDC.Push(Guid.NewGuid().ToString())) + { + logger.Info(CloudStackTypes.DettachCommand + Utils.CleanString(cmd.ToString())); + + string details = null; + bool result = false; + + try + { + string vmName = (string)cmd.vmName; + DiskTO disk = DiskTO.ParseJson(cmd.disk); + + if (disk.type.Equals("ISO")) + { + TemplateObjectTO dataStore = disk.templateObjectTO; + NFSTO share = dataStore.nfsDataStoreTO; + string diskPath = Utils.NormalizePath(Path.Combine(share.UncPath, dataStore.path)); + wmiCallsV2.DetachDisk(vmName, diskPath); + result = true; + } + else if (disk.type.Equals("DATADISK")) + { + VolumeObjectTO volume = disk.volumeObjectTO; + string diskPath = Utils.NormalizePath(volume.FullFileName); + wmiCallsV2.DetachDisk(vmName, diskPath); + result = true; + } + else + { + details = "Invalid disk type to be dettached from vm " + vmName; + } + } + catch (Exception sysEx) + { + details = CloudStackTypes.DettachCommand + " failed due to " + sysEx.Message; + logger.Error(details, sysEx); + } + + object ansContent = new + { + result = result, + details = details, + contextMap = contextMap + }; + + return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.DettachAnswer); + } + } + + // POST api/HypervResource/RebootCommand + [HttpPost] + [ActionName(CloudStackTypes.RebootCommand)] + public JContainer RebootCommand([FromBody]dynamic cmd) + { + using (log4net.NDC.Push(Guid.NewGuid().ToString())) + { logger.Info(CloudStackTypes.RebootCommand + Utils.CleanString(cmd.ToString())); - - string details = null; - bool result = false; - - try - { - string vmName = (string)cmd.vmName; - var sys = wmiCallsV2.GetComputerSystem(vmName); - if (sys == null) - { - details = CloudStackTypes.RebootCommand + " requested unknown VM " + vmName; - logger.Error(details); - } - else - { - wmiCallsV2.SetState(sys, RequiredState.Reset); - result = true; - } - } - catch (Exception sysEx) - { - details = CloudStackTypes.RebootCommand + " failed due to " + sysEx.Message; - logger.Error(details, sysEx); - } - - object ansContent = new - { - result = result, - details = details, - contextMap = contextMap - }; - - return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.RebootAnswer); - } - } - - // POST api/HypervResource/DestroyCommand - [HttpPost] - [ActionName(CloudStackTypes.DestroyCommand)] - public JContainer DestroyCommand([FromBody]dynamic cmd) - { - using (log4net.NDC.Push(Guid.NewGuid().ToString())) - { + + string details = null; + bool result = false; + + try + { + string vmName = (string)cmd.vmName; + var sys = wmiCallsV2.GetComputerSystem(vmName); + if (sys == null) + { + details = CloudStackTypes.RebootCommand + " requested unknown VM " + vmName; + logger.Error(details); + } + else + { + wmiCallsV2.SetState(sys, RequiredState.Reset); + result = true; + } + } + catch (Exception sysEx) + { + details = CloudStackTypes.RebootCommand + " failed due to " + sysEx.Message; + logger.Error(details, sysEx); + } + + object ansContent = new + { + result = result, + details = details, + contextMap = contextMap + }; + + return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.RebootAnswer); + } + } + + // POST api/HypervResource/DestroyCommand + [HttpPost] + [ActionName(CloudStackTypes.DestroyCommand)] + public JContainer DestroyCommand([FromBody]dynamic cmd) + { + using (log4net.NDC.Push(Guid.NewGuid().ToString())) + { logger.Info(CloudStackTypes.DestroyCommand + Utils.CleanString(cmd.ToString())); - - string details = null; - bool result = false; - - try - { - // Assert + + string details = null; + bool result = false; + + try + { + // Assert String errMsg = "No 'volume' details in " + CloudStackTypes.DestroyCommand + " " + Utils.CleanString(cmd.ToString()); - if (cmd.volume == null) - { - logger.Error(errMsg); - throw new ArgumentException(errMsg); - } - - // Assert - errMsg = "No valide path in DestroyCommand in " + CloudStackTypes.DestroyCommand + " " + (String)cmd.ToString(); - if (cmd.volume.path == null) - { - logger.Error(errMsg); - throw new ArgumentException(errMsg); - } - - String path = (string)cmd.volume.path; - if (!File.Exists(path)) - { - logger.Info(CloudStackTypes.DestroyCommand + ", but volume at pass already deleted " + path); - } - - string vmName = (string)cmd.vmName; - if (!string.IsNullOrEmpty(vmName) && File.Exists(path)) - { - // Make sure that this resource is removed from the VM - wmiCallsV2.DetachDisk(vmName, path); - } - - File.Delete(path); - result = true; - } - catch (Exception sysEx) - { - details = CloudStackTypes.DestroyCommand + " failed due to " + sysEx.Message; - logger.Error(details, sysEx); - } - - object ansContent = new - { - result = result, - details = details, - contextMap = contextMap - }; - - return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.Answer); - } - } - - // POST api/HypervResource/DeleteCommand - [HttpPost] - [ActionName(CloudStackTypes.DeleteCommand)] - public JContainer DeleteCommand([FromBody]dynamic cmd) - { - using (log4net.NDC.Push(Guid.NewGuid().ToString())) - { + if (cmd.volume == null) + { + logger.Error(errMsg); + throw new ArgumentException(errMsg); + } + + // Assert + errMsg = "No valide path in DestroyCommand in " + CloudStackTypes.DestroyCommand + " " + (String)cmd.ToString(); + if (cmd.volume.path == null) + { + logger.Error(errMsg); + throw new ArgumentException(errMsg); + } + + String path = (string)cmd.volume.path; + if (!File.Exists(path)) + { + logger.Info(CloudStackTypes.DestroyCommand + ", but volume at pass already deleted " + path); + } + + string vmName = (string)cmd.vmName; + if (!string.IsNullOrEmpty(vmName) && File.Exists(path)) + { + // Make sure that this resource is removed from the VM + wmiCallsV2.DetachDisk(vmName, path); + } + + File.Delete(path); + result = true; + } + catch (Exception sysEx) + { + details = CloudStackTypes.DestroyCommand + " failed due to " + sysEx.Message; + logger.Error(details, sysEx); + } + + object ansContent = new + { + result = result, + details = details, + contextMap = contextMap + }; + + return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.Answer); + } + } + + // POST api/HypervResource/DeleteCommand + [HttpPost] + [ActionName(CloudStackTypes.DeleteCommand)] + public JContainer DeleteCommand([FromBody]dynamic cmd) + { + using (log4net.NDC.Push(Guid.NewGuid().ToString())) + { logger.Info(CloudStackTypes.DestroyCommand + Utils.CleanString(cmd.ToString())); - - string details = null; - bool result = false; - - try - { - // Assert + + string details = null; + bool result = false; + + try + { + // Assert String errMsg = "No 'volume' details in " + CloudStackTypes.DestroyCommand + " " + Utils.CleanString(cmd.ToString()); - VolumeObjectTO destVolumeObjectTO = VolumeObjectTO.ParseJson(cmd.data); - - if (destVolumeObjectTO.name == null) - { - logger.Error(errMsg); - throw new ArgumentException(errMsg); - } - - String path = destVolumeObjectTO.FullFileName; - if (!File.Exists(path)) - { - logger.Info(CloudStackTypes.DestroyCommand + ", but volume at pass already deleted " + path); - } - - string vmName = (string)cmd.vmName; - if (!string.IsNullOrEmpty(vmName) && File.Exists(path)) - { - // Make sure that this resource is removed from the VM - wmiCallsV2.DetachDisk(vmName, path); - } - - File.Delete(path); - result = true; - } - catch (Exception sysEx) - { - details = CloudStackTypes.DestroyCommand + " failed due to " + sysEx.Message; - logger.Error(details, sysEx); - } - - object ansContent = new - { - result = result, - details = details, - contextMap = contextMap - }; - - return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.Answer); - } - } - - - private static JArray ReturnCloudStackTypedJArray(object ansContent, string ansType) - { - JObject ansObj = Utils.CreateCloudStackObject(ansType, ansContent); - JArray answer = new JArray(ansObj); - logger.Info(Utils.CleanString(ansObj.ToString())); - return answer; - } - - // POST api/HypervResource/CreateCommand - [HttpPost] - [ActionName(CloudStackTypes.CreateCommand)] - public JContainer CreateCommand([FromBody]dynamic cmd) - { - using (log4net.NDC.Push(Guid.NewGuid().ToString())) - { - logger.Info(CloudStackTypes.CreateCommand + Utils.CleanString(cmd.ToString())); - - string details = null; - bool result = false; - VolumeInfo volume = new VolumeInfo(); - - try - { - string diskType = cmd.diskCharacteristics.type; - ulong disksize = cmd.diskCharacteristics.size; - string templateUri = cmd.templateUrl; - - // assert: valid storagepool? - string poolTypeStr = cmd.pool.type; - string poolLocalPath = cmd.pool.path; - string poolUuid = cmd.pool.uuid; - string newVolPath = null; - long volId = cmd.volId; - string newVolName = null; - - if (ValidStoragePool(poolTypeStr, poolLocalPath, poolUuid, ref details)) - { - // No template URI? Its a blank disk. - if (string.IsNullOrEmpty(templateUri)) - { - // assert - VolumeType volType; - if (!Enum.TryParse(diskType, out volType) && volType != VolumeType.DATADISK) - { - details = "Cannot create volumes of type " + (string.IsNullOrEmpty(diskType) ? "NULL" : diskType); - } - else - { - newVolName = cmd.diskCharacteristics.name; - newVolPath = Path.Combine(poolLocalPath, newVolName, diskType.ToLower()); - // TODO: make volume format and block size configurable - wmiCallsV2.CreateDynamicVirtualHardDisk(disksize, newVolPath); - if (File.Exists(newVolPath)) - { - result = true; - } - else - { - details = "Failed to create DATADISK with name " + newVolName; - } - } - } - else - { - // TODO: Does this always work, or do I need to download template at times? - if (templateUri.Contains("/") || templateUri.Contains("\\")) - { - details = "Problem with templateURL " + templateUri + - " the URL should be volume UUID in primary storage created by previous PrimaryStorageDownloadCommand"; - logger.Error(details); - } - else - { - logger.Debug("Template's name in primary store should be " + templateUri); - // HypervPhysicalDisk BaseVol = primaryPool.getPhysicalDisk(tmplturl); - FileInfo srcFileInfo = new FileInfo(templateUri); - newVolName = Guid.NewGuid() + srcFileInfo.Extension; - newVolPath = Path.Combine(poolLocalPath, newVolName); - logger.Debug("New volume will be at " + newVolPath); - string oldVolPath = Path.Combine(poolLocalPath, templateUri); - File.Copy(oldVolPath, newVolPath); - if (File.Exists(newVolPath)) - { - result = true; - } - else - { - details = "Failed to create DATADISK with name " + newVolName; - } - } - volume = new VolumeInfo( - volId, diskType, - poolTypeStr, poolUuid, newVolName, - newVolPath, newVolPath, (long)disksize, null); - } - } - } - catch (Exception sysEx) - { - // TODO: consider this as model for error processing in all commands - details = CloudStackTypes.CreateCommand + " failed due to " + sysEx.Message; - logger.Error(details, sysEx); - } - - object ansContent = new - { - result = result, - details = details, - volume = volume, - contextMap = contextMap - }; - return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.CreateAnswer); - } - } - - // POST api/HypervResource/PrimaryStorageDownloadCommand - [HttpPost] - [ActionName(CloudStackTypes.PrimaryStorageDownloadCommand)] - public JContainer PrimaryStorageDownloadCommand([FromBody]dynamic cmd) - { - using (log4net.NDC.Push(Guid.NewGuid().ToString())) - { - logger.Info(CloudStackTypes.PrimaryStorageDownloadCommand + Utils.CleanString(cmd.ToString())); - string details = null; - bool result = false; - long size = 0; - string newCopyFileName = null; - - string poolLocalPath = cmd.localPath; - if (!Directory.Exists(poolLocalPath)) - { - details = "None existent local path " + poolLocalPath; - } - else - { - // Compose name for downloaded file. - string sourceUrl = cmd.url; - if (sourceUrl.ToLower().EndsWith(".vhd")) - { - newCopyFileName = Guid.NewGuid() + ".vhd"; - } - if (sourceUrl.ToLower().EndsWith(".vhdx")) - { - newCopyFileName = Guid.NewGuid() + ".vhdx"; - } - - // assert - if (newCopyFileName == null) - { - details = CloudStackTypes.PrimaryStorageDownloadCommand + " Invalid file extension for hypervisor type in source URL " + sourceUrl; - logger.Error(details); - } - else - { - try - { - FileInfo newFile; - if (CopyURI(sourceUrl, newCopyFileName, poolLocalPath, out newFile, ref details)) - { - size = newFile.Length; - result = true; - } - } - catch (System.Exception ex) - { - details = CloudStackTypes.PrimaryStorageDownloadCommand + " Cannot download source URL " + sourceUrl + " due to " + ex.Message; - logger.Error(details, ex); - } - } - } - - object ansContent = new - { - result = result, - details = details, - templateSize = size, - installPath = newCopyFileName, - contextMap = contextMap - }; - return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.PrimaryStorageDownloadAnswer); - } - } - - private static bool ValidStoragePool(string poolTypeStr, string poolLocalPath, string poolUuid, ref string details) - { - StoragePoolType poolType; - if (!Enum.TryParse(poolTypeStr, out poolType) || poolType != StoragePoolType.Filesystem) - { - details = "Primary storage pool " + poolUuid + " type " + poolType + " local path " + poolLocalPath + " has invalid StoragePoolType"; - logger.Error(details); - return false; - } - else if (!Directory.Exists(poolLocalPath)) - { - details = "Primary storage pool " + poolUuid + " type " + poolType + " local path " + poolLocalPath + " has invalid local path"; - logger.Error(details); - return false; - } - return true; - } - - /// - /// Exceptions to watch out for: - /// Exceptions related to URI creation - /// System.SystemException - /// +-System.ArgumentNullException - /// +-System.FormatException - /// +-System.UriFormatException - /// - /// Exceptions related to NFS URIs - /// System.SystemException - /// +-System.NotSupportedException - /// +-System.ArgumentException - /// +-System.ArgumentNullException - /// +-System.Security.SecurityException; - /// +-System.UnauthorizedAccessException - /// +-System.IO.IOException - /// +-System.IO.PathTooLongException - /// - /// Exceptions related to HTTP URIs - /// System.SystemException - /// +-System.InvalidOperationException - /// +-System.Net.WebException - /// +-System.NotSupportedException - /// +-System.ArgumentNullException - /// - /// - /// - /// - /// - private bool CopyURI(string sourceUri, string newCopyFileName, string poolLocalPath, out FileInfo newFile, ref string details) - { - Uri source = new Uri(sourceUri); - String destFilePath = Path.Combine(poolLocalPath, newCopyFileName); - string[] pathSegments = source.Segments; - String templateUUIDandExtension = pathSegments[pathSegments.Length - 1]; - newFile = new FileInfo(destFilePath); - - // NFS URI assumed to already be mounted locally. Mount location given by settings. - if (source.Scheme.ToLower().Equals("nfs")) - { - String srcDiskPath = Path.Combine(HypervResourceController.config.LocalSecondaryStoragePath, templateUUIDandExtension); - String taskMsg = "Copy NFS url in " + sourceUri + " at " + srcDiskPath + " to pool " + poolLocalPath; - logger.Debug(taskMsg); - File.Copy(srcDiskPath, destFilePath); - } - else if (source.Scheme.ToLower().Equals("http") || source.Scheme.ToLower().Equals("https")) - { - System.Net.WebClient webclient = new WebClient(); - webclient.DownloadFile(source, destFilePath); - } - else - { - details = "Unsupported URI scheme " + source.Scheme.ToLower() + " in source URI " + sourceUri; - logger.Error(details); - return false; - } - - if (!File.Exists(destFilePath)) - { - details = "Filed to copy " + sourceUri + " to primary pool destination " + destFilePath; - logger.Error(details); - return false; - } - return true; - } - - // POST api/HypervResource/CheckHealthCommand - [HttpPost] - [ActionName(CloudStackTypes.CheckHealthCommand)] - public JContainer CheckHealthCommand([FromBody]dynamic cmd) - { - using (log4net.NDC.Push(Guid.NewGuid().ToString())) - { + VolumeObjectTO destVolumeObjectTO = VolumeObjectTO.ParseJson(cmd.data); + + if (destVolumeObjectTO.name == null) + { + logger.Error(errMsg); + throw new ArgumentException(errMsg); + } + + String path = destVolumeObjectTO.FullFileName; + if (!File.Exists(path)) + { + logger.Info(CloudStackTypes.DestroyCommand + ", but volume at pass already deleted " + path); + } + + string vmName = (string)cmd.vmName; + if (!string.IsNullOrEmpty(vmName) && File.Exists(path)) + { + // Make sure that this resource is removed from the VM + wmiCallsV2.DetachDisk(vmName, path); + } + + File.Delete(path); + result = true; + } + catch (Exception sysEx) + { + details = CloudStackTypes.DestroyCommand + " failed due to " + sysEx.Message; + logger.Error(details, sysEx); + } + + object ansContent = new + { + result = result, + details = details, + contextMap = contextMap + }; + + return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.Answer); + } + } + + + private static JArray ReturnCloudStackTypedJArray(object ansContent, string ansType) + { + JObject ansObj = Utils.CreateCloudStackObject(ansType, ansContent); + JArray answer = new JArray(ansObj); + logger.Info(Utils.CleanString(ansObj.ToString())); + return answer; + } + + // POST api/HypervResource/CreateCommand + [HttpPost] + [ActionName(CloudStackTypes.CreateCommand)] + public JContainer CreateCommand([FromBody]dynamic cmd) + { + using (log4net.NDC.Push(Guid.NewGuid().ToString())) + { + logger.Info(CloudStackTypes.CreateCommand + Utils.CleanString(cmd.ToString())); + + string details = null; + bool result = false; + VolumeInfo volume = new VolumeInfo(); + + try + { + string diskType = cmd.diskCharacteristics.type; + ulong disksize = cmd.diskCharacteristics.size; + string templateUri = cmd.templateUrl; + + // assert: valid storagepool? + string poolTypeStr = cmd.pool.type; + string poolLocalPath = cmd.pool.path; + string poolUuid = cmd.pool.uuid; + string newVolPath = null; + long volId = cmd.volId; + string newVolName = null; + + if (ValidStoragePool(poolTypeStr, poolLocalPath, poolUuid, ref details)) + { + // No template URI? Its a blank disk. + if (string.IsNullOrEmpty(templateUri)) + { + // assert + VolumeType volType; + if (!Enum.TryParse(diskType, out volType) && volType != VolumeType.DATADISK) + { + details = "Cannot create volumes of type " + (string.IsNullOrEmpty(diskType) ? "NULL" : diskType); + } + else + { + newVolName = cmd.diskCharacteristics.name; + newVolPath = Path.Combine(poolLocalPath, newVolName, diskType.ToLower()); + // TODO: make volume format and block size configurable + wmiCallsV2.CreateDynamicVirtualHardDisk(disksize, newVolPath); + if (File.Exists(newVolPath)) + { + result = true; + } + else + { + details = "Failed to create DATADISK with name " + newVolName; + } + } + } + else + { + // TODO: Does this always work, or do I need to download template at times? + if (templateUri.Contains("/") || templateUri.Contains("\\")) + { + details = "Problem with templateURL " + templateUri + + " the URL should be volume UUID in primary storage created by previous PrimaryStorageDownloadCommand"; + logger.Error(details); + } + else + { + logger.Debug("Template's name in primary store should be " + templateUri); + // HypervPhysicalDisk BaseVol = primaryPool.getPhysicalDisk(tmplturl); + FileInfo srcFileInfo = new FileInfo(templateUri); + newVolName = Guid.NewGuid() + srcFileInfo.Extension; + newVolPath = Path.Combine(poolLocalPath, newVolName); + logger.Debug("New volume will be at " + newVolPath); + string oldVolPath = Path.Combine(poolLocalPath, templateUri); + File.Copy(oldVolPath, newVolPath); + if (File.Exists(newVolPath)) + { + result = true; + } + else + { + details = "Failed to create DATADISK with name " + newVolName; + } + } + volume = new VolumeInfo( + volId, diskType, + poolTypeStr, poolUuid, newVolName, + newVolPath, newVolPath, (long)disksize, null); + } + } + } + catch (Exception sysEx) + { + // TODO: consider this as model for error processing in all commands + details = CloudStackTypes.CreateCommand + " failed due to " + sysEx.Message; + logger.Error(details, sysEx); + } + + object ansContent = new + { + result = result, + details = details, + volume = volume, + contextMap = contextMap + }; + return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.CreateAnswer); + } + } + + // POST api/HypervResource/PrimaryStorageDownloadCommand + [HttpPost] + [ActionName(CloudStackTypes.PrimaryStorageDownloadCommand)] + public JContainer PrimaryStorageDownloadCommand([FromBody]dynamic cmd) + { + using (log4net.NDC.Push(Guid.NewGuid().ToString())) + { + logger.Info(CloudStackTypes.PrimaryStorageDownloadCommand + Utils.CleanString(cmd.ToString())); + string details = null; + bool result = false; + long size = 0; + string newCopyFileName = null; + + string poolLocalPath = cmd.localPath; + if (!Directory.Exists(poolLocalPath)) + { + details = "None existent local path " + poolLocalPath; + } + else + { + // Compose name for downloaded file. + string sourceUrl = cmd.url; + if (sourceUrl.ToLower().EndsWith(".vhd")) + { + newCopyFileName = Guid.NewGuid() + ".vhd"; + } + if (sourceUrl.ToLower().EndsWith(".vhdx")) + { + newCopyFileName = Guid.NewGuid() + ".vhdx"; + } + + // assert + if (newCopyFileName == null) + { + details = CloudStackTypes.PrimaryStorageDownloadCommand + " Invalid file extension for hypervisor type in source URL " + sourceUrl; + logger.Error(details); + } + else + { + try + { + FileInfo newFile; + if (CopyURI(sourceUrl, newCopyFileName, poolLocalPath, out newFile, ref details)) + { + size = newFile.Length; + result = true; + } + } + catch (System.Exception ex) + { + details = CloudStackTypes.PrimaryStorageDownloadCommand + " Cannot download source URL " + sourceUrl + " due to " + ex.Message; + logger.Error(details, ex); + } + } + } + + object ansContent = new + { + result = result, + details = details, + templateSize = size, + installPath = newCopyFileName, + contextMap = contextMap + }; + return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.PrimaryStorageDownloadAnswer); + } + } + + private static bool ValidStoragePool(string poolTypeStr, string poolLocalPath, string poolUuid, ref string details) + { + StoragePoolType poolType; + if (!Enum.TryParse(poolTypeStr, out poolType) || poolType != StoragePoolType.Filesystem) + { + details = "Primary storage pool " + poolUuid + " type " + poolType + " local path " + poolLocalPath + " has invalid StoragePoolType"; + logger.Error(details); + return false; + } + else if (!Directory.Exists(poolLocalPath)) + { + details = "Primary storage pool " + poolUuid + " type " + poolType + " local path " + poolLocalPath + " has invalid local path"; + logger.Error(details); + return false; + } + return true; + } + + /// + /// Exceptions to watch out for: + /// Exceptions related to URI creation + /// System.SystemException + /// +-System.ArgumentNullException + /// +-System.FormatException + /// +-System.UriFormatException + /// + /// Exceptions related to NFS URIs + /// System.SystemException + /// +-System.NotSupportedException + /// +-System.ArgumentException + /// +-System.ArgumentNullException + /// +-System.Security.SecurityException; + /// +-System.UnauthorizedAccessException + /// +-System.IO.IOException + /// +-System.IO.PathTooLongException + /// + /// Exceptions related to HTTP URIs + /// System.SystemException + /// +-System.InvalidOperationException + /// +-System.Net.WebException + /// +-System.NotSupportedException + /// +-System.ArgumentNullException + /// + /// + /// + /// + /// + private bool CopyURI(string sourceUri, string newCopyFileName, string poolLocalPath, out FileInfo newFile, ref string details) + { + Uri source = new Uri(sourceUri); + String destFilePath = Path.Combine(poolLocalPath, newCopyFileName); + string[] pathSegments = source.Segments; + String templateUUIDandExtension = pathSegments[pathSegments.Length - 1]; + newFile = new FileInfo(destFilePath); + + // NFS URI assumed to already be mounted locally. Mount location given by settings. + if (source.Scheme.ToLower().Equals("nfs")) + { + String srcDiskPath = Path.Combine(HypervResourceController.config.LocalSecondaryStoragePath, templateUUIDandExtension); + String taskMsg = "Copy NFS url in " + sourceUri + " at " + srcDiskPath + " to pool " + poolLocalPath; + logger.Debug(taskMsg); + File.Copy(srcDiskPath, destFilePath); + } + else if (source.Scheme.ToLower().Equals("http") || source.Scheme.ToLower().Equals("https")) + { + System.Net.WebClient webclient = new WebClient(); + webclient.DownloadFile(source, destFilePath); + } + else + { + details = "Unsupported URI scheme " + source.Scheme.ToLower() + " in source URI " + sourceUri; + logger.Error(details); + return false; + } + + if (!File.Exists(destFilePath)) + { + details = "Filed to copy " + sourceUri + " to primary pool destination " + destFilePath; + logger.Error(details); + return false; + } + return true; + } + + // POST api/HypervResource/CheckHealthCommand + [HttpPost] + [ActionName(CloudStackTypes.CheckHealthCommand)] + public JContainer CheckHealthCommand([FromBody]dynamic cmd) + { + using (log4net.NDC.Push(Guid.NewGuid().ToString())) + { logger.Info(CloudStackTypes.CheckHealthCommand + Utils.CleanString(cmd.ToString())); - object ansContent = new - { - result = true, - details = "resource is alive", - contextMap = contextMap - }; - return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.CheckHealthAnswer); - } - } - - // POST api/HypervResource/CheckOnHostCommand - [HttpPost] - [ActionName(CloudStackTypes.CheckOnHostCommand)] - public JContainer CheckOnHostCommand([FromBody]dynamic cmd) - { - using (log4net.NDC.Push(Guid.NewGuid().ToString())) - { + object ansContent = new + { + result = true, + details = "resource is alive", + contextMap = contextMap + }; + return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.CheckHealthAnswer); + } + } + + // POST api/HypervResource/CheckOnHostCommand + [HttpPost] + [ActionName(CloudStackTypes.CheckOnHostCommand)] + public JContainer CheckOnHostCommand([FromBody]dynamic cmd) + { + using (log4net.NDC.Push(Guid.NewGuid().ToString())) + { logger.Info(CloudStackTypes.CheckOnHostCommand + Utils.CleanString(cmd.ToString())); string details = "host is not alive"; bool result = true; @@ -807,16 +807,16 @@ namespace HypervResource logger.Error("Error Occurred in " + CloudStackTypes.CheckOnHostCommand + " : " + e.Message); } - object ansContent = new - { + object ansContent = new + { result = result, details = details, - contextMap = contextMap - }; - return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.CheckOnHostAnswer); - } - } - + contextMap = contextMap + }; + return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.CheckOnHostAnswer); + } + } + private bool IsHostAlive(string poolPath, string privateIp) { bool hostAlive = false; @@ -849,177 +849,177 @@ namespace HypervResource return hostAlive; } - // POST api/HypervResource/CheckSshCommand - // TODO: create test - [HttpPost] - [ActionName(CloudStackTypes.CheckSshCommand)] - public JContainer CheckSshCommand([FromBody]dynamic cmd) - { - using (log4net.NDC.Push(Guid.NewGuid().ToString())) - { + // POST api/HypervResource/CheckSshCommand + // TODO: create test + [HttpPost] + [ActionName(CloudStackTypes.CheckSshCommand)] + public JContainer CheckSshCommand([FromBody]dynamic cmd) + { + using (log4net.NDC.Push(Guid.NewGuid().ToString())) + { logger.Info(CloudStackTypes.CheckSshCommand + Utils.CleanString(cmd.ToString())); - object ansContent = new - { - result = true, - details = "NOP, TODO: implement properly", - contextMap = contextMap - }; - return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.CheckSshAnswer); - } - } - - // POST api/HypervResource/CheckVirtualMachineCommand - [HttpPost] - [ActionName(CloudStackTypes.CheckVirtualMachineCommand)] - public JContainer CheckVirtualMachineCommand([FromBody]dynamic cmd) - { - using (log4net.NDC.Push(Guid.NewGuid().ToString())) - { + object ansContent = new + { + result = true, + details = "NOP, TODO: implement properly", + contextMap = contextMap + }; + return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.CheckSshAnswer); + } + } + + // POST api/HypervResource/CheckVirtualMachineCommand + [HttpPost] + [ActionName(CloudStackTypes.CheckVirtualMachineCommand)] + public JContainer CheckVirtualMachineCommand([FromBody]dynamic cmd) + { + using (log4net.NDC.Push(Guid.NewGuid().ToString())) + { logger.Info(CloudStackTypes.CheckVirtualMachineCommand + Utils.CleanString(cmd.ToString())); - string details = null; - bool result = false; - string vmName = cmd.vmName; - string state = null; - - // TODO: Look up the VM, convert Hyper-V state to CloudStack version. - var sys = wmiCallsV2.GetComputerSystem(vmName); - if (sys == null) - { - details = CloudStackTypes.CheckVirtualMachineCommand + " requested unknown VM " + vmName; - logger.Error(details); - } - else - { - state = EnabledState.ToCloudStackState(sys.EnabledState); // TODO: V2 changes? - result = true; - } - - object ansContent = new - { - result = result, - details = details, - state = state, - contextMap = contextMap - }; - return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.CheckVirtualMachineAnswer); - } - } - - // POST api/HypervResource/DeleteStoragePoolCommand - [HttpPost] - [ActionName(CloudStackTypes.DeleteStoragePoolCommand)] - public JContainer DeleteStoragePoolCommand([FromBody]dynamic cmd) - { - using (log4net.NDC.Push(Guid.NewGuid().ToString())) - { + string details = null; + bool result = false; + string vmName = cmd.vmName; + string state = null; + + // TODO: Look up the VM, convert Hyper-V state to CloudStack version. + var sys = wmiCallsV2.GetComputerSystem(vmName); + if (sys == null) + { + details = CloudStackTypes.CheckVirtualMachineCommand + " requested unknown VM " + vmName; + logger.Error(details); + } + else + { + state = EnabledState.ToCloudStackState(sys.EnabledState); // TODO: V2 changes? + result = true; + } + + object ansContent = new + { + result = result, + details = details, + state = state, + contextMap = contextMap + }; + return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.CheckVirtualMachineAnswer); + } + } + + // POST api/HypervResource/DeleteStoragePoolCommand + [HttpPost] + [ActionName(CloudStackTypes.DeleteStoragePoolCommand)] + public JContainer DeleteStoragePoolCommand([FromBody]dynamic cmd) + { + using (log4net.NDC.Push(Guid.NewGuid().ToString())) + { logger.Info(CloudStackTypes.DeleteStoragePoolCommand + Utils.CleanString(cmd.ToString())); - object ansContent = new - { - result = true, - details = "Current implementation does not delete local path corresponding to storage pool!", - contextMap = contextMap - }; - return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.Answer); - } - } - - /// - /// NOP - legacy command - - /// POST api/HypervResource/CreateStoragePoolCommand - /// - /// - /// - [HttpPost] - [ActionName(CloudStackTypes.CreateStoragePoolCommand)] - public JContainer CreateStoragePoolCommand([FromBody]dynamic cmd) - { - using (log4net.NDC.Push(Guid.NewGuid().ToString())) - { - logger.Info(CloudStackTypes.CreateStoragePoolCommand + Utils.CleanString(cmd.ToString())); - object ansContent = new - { - result = true, - details = "success - NOP", - contextMap = contextMap - }; - return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.Answer); - } - } - - // POST api/HypervResource/ModifyStoragePoolCommand - [HttpPost] - [ActionName(CloudStackTypes.ModifyStoragePoolCommand)] - public JContainer ModifyStoragePoolCommand([FromBody]dynamic cmd) - { - using (log4net.NDC.Push(Guid.NewGuid().ToString())) - { - logger.Info(CloudStackTypes.ModifyStoragePoolCommand + Utils.CleanString(cmd.ToString())); - string details = null; - string localPath; - StoragePoolType poolType; - object ansContent; - - bool result = ValidateStoragePoolCommand(cmd, out localPath, out poolType, ref details); - if (!result) - { - ansContent = new - { - result = result, - details = details, - contextMap = contextMap - }; - return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.Answer); - } - - var tInfo = new Dictionary(); - long capacityBytes = 0; - long availableBytes = 0; - string hostPath = null; - if (poolType == StoragePoolType.Filesystem) - { - GetCapacityForLocalPath(localPath, out capacityBytes, out availableBytes); - hostPath = localPath; - } - else if (poolType == StoragePoolType.NetworkFilesystem || - poolType == StoragePoolType.SMB) - { - NFSTO share = new NFSTO(); - String uriStr = "cifs://" + (string)cmd.pool.host + (string)cmd.pool.path; - share.uri = new Uri(uriStr); - hostPath = Utils.NormalizePath(share.UncPath); - - // Check access to share. - Utils.ConnectToRemote(share.UncPath, share.Domain, share.User, share.Password); - Utils.GetShareDetails(share.UncPath, out capacityBytes, out availableBytes); - config.setPrimaryStorage((string)cmd.pool.uuid, hostPath); - } - else - { - result = false; - } - - String uuid = null; - var poolInfo = new - { - uuid = uuid, - host = cmd.pool.host, - hostPath = cmd.pool.path, - localPath = hostPath, - poolType = cmd.pool.type, - capacityBytes = capacityBytes, - availableBytes = availableBytes - }; - - ansContent = new - { - result = result, - details = details, - localPath = hostPath, - templateInfo = tInfo, - poolInfo = poolInfo, - contextMap = contextMap - }; - + object ansContent = new + { + result = true, + details = "Current implementation does not delete local path corresponding to storage pool!", + contextMap = contextMap + }; + return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.Answer); + } + } + + /// + /// NOP - legacy command - + /// POST api/HypervResource/CreateStoragePoolCommand + /// + /// + /// + [HttpPost] + [ActionName(CloudStackTypes.CreateStoragePoolCommand)] + public JContainer CreateStoragePoolCommand([FromBody]dynamic cmd) + { + using (log4net.NDC.Push(Guid.NewGuid().ToString())) + { + logger.Info(CloudStackTypes.CreateStoragePoolCommand + Utils.CleanString(cmd.ToString())); + object ansContent = new + { + result = true, + details = "success - NOP", + contextMap = contextMap + }; + return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.Answer); + } + } + + // POST api/HypervResource/ModifyStoragePoolCommand + [HttpPost] + [ActionName(CloudStackTypes.ModifyStoragePoolCommand)] + public JContainer ModifyStoragePoolCommand([FromBody]dynamic cmd) + { + using (log4net.NDC.Push(Guid.NewGuid().ToString())) + { + logger.Info(CloudStackTypes.ModifyStoragePoolCommand + Utils.CleanString(cmd.ToString())); + string details = null; + string localPath; + StoragePoolType poolType; + object ansContent; + + bool result = ValidateStoragePoolCommand(cmd, out localPath, out poolType, ref details); + if (!result) + { + ansContent = new + { + result = result, + details = details, + contextMap = contextMap + }; + return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.Answer); + } + + var tInfo = new Dictionary(); + long capacityBytes = 0; + long availableBytes = 0; + string hostPath = null; + if (poolType == StoragePoolType.Filesystem) + { + GetCapacityForLocalPath(localPath, out capacityBytes, out availableBytes); + hostPath = localPath; + } + else if (poolType == StoragePoolType.NetworkFilesystem || + poolType == StoragePoolType.SMB) + { + NFSTO share = new NFSTO(); + String uriStr = "cifs://" + (string)cmd.pool.host + (string)cmd.pool.path; + share.uri = new Uri(uriStr); + hostPath = Utils.NormalizePath(share.UncPath); + + // Check access to share. + Utils.ConnectToRemote(share.UncPath, share.Domain, share.User, share.Password); + Utils.GetShareDetails(share.UncPath, out capacityBytes, out availableBytes); + config.setPrimaryStorage((string)cmd.pool.uuid, hostPath); + } + else + { + result = false; + } + + String uuid = null; + var poolInfo = new + { + uuid = uuid, + host = cmd.pool.host, + hostPath = cmd.pool.path, + localPath = hostPath, + poolType = cmd.pool.type, + capacityBytes = capacityBytes, + availableBytes = availableBytes + }; + + ansContent = new + { + result = result, + details = details, + localPath = hostPath, + templateInfo = tInfo, + poolInfo = poolInfo, + contextMap = contextMap + }; + if (result) { try @@ -1041,34 +1041,34 @@ namespace HypervResource } } - return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.ModifyStoragePoolAnswer); - } - } - - private bool ValidateStoragePoolCommand(dynamic cmd, out string localPath, out StoragePoolType poolType, ref string details) - { - dynamic pool = cmd.pool; - string poolTypeStr = pool.type; - localPath = cmd.localPath; - if (!Enum.TryParse(poolTypeStr, out poolType)) - { - details = "Request to create / modify unsupported pool type: " + (poolTypeStr == null ? "NULL" : poolTypeStr) + "in cmd " + JsonConvert.SerializeObject(cmd); - logger.Error(details); - return false; - } - - if (poolType != StoragePoolType.Filesystem && - poolType != StoragePoolType.NetworkFilesystem && - poolType != StoragePoolType.SMB) - { - details = "Request to create / modify unsupported pool type: " + (poolTypeStr == null ? "NULL" : poolTypeStr) + "in cmd " + JsonConvert.SerializeObject(cmd); - logger.Error(details); - return false; - } - - return true; - } - + return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.ModifyStoragePoolAnswer); + } + } + + private bool ValidateStoragePoolCommand(dynamic cmd, out string localPath, out StoragePoolType poolType, ref string details) + { + dynamic pool = cmd.pool; + string poolTypeStr = pool.type; + localPath = cmd.localPath; + if (!Enum.TryParse(poolTypeStr, out poolType)) + { + details = "Request to create / modify unsupported pool type: " + (poolTypeStr == null ? "NULL" : poolTypeStr) + "in cmd " + JsonConvert.SerializeObject(cmd); + logger.Error(details); + return false; + } + + if (poolType != StoragePoolType.Filesystem && + poolType != StoragePoolType.NetworkFilesystem && + poolType != StoragePoolType.SMB) + { + details = "Request to create / modify unsupported pool type: " + (poolTypeStr == null ? "NULL" : poolTypeStr) + "in cmd " + JsonConvert.SerializeObject(cmd); + logger.Error(details); + return false; + } + + return true; + } + // POST api/HypervResource/PlugNicCommand [HttpPost] [ActionName(CloudStackTypes.PlugNicCommand)] @@ -1087,301 +1087,301 @@ namespace HypervResource } } - - // POST api/HypervResource/CleanupNetworkRulesCmd - [HttpPost] - [ActionName(CloudStackTypes.CleanupNetworkRulesCmd)] - public JContainer CleanupNetworkRulesCmd([FromBody]dynamic cmd) - { - using (log4net.NDC.Push(Guid.NewGuid().ToString())) - { + + // POST api/HypervResource/CleanupNetworkRulesCmd + [HttpPost] + [ActionName(CloudStackTypes.CleanupNetworkRulesCmd)] + public JContainer CleanupNetworkRulesCmd([FromBody]dynamic cmd) + { + using (log4net.NDC.Push(Guid.NewGuid().ToString())) + { logger.Info(CloudStackTypes.CleanupNetworkRulesCmd + Utils.CleanString(cmd.ToString())); - object ansContent = new - { - result = false, - details = "nothing to cleanup in our current implementation", - contextMap = contextMap - }; - return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.Answer); - } - } - - // POST api/HypervResource/CheckNetworkCommand - [HttpPost] - [ActionName(CloudStackTypes.CheckNetworkCommand)] - public JContainer CheckNetworkCommand([FromBody]dynamic cmd) - { - using (log4net.NDC.Push(Guid.NewGuid().ToString())) - { + object ansContent = new + { + result = false, + details = "nothing to cleanup in our current implementation", + contextMap = contextMap + }; + return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.Answer); + } + } + + // POST api/HypervResource/CheckNetworkCommand + [HttpPost] + [ActionName(CloudStackTypes.CheckNetworkCommand)] + public JContainer CheckNetworkCommand([FromBody]dynamic cmd) + { + using (log4net.NDC.Push(Guid.NewGuid().ToString())) + { logger.Info(CloudStackTypes.CheckNetworkCommand + Utils.CleanString(cmd.ToString())); - object ansContent = new - { - result = true, - details = (string)null, - contextMap = contextMap - }; - return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.CheckNetworkAnswer); - } - } - - // POST api/HypervResource/ReadyCommand - [HttpPost] - [ActionName(CloudStackTypes.ReadyCommand)] - public JContainer ReadyCommand([FromBody]dynamic cmd) - { - using (log4net.NDC.Push(Guid.NewGuid().ToString())) - { + object ansContent = new + { + result = true, + details = (string)null, + contextMap = contextMap + }; + return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.CheckNetworkAnswer); + } + } + + // POST api/HypervResource/ReadyCommand + [HttpPost] + [ActionName(CloudStackTypes.ReadyCommand)] + public JContainer ReadyCommand([FromBody]dynamic cmd) + { + using (log4net.NDC.Push(Guid.NewGuid().ToString())) + { logger.Info(CloudStackTypes.ReadyCommand + Utils.CleanString(cmd.ToString())); - object ansContent = new - { - result = true, - details = (string)null, - contextMap = contextMap - }; - return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.ReadyAnswer); - } - - } - - // POST api/HypervResource/StartCommand - [HttpPost] - [ActionName(CloudStackTypes.StartCommand)] - public JContainer StartCommand([FromBody]dynamic cmd) - { - using (log4net.NDC.Push(Guid.NewGuid().ToString())) - { - logger.Info(CloudStackTypes.StartCommand + Utils.CleanString(cmd.ToString())); - string details = null; - bool result = false; - - try - { - string systemVmIsoPath = systemVmIso; - lock (systemVmIso) - { - systemVmIsoPath = systemVmIso; - String uriStr = (String)cmd.secondaryStorage; - if (!String.IsNullOrEmpty(uriStr)) - { - if (String.IsNullOrEmpty(systemVmIsoPath) || !File.Exists(systemVmIsoPath)) - { - NFSTO share = new NFSTO(); - share.uri = new Uri(uriStr); - string defaultDataPath = wmiCallsV2.GetDefaultDataRoot(); - - string secondaryPath = Utils.NormalizePath(Path.Combine(share.UncPath, "systemvm")); + object ansContent = new + { + result = true, + details = (string)null, + contextMap = contextMap + }; + return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.ReadyAnswer); + } + + } + + // POST api/HypervResource/StartCommand + [HttpPost] + [ActionName(CloudStackTypes.StartCommand)] + public JContainer StartCommand([FromBody]dynamic cmd) + { + using (log4net.NDC.Push(Guid.NewGuid().ToString())) + { + logger.Info(CloudStackTypes.StartCommand + Utils.CleanString(cmd.ToString())); + string details = null; + bool result = false; + + try + { + string systemVmIsoPath = systemVmIso; + lock (systemVmIso) + { + systemVmIsoPath = systemVmIso; + String uriStr = (String)cmd.secondaryStorage; + if (!String.IsNullOrEmpty(uriStr)) + { + if (String.IsNullOrEmpty(systemVmIsoPath) || !File.Exists(systemVmIsoPath)) + { + NFSTO share = new NFSTO(); + share.uri = new Uri(uriStr); + string defaultDataPath = wmiCallsV2.GetDefaultDataRoot(); + + string secondaryPath = Utils.NormalizePath(Path.Combine(share.UncPath, "systemvm")); string[] choices = Directory.GetFiles(secondaryPath, "systemvm*.iso"); - if (choices.Length != 1) - { - String errMsg = "Couldn't locate the systemvm iso on " + secondaryPath; - logger.Debug(errMsg); - } - else - { - systemVmIsoPath = Utils.NormalizePath(Path.Combine(defaultDataPath, Path.GetFileName(choices[0]))); - if (!File.Exists(systemVmIsoPath)) - { - Utils.DownloadCifsFileToLocalFile(choices[0], share, systemVmIsoPath); - } - systemVmIso = systemVmIsoPath; - } - } - } - } - - wmiCallsV2.DeployVirtualMachine(cmd, systemVmIsoPath); - result = true; - } - catch (Exception wmiEx) - { - details = CloudStackTypes.StartCommand + " fail on exception" + wmiEx.Message; - logger.Error(details, wmiEx); - } - - object ansContent = new - { - result = result, - details = details, - vm = cmd.vm, - contextMap = contextMap - }; - return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.StartAnswer); - } - } - - // POST api/HypervResource/StopCommand - [HttpPost] - [ActionName(CloudStackTypes.StopCommand)] - public JContainer StopCommand([FromBody]dynamic cmd) - { - using (log4net.NDC.Push(Guid.NewGuid().ToString())) - { + if (choices.Length != 1) + { + String errMsg = "Couldn't locate the systemvm iso on " + secondaryPath; + logger.Debug(errMsg); + } + else + { + systemVmIsoPath = Utils.NormalizePath(Path.Combine(defaultDataPath, Path.GetFileName(choices[0]))); + if (!File.Exists(systemVmIsoPath)) + { + Utils.DownloadCifsFileToLocalFile(choices[0], share, systemVmIsoPath); + } + systemVmIso = systemVmIsoPath; + } + } + } + } + + wmiCallsV2.DeployVirtualMachine(cmd, systemVmIsoPath); + result = true; + } + catch (Exception wmiEx) + { + details = CloudStackTypes.StartCommand + " fail on exception" + wmiEx.Message; + logger.Error(details, wmiEx); + } + + object ansContent = new + { + result = result, + details = details, + vm = cmd.vm, + contextMap = contextMap + }; + return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.StartAnswer); + } + } + + // POST api/HypervResource/StopCommand + [HttpPost] + [ActionName(CloudStackTypes.StopCommand)] + public JContainer StopCommand([FromBody]dynamic cmd) + { + using (log4net.NDC.Push(Guid.NewGuid().ToString())) + { logger.Info(CloudStackTypes.StopCommand + Utils.CleanString(cmd.ToString())); - string details = null; - bool result = false; - bool checkBeforeCleanup = cmd.checkBeforeCleanup; - String vmName = cmd.vmName; - - if (checkBeforeCleanup == true) - { - ComputerSystem vm = wmiCallsV2.GetComputerSystem(vmName); - if (vm == null || vm.EnabledState == 2) - { - // VM is not available or vm in running state - return ReturnCloudStackTypedJArray(new { result = false, details = "VM is running on host, bailing out", vm = vmName, contextMap = contextMap }, CloudStackTypes.StopAnswer); - } - } - try - { - wmiCallsV2.DestroyVm(cmd); - result = true; - } - catch (Exception wmiEx) - { - details = CloudStackTypes.StopCommand + " fail on exception" + wmiEx.Message; - logger.Error(details, wmiEx); - } - - object ansContent = new - { - result = result, - details = details, - vm = cmd.vm, - contextMap = contextMap - }; - return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.StopAnswer); - } - } - - // POST api/HypervResource/CreateObjectCommand - [HttpPost] - [ActionName(CloudStackTypes.CreateObjectCommand)] - public JContainer CreateObjectCommand([FromBody]dynamic cmd) - { - using (log4net.NDC.Push(Guid.NewGuid().ToString())) - { - logger.Info(CloudStackTypes.CreateObjectCommand + Utils.CleanString(cmd.ToString())); - - bool result = false; - string details = null; + string details = null; + bool result = false; + bool checkBeforeCleanup = cmd.checkBeforeCleanup; + String vmName = cmd.vmName; + + if (checkBeforeCleanup == true) + { + ComputerSystem vm = wmiCallsV2.GetComputerSystem(vmName); + if (vm == null || vm.EnabledState == 2) + { + // VM is not available or vm in running state + return ReturnCloudStackTypedJArray(new { result = false, details = "VM is running on host, bailing out", vm = vmName, contextMap = contextMap }, CloudStackTypes.StopAnswer); + } + } + try + { + wmiCallsV2.DestroyVm(cmd); + result = true; + } + catch (Exception wmiEx) + { + details = CloudStackTypes.StopCommand + " fail on exception" + wmiEx.Message; + logger.Error(details, wmiEx); + } + + object ansContent = new + { + result = result, + details = details, + vm = cmd.vm, + contextMap = contextMap + }; + return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.StopAnswer); + } + } + + // POST api/HypervResource/CreateObjectCommand + [HttpPost] + [ActionName(CloudStackTypes.CreateObjectCommand)] + public JContainer CreateObjectCommand([FromBody]dynamic cmd) + { + using (log4net.NDC.Push(Guid.NewGuid().ToString())) + { + logger.Info(CloudStackTypes.CreateObjectCommand + Utils.CleanString(cmd.ToString())); + + bool result = false; + string details = null; object newData = null; - try - { - VolumeObjectTO volume = VolumeObjectTO.ParseJson(cmd.data); - PrimaryDataStoreTO primary = volume.primaryDataStore; - ulong volumeSize = volume.size; + try + { + VolumeObjectTO volume = VolumeObjectTO.ParseJson(cmd.data); + PrimaryDataStoreTO primary = volume.primaryDataStore; + ulong volumeSize = volume.size; string volumeName = volume.uuid + ".vhdx"; - string volumePath = null; - - if (primary.isLocal) - { - volumePath = Path.Combine(primary.Path, volumeName); - } - else - { - volumePath = @"\\" + primary.uri.Host + primary.uri.LocalPath + @"\" + volumeName; - volumePath = Utils.NormalizePath(volumePath); - Utils.ConnectToRemote(primary.UncPath, primary.Domain, primary.User, primary.Password); - } + string volumePath = null; + + if (primary.isLocal) + { + volumePath = Path.Combine(primary.Path, volumeName); + } + else + { + volumePath = @"\\" + primary.uri.Host + primary.uri.LocalPath + @"\" + volumeName; + volumePath = Utils.NormalizePath(volumePath); + Utils.ConnectToRemote(primary.UncPath, primary.Domain, primary.User, primary.Password); + } volume.path = volume.uuid; - wmiCallsV2.CreateDynamicVirtualHardDisk(volumeSize, volumePath); - if (File.Exists(volumePath)) - { - result = true; + wmiCallsV2.CreateDynamicVirtualHardDisk(volumeSize, volumePath); + if (File.Exists(volumePath)) + { + result = true; JObject ansObj = Utils.CreateCloudStackObject(CloudStackTypes.VolumeObjectTO, volume); newData = ansObj; - } - else - { - details = "Failed to create disk with name " + volumePath; - } - } - catch (Exception ex) - { - // Test by providing wrong key - details = CloudStackTypes.CreateObjectCommand + " failed on exception, " + ex.Message; - logger.Error(details, ex); - } - - object ansContent = new - { - result = result, - details = details, + } + else + { + details = "Failed to create disk with name " + volumePath; + } + } + catch (Exception ex) + { + // Test by providing wrong key + details = CloudStackTypes.CreateObjectCommand + " failed on exception, " + ex.Message; + logger.Error(details, ex); + } + + object ansContent = new + { + result = result, + details = details, data = newData, - contextMap = contextMap - }; - - return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.CreateObjectAnswer); - } - } - - // POST api/HypervResource/MaintainCommand - // TODO: should this be a NOP? - [HttpPost] - [ActionName(CloudStackTypes.MaintainCommand)] - public JContainer MaintainCommand([FromBody]dynamic cmd) - { - using (log4net.NDC.Push(Guid.NewGuid().ToString())) - { + contextMap = contextMap + }; + + return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.CreateObjectAnswer); + } + } + + // POST api/HypervResource/MaintainCommand + // TODO: should this be a NOP? + [HttpPost] + [ActionName(CloudStackTypes.MaintainCommand)] + public JContainer MaintainCommand([FromBody]dynamic cmd) + { + using (log4net.NDC.Push(Guid.NewGuid().ToString())) + { logger.Info(CloudStackTypes.MaintainCommand + Utils.CleanString(cmd.ToString())); - - object ansContent = new - { - result = true, - willMigrate = true, - details = "success - NOP for MaintainCommand", - _reconnect = false, - contextMap = contextMap - }; - - return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.MaintainAnswer); - } - } - - // POST api/HypervResource/PingRoutingCommand - // TODO: should this be a NOP? - [HttpPost] - [ActionName(CloudStackTypes.PingRoutingCommand)] - public JContainer PingRoutingCommand([FromBody]dynamic cmd) - { - using (log4net.NDC.Push(Guid.NewGuid().ToString())) - { + + object ansContent = new + { + result = true, + willMigrate = true, + details = "success - NOP for MaintainCommand", + _reconnect = false, + contextMap = contextMap + }; + + return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.MaintainAnswer); + } + } + + // POST api/HypervResource/PingRoutingCommand + // TODO: should this be a NOP? + [HttpPost] + [ActionName(CloudStackTypes.PingRoutingCommand)] + public JContainer PingRoutingCommand([FromBody]dynamic cmd) + { + using (log4net.NDC.Push(Guid.NewGuid().ToString())) + { logger.Info(CloudStackTypes.PingRoutingCommand + Utils.CleanString(cmd.ToString())); - - object ansContent = new - { - result = true, - details = "success - NOP for PingRoutingCommand", - _reconnect = false, - contextMap = contextMap - }; - - return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.Answer); - } - } - - // POST api/HypervResource/PingCommand - // TODO: should this be a NOP? - [HttpPost] - [ActionName(CloudStackTypes.PingCommand)] - public JContainer PingCommand([FromBody]dynamic cmd) - { - using (log4net.NDC.Push(Guid.NewGuid().ToString())) - { + + object ansContent = new + { + result = true, + details = "success - NOP for PingRoutingCommand", + _reconnect = false, + contextMap = contextMap + }; + + return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.Answer); + } + } + + // POST api/HypervResource/PingCommand + // TODO: should this be a NOP? + [HttpPost] + [ActionName(CloudStackTypes.PingCommand)] + public JContainer PingCommand([FromBody]dynamic cmd) + { + using (log4net.NDC.Push(Guid.NewGuid().ToString())) + { logger.Info(CloudStackTypes.PingCommand + Utils.CleanString(cmd.ToString())); - - object ansContent = new - { - result = true, - details = "success - NOP for PingCommand", - _reconnect = false, - contextMap = contextMap - }; - - return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.Answer); - } - } - + + object ansContent = new + { + result = true, + details = "success - NOP for PingCommand", + _reconnect = false, + contextMap = contextMap + }; + + return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.Answer); + } + } + // POST api/HypervResource/ModifyVmVnicVlanCommand [HttpPost] [ActionName(CloudStackTypes.ModifyVmNicConfigCommand)] @@ -1395,17 +1395,17 @@ namespace HypervResource String vmName = cmd.vmName; String vlan = cmd.vlan; string macAddress = cmd.macAddress; - uint pos = cmd.index; + uint pos = cmd.index; bool enable = cmd.enable; string switchLableName = cmd.switchLableName; if (macAddress != null) { - wmiCallsV2.ModifyVmVLan(vmName, vlan, macAddress); + wmiCallsV2.ModifyVmVLan(vmName, vlan, macAddress); result = true; } else if (pos >= 1) - { - wmiCallsV2.ModifyVmVLan(vmName, vlan, pos, enable, switchLableName); + { + wmiCallsV2.ModifyVmVLan(vmName, vlan, pos, enable, switchLableName); result = true; } @@ -1434,33 +1434,33 @@ namespace HypervResource List nicDetails = new List(); var nicSettingsViaVm = wmiCallsV2.GetEthernetPortSettings(vm); NicDetails nic = null; - int index = 0; - int[] nicStates = new int[8]; - int[] nicVlan = new int[8]; - int vlanid = 1; - - var ethernetConnections = wmiCallsV2.GetEthernetConnections(vm); - foreach (EthernetPortAllocationSettingData item in ethernetConnections) - { - EthernetSwitchPortVlanSettingData vlanSettings = wmiCallsV2.GetVlanSettings(item); - if (vlanSettings == null) - { - vlanid = -1; - } - else - { - vlanid = vlanSettings.AccessVlanId; - } - nicStates[index] = (Int32)(item.EnabledState); - nicVlan[index] = vlanid; - index++; - } - + int index = 0; + int[] nicStates = new int[8]; + int[] nicVlan = new int[8]; + int vlanid = 1; + + var ethernetConnections = wmiCallsV2.GetEthernetConnections(vm); + foreach (EthernetPortAllocationSettingData item in ethernetConnections) + { + EthernetSwitchPortVlanSettingData vlanSettings = wmiCallsV2.GetVlanSettings(item); + if (vlanSettings == null) + { + vlanid = -1; + } + else + { + vlanid = vlanSettings.AccessVlanId; + } + nicStates[index] = (Int32)(item.EnabledState); + nicVlan[index] = vlanid; + index++; + } + index = 0; foreach (SyntheticEthernetPortSettingData item in nicSettingsViaVm) { - nic = new NicDetails(item.Address, nicVlan[index], nicStates[index]); - index++; + nic = new NicDetails(item.Address, nicVlan[index], nicStates[index]); + index++; nicDetails.Add(nic); } @@ -1480,909 +1480,909 @@ namespace HypervResource - // POST api/HypervResource/GetVmStatsCommand - [HttpPost] - [ActionName(CloudStackTypes.GetVmStatsCommand)] - public JContainer GetVmStatsCommand([FromBody]dynamic cmd) - { - using (log4net.NDC.Push(Guid.NewGuid().ToString())) - { + // POST api/HypervResource/GetVmStatsCommand + [HttpPost] + [ActionName(CloudStackTypes.GetVmStatsCommand)] + public JContainer GetVmStatsCommand([FromBody]dynamic cmd) + { + using (log4net.NDC.Push(Guid.NewGuid().ToString())) + { logger.Info(CloudStackTypes.GetVmStatsCommand + Utils.CleanString(cmd.ToString())); - bool result = false; - JArray vmNamesJson = cmd.vmNames; - string[] vmNames = vmNamesJson.ToObject(); - Dictionary vmProcessorInfo = new Dictionary(vmNames.Length); - - var vmsToInspect = new List(); - foreach (var vmName in vmNames) - { - var sys = wmiCallsV2.GetComputerSystem(vmName); - if (sys == null) - { - logger.InfoFormat("GetVmStatsCommand requested unknown VM {0}", vmNames); - continue; - } - var sysInfo = wmiCallsV2.GetVmSettings(sys); - vmsToInspect.Add(sysInfo.Path); - } - - wmiCallsV2.GetSummaryInfo(vmProcessorInfo, vmsToInspect); - - // TODO: Network usage comes from Performance Counter API; however it is only available in kb/s, and not in total terms. - // Curious about these? Use perfmon to inspect them, e.g. http://msdn.microsoft.com/en-us/library/xhcx5a20%28v=vs.100%29.aspx - // Recent post on these counter at http://blogs.technet.com/b/cedward/archive/2011/07/19/hyper-v-networking-optimizations-part-6-of-6-monitoring-hyper-v-network-consumption.aspx - result = true; - - object ansContent = new - { - vmStatsMap = vmProcessorInfo, - result = result, - contextMap = contextMap - }; - return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.GetVmStatsAnswer); - } - } - - // POST api/HypervResource/CopyCommand - [HttpPost] - [ActionName(CloudStackTypes.CopyCommand)] - public JContainer CopyCommand(dynamic cmd) - { - using (log4net.NDC.Push(Guid.NewGuid().ToString())) - { - // Log command *after* we've removed security details from the command. - logger.Info(CloudStackTypes.CopyCommand + Utils.CleanString(cmd.ToString())); - - bool result = false; - string details = null; - object newData = null; - TemplateObjectTO destTemplateObjectTO = null; - VolumeObjectTO destVolumeObjectTO = null; - VolumeObjectTO srcVolumeObjectTO = null; - TemplateObjectTO srcTemplateObjectTO = null; - - try - { - srcTemplateObjectTO = TemplateObjectTO.ParseJson(cmd.srcTO); - destTemplateObjectTO = TemplateObjectTO.ParseJson(cmd.destTO); - srcVolumeObjectTO = VolumeObjectTO.ParseJson(cmd.srcTO); - destVolumeObjectTO = VolumeObjectTO.ParseJson(cmd.destTO); - - string destFile = null; - if (destTemplateObjectTO != null) - { - if (destTemplateObjectTO.primaryDataStore != null) - { - destFile = destTemplateObjectTO.FullFileName; - if (!destTemplateObjectTO.primaryDataStore.isLocal) - { - PrimaryDataStoreTO primary = destTemplateObjectTO.primaryDataStore; - Utils.ConnectToRemote(primary.UncPath, primary.Domain, primary.User, primary.Password); - } - } - else if (destTemplateObjectTO.nfsDataStoreTO != null) - { - destFile = destTemplateObjectTO.FullFileName; - NFSTO store = destTemplateObjectTO.nfsDataStoreTO; - Utils.ConnectToRemote(store.UncPath, store.Domain, store.User, store.Password); - } - } - - // Template already downloaded? - if (destFile != null && File.Exists(destFile) && - !String.IsNullOrEmpty(destTemplateObjectTO.checksum)) - { - // TODO: checksum fails us, because it is of the compressed image. - // ASK: should we store the compressed or uncompressed version or is the checksum not calculated correctly? - logger.Debug(CloudStackTypes.CopyCommand + " calling VerifyChecksum to see if we already have the file at " + destFile); - result = VerifyChecksum(destFile, destTemplateObjectTO.checksum); - if (!result) - { - result = true; - logger.Debug(CloudStackTypes.CopyCommand + " existing file has different checksum " + destFile); - } - } - - // Do we have to create a new one? - if (!result) - { - // Create local copy of a template? - if (srcTemplateObjectTO != null && destTemplateObjectTO != null) - { - // S3 download to primary storage? - // NFS provider download to primary storage? - if ((srcTemplateObjectTO.s3DataStoreTO != null || srcTemplateObjectTO.nfsDataStoreTO != null) && destTemplateObjectTO.primaryDataStore != null) - { - if (File.Exists(destFile)) - { - logger.Info("Deleting existing file " + destFile); - File.Delete(destFile); - } - - if (srcTemplateObjectTO.s3DataStoreTO != null) - { - // Download from S3 to destination data storage - DownloadS3ObjectToFile(srcTemplateObjectTO.path, srcTemplateObjectTO.s3DataStoreTO, destFile); - } - else if (srcTemplateObjectTO.nfsDataStoreTO != null) - { - // Download from S3 to destination data storage - Utils.DownloadCifsFileToLocalFile(srcTemplateObjectTO.path, srcTemplateObjectTO.nfsDataStoreTO, destFile); - } - - // Uncompress, as required - if (srcTemplateObjectTO.path.EndsWith(".bz2")) - { - String uncompressedFile = destFile + ".tmp"; - String compressedFile = destFile; - using (var uncompressedOutStrm = new FileStream(uncompressedFile, FileMode.CreateNew, FileAccess.Write)) - { - using (var compressedInStrm = new FileStream(destFile, FileMode.Open, FileAccess.Read)) - { - using (var bz2UncompressorStrm = new Ionic.BZip2.BZip2InputStream(compressedInStrm, true) /* outer 'using' statement will close FileStream*/ ) - { - int count = 0; - int bufsize = 1024 * 1024; - byte[] buf = new byte[bufsize]; - - // EOF returns -1, see http://dotnetzip.codeplex.com/workitem/16069 - while (0 < (count = bz2UncompressorStrm.Read(buf, 0, bufsize))) - { - uncompressedOutStrm.Write(buf, 0, count); - } - } - } - } - File.Delete(compressedFile); - File.Move(uncompressedFile, compressedFile); - if (File.Exists(uncompressedFile)) - { - String errMsg = "Extra file left around called " + uncompressedFile + " when creating " + destFile; - logger.Error(errMsg); - throw new IOException(errMsg); - } - } - - // assert - if (!File.Exists(destFile)) - { - String errMsg = "Failed to create " + destFile + " , because the file is missing"; - logger.Error(errMsg); - throw new IOException(errMsg); - } - - newData = cmd.destTO; - result = true; - } - else - { - details = "Data store combination not supported"; - } - } - // Create volume from a template? - else if (srcTemplateObjectTO != null && destVolumeObjectTO != null) - { - // VolumeObjectTO guesses file extension based on existing files - // this can be wrong if the previous file had a different file type - var guessedDestFile = destVolumeObjectTO.FullFileName; - if (File.Exists(guessedDestFile)) - { - logger.Info("Deleting existing file " + guessedDestFile); - File.Delete(guessedDestFile); - } - - destVolumeObjectTO.format = srcTemplateObjectTO.format; - destFile = destVolumeObjectTO.FullFileName; - if (File.Exists(destFile)) - { - logger.Info("Deleting existing file " + destFile); - File.Delete(destFile); - } - - string srcFile = srcTemplateObjectTO.FullFileName; - if (!File.Exists(srcFile)) - { - details = "Local template file missing from " + srcFile; - } - else - { - // TODO: thin provision instead of copying the full file. - File.Copy(srcFile, destFile); - destVolumeObjectTO.path = destVolumeObjectTO.uuid; - JObject ansObj = Utils.CreateCloudStackObject(CloudStackTypes.VolumeObjectTO, destVolumeObjectTO); - newData = ansObj; - result = true; - } - } - else if (srcVolumeObjectTO != null && destVolumeObjectTO != null) - { - var guessedDestFile = destVolumeObjectTO.FullFileName; - if (File.Exists(guessedDestFile)) - { - logger.Info("Deleting existing file " + guessedDestFile); - File.Delete(guessedDestFile); - } - - destVolumeObjectTO.format = srcVolumeObjectTO.format; - destFile = destVolumeObjectTO.FullFileName; - if (File.Exists(destFile)) - { - logger.Info("Deleting existing file " + destFile); - File.Delete(destFile); - } - - string srcFile = srcVolumeObjectTO.FullFileName; - if (!File.Exists(srcFile)) - { - details = "Local template file missing from " + srcFile; - } - else - { - // Create the directory before copying the files. CreateDirectory - // doesn't do anything if the directory is already present. - Directory.CreateDirectory(Path.GetDirectoryName(destFile)); - File.Copy(srcFile, destFile); - - if (srcVolumeObjectTO.nfsDataStore != null && srcVolumeObjectTO.primaryDataStore == null) - { - logger.Info("Copied volume from secondary data store to primary. Path: " + destVolumeObjectTO.path); - } - else if (srcVolumeObjectTO.primaryDataStore != null && srcVolumeObjectTO.nfsDataStore == null) - { - destVolumeObjectTO.path = destVolumeObjectTO.path + "/" + destVolumeObjectTO.uuid; - if (destVolumeObjectTO.format != null) - { - destVolumeObjectTO.path += "." + destVolumeObjectTO.format.ToLower(); - } - } - else - { - logger.Error("Destination volume path wasn't set. Unsupported source volume data store."); - } - - // Create volumeto object deserialize and send it - JObject ansObj = Utils.CreateCloudStackObject(CloudStackTypes.VolumeObjectTO, destVolumeObjectTO); - newData = ansObj; - result = true; - } - } - else if (srcVolumeObjectTO != null && destTemplateObjectTO != null) - { - var guessedDestFile = destTemplateObjectTO.FullFileName; - if (File.Exists(guessedDestFile)) - { - logger.Info("Deleting existing file " + guessedDestFile); - File.Delete(guessedDestFile); - } - - destTemplateObjectTO.format = srcVolumeObjectTO.format; - destFile = destTemplateObjectTO.FullFileName; - if (File.Exists(destFile)) - { - logger.Info("Deleting existing file " + destFile); - File.Delete(destFile); - } - - string srcFile = srcVolumeObjectTO.FullFileName; - if (!File.Exists(srcFile)) - { - details = "Local template file missing from " + srcFile; - } - else - { - // Create the directory before copying the files. CreateDirectory - // doesn't do anything if the directory is already present. - Directory.CreateDirectory(Path.GetDirectoryName(destFile)); - File.Copy(srcFile, destFile); - - FileInfo destFileInfo = new FileInfo(destFile); - // Write the template.properties file - PostCreateTemplate(Path.GetDirectoryName(destFile), destTemplateObjectTO.id, destTemplateObjectTO.name, - destFileInfo.Length.ToString(), srcVolumeObjectTO.size.ToString(), destTemplateObjectTO.format); - - TemplateObjectTO destTemplateObject = new TemplateObjectTO(); - destTemplateObject.size = srcVolumeObjectTO.size.ToString(); - destTemplateObject.format = srcVolumeObjectTO.format; - destTemplateObject.path = destTemplateObjectTO.path + "/" + destTemplateObjectTO.uuid; - if (destTemplateObject.format != null) - { - destTemplateObject.path += "." + destTemplateObject.format.ToLower(); - } - destTemplateObject.nfsDataStoreTO = destTemplateObjectTO.nfsDataStoreTO; - destTemplateObject.checksum = destTemplateObjectTO.checksum; - newData = destTemplateObject; - JObject ansObj = Utils.CreateCloudStackObject(CloudStackTypes.TemplateObjectTO, destTemplateObject); - newData = ansObj; - result = true; - } - } - else - { - details = "Data store combination not supported"; - } - } - } - catch (Exception ex) - { - // Test by providing wrong key - details = CloudStackTypes.CopyCommand + " failed on exception, " + ex.Message; - logger.Error(details, ex); - } - - object ansContent = new - { - result = result, - details = details, - newData = newData, - contextMap = contextMap - }; - return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.CopyCmdAnswer); - } - } - - private static void PostCreateTemplate(string path, string templateId, string templateUuid, string physicalSize, string virtualSize, string format) - { - string templatePropFile = Path.Combine(path, "template.properties"); - using (StreamWriter sw = new StreamWriter(File.Open(templatePropFile, FileMode.Create), Encoding.GetEncoding("iso-8859-1"))) - { - if (format != null) - { - format = format.ToLower(); - } - - sw.NewLine = "\n"; - sw.WriteLine("id=" + templateId); - sw.WriteLine("filename=" + templateUuid + "." + format); - sw.WriteLine(format + ".filename=" + templateUuid + "." + format); - sw.WriteLine("uniquename=" + templateUuid); - sw.WriteLine(format + "=true"); - sw.WriteLine("virtualsize=" + virtualSize); - sw.WriteLine(format + ".virtualsize=" + virtualSize); - sw.WriteLine("size=" + physicalSize); - sw.WriteLine(format + ".size=" + physicalSize); - sw.WriteLine("public=false"); - } - } - - private static bool VerifyChecksum(string destFile, string checksum) - { - string localChecksum = BitConverter.ToString(CalcFileChecksum(destFile)).Replace("-", "").ToLower(); - logger.Debug("Checksum of " + destFile + " is " + checksum); - if (checksum.Equals(localChecksum)) - { - return true; - } - return false; - } - - /// - /// Match implmentation of DownloadManagerImpl.computeCheckSum - /// - /// - /// - private static byte[] CalcFileChecksum(string destFile) - { - // TODO: Add unit test to verify that checksum algorithm has not changed. - using (MD5 md5 = MD5.Create()) - { - using (FileStream stream = File.OpenRead(destFile)) - { - return md5.ComputeHash(stream); - } - } - } - - private static void DownloadS3ObjectToFile(string srcObjectKey, S3TO srcS3TO, string destFile) - { - AmazonS3Config S3Config = new AmazonS3Config - { - ServiceURL = srcS3TO.endpoint, - CommunicationProtocol = Amazon.S3.Model.Protocol.HTTP - }; - - if (srcS3TO.httpsFlag) - { - S3Config.CommunicationProtocol = Protocol.HTTPS; - } - - try - { - using (AmazonS3 client = Amazon.AWSClientFactory.CreateAmazonS3Client(srcS3TO.accessKey, srcS3TO.secretKey, S3Config)) - { - GetObjectRequest getObjectRequest = new GetObjectRequest().WithBucketName(srcS3TO.bucketName).WithKey(srcObjectKey); - - using (S3Response getObjectResponse = client.GetObject(getObjectRequest)) - { - using (Stream s = getObjectResponse.ResponseStream) - { - using (FileStream fs = new FileStream(destFile, FileMode.Create, FileAccess.Write)) - { - byte[] data = new byte[524288]; - int bytesRead = 0; - do - { - bytesRead = s.Read(data, 0, data.Length); - fs.Write(data, 0, bytesRead); - } - while (bytesRead > 0); - fs.Flush(); - } - } - } - } - } - catch (Exception ex) - { - string errMsg = "Download from S3 url" + srcS3TO.endpoint + " said: " + ex.Message; - logger.Error(errMsg, ex); - throw new Exception(errMsg, ex); - } - } - - // POST api/HypervResource/GetStorageStatsCommand - [HttpPost] - [ActionName(CloudStackTypes.GetStorageStatsCommand)] - public JContainer GetStorageStatsCommand([FromBody]dynamic cmd) - { - using (log4net.NDC.Push(Guid.NewGuid().ToString())) - { - logger.Info(CloudStackTypes.GetStorageStatsCommand + Utils.CleanString(cmd.ToString())); - bool result = false; - string details = null; - long capacity = 0; - long available = 0; - long used = 0; - try - { - StoragePoolType poolType; - string hostPath = null; - if (!Enum.TryParse((string)cmd.pooltype, out poolType)) - { - details = "Request to get unsupported pool type: " + ((string)cmd.pooltype == null ? "NULL" : (string)cmd.pooltype) + "in cmd " + - JsonConvert.SerializeObject(cmd); - logger.Error(details); - } - else if (poolType == StoragePoolType.Filesystem) - { - hostPath = (string)cmd.localPath;; - GetCapacityForLocalPath(hostPath, out capacity, out available); - used = capacity - available; - result = true; - } - else if (poolType == StoragePoolType.NetworkFilesystem || poolType == StoragePoolType.SMB) - { - string sharePath = config.getPrimaryStorage((string)cmd.id); - if (sharePath != null) - { - hostPath = sharePath; - Utils.GetShareDetails(sharePath, out capacity, out available); - used = capacity - available; - result = true; - } - } - else - { - result = false; - } - - if (result) - { - logger.Debug(CloudStackTypes.GetStorageStatsCommand + " set used bytes for " + hostPath + " to " + used); - } - } - catch (Exception ex) - { - details = CloudStackTypes.GetStorageStatsCommand + " failed on exception" + ex.Message; - logger.Error(details, ex); - } - - object ansContent = new - { - result = result, - details = details, - capacity = capacity, - used = used, - contextMap = contextMap - }; - return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.GetStorageStatsAnswer); - } - } - - // POST api/HypervResource/GetHostStatsCommand - [HttpPost] - [ActionName(CloudStackTypes.GetHostStatsCommand)] - public JContainer GetHostStatsCommand([FromBody]dynamic cmd) - { - using (log4net.NDC.Push(Guid.NewGuid().ToString())) - { + bool result = false; + JArray vmNamesJson = cmd.vmNames; + string[] vmNames = vmNamesJson.ToObject(); + Dictionary vmProcessorInfo = new Dictionary(vmNames.Length); + + var vmsToInspect = new List(); + foreach (var vmName in vmNames) + { + var sys = wmiCallsV2.GetComputerSystem(vmName); + if (sys == null) + { + logger.InfoFormat("GetVmStatsCommand requested unknown VM {0}", vmNames); + continue; + } + var sysInfo = wmiCallsV2.GetVmSettings(sys); + vmsToInspect.Add(sysInfo.Path); + } + + wmiCallsV2.GetSummaryInfo(vmProcessorInfo, vmsToInspect); + + // TODO: Network usage comes from Performance Counter API; however it is only available in kb/s, and not in total terms. + // Curious about these? Use perfmon to inspect them, e.g. http://msdn.microsoft.com/en-us/library/xhcx5a20%28v=vs.100%29.aspx + // Recent post on these counter at http://blogs.technet.com/b/cedward/archive/2011/07/19/hyper-v-networking-optimizations-part-6-of-6-monitoring-hyper-v-network-consumption.aspx + result = true; + + object ansContent = new + { + vmStatsMap = vmProcessorInfo, + result = result, + contextMap = contextMap + }; + return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.GetVmStatsAnswer); + } + } + + // POST api/HypervResource/CopyCommand + [HttpPost] + [ActionName(CloudStackTypes.CopyCommand)] + public JContainer CopyCommand(dynamic cmd) + { + using (log4net.NDC.Push(Guid.NewGuid().ToString())) + { + // Log command *after* we've removed security details from the command. + logger.Info(CloudStackTypes.CopyCommand + Utils.CleanString(cmd.ToString())); + + bool result = false; + string details = null; + object newData = null; + TemplateObjectTO destTemplateObjectTO = null; + VolumeObjectTO destVolumeObjectTO = null; + VolumeObjectTO srcVolumeObjectTO = null; + TemplateObjectTO srcTemplateObjectTO = null; + + try + { + srcTemplateObjectTO = TemplateObjectTO.ParseJson(cmd.srcTO); + destTemplateObjectTO = TemplateObjectTO.ParseJson(cmd.destTO); + srcVolumeObjectTO = VolumeObjectTO.ParseJson(cmd.srcTO); + destVolumeObjectTO = VolumeObjectTO.ParseJson(cmd.destTO); + + string destFile = null; + if (destTemplateObjectTO != null) + { + if (destTemplateObjectTO.primaryDataStore != null) + { + destFile = destTemplateObjectTO.FullFileName; + if (!destTemplateObjectTO.primaryDataStore.isLocal) + { + PrimaryDataStoreTO primary = destTemplateObjectTO.primaryDataStore; + Utils.ConnectToRemote(primary.UncPath, primary.Domain, primary.User, primary.Password); + } + } + else if (destTemplateObjectTO.nfsDataStoreTO != null) + { + destFile = destTemplateObjectTO.FullFileName; + NFSTO store = destTemplateObjectTO.nfsDataStoreTO; + Utils.ConnectToRemote(store.UncPath, store.Domain, store.User, store.Password); + } + } + + // Template already downloaded? + if (destFile != null && File.Exists(destFile) && + !String.IsNullOrEmpty(destTemplateObjectTO.checksum)) + { + // TODO: checksum fails us, because it is of the compressed image. + // ASK: should we store the compressed or uncompressed version or is the checksum not calculated correctly? + logger.Debug(CloudStackTypes.CopyCommand + " calling VerifyChecksum to see if we already have the file at " + destFile); + result = VerifyChecksum(destFile, destTemplateObjectTO.checksum); + if (!result) + { + result = true; + logger.Debug(CloudStackTypes.CopyCommand + " existing file has different checksum " + destFile); + } + } + + // Do we have to create a new one? + if (!result) + { + // Create local copy of a template? + if (srcTemplateObjectTO != null && destTemplateObjectTO != null) + { + // S3 download to primary storage? + // NFS provider download to primary storage? + if ((srcTemplateObjectTO.s3DataStoreTO != null || srcTemplateObjectTO.nfsDataStoreTO != null) && destTemplateObjectTO.primaryDataStore != null) + { + if (File.Exists(destFile)) + { + logger.Info("Deleting existing file " + destFile); + File.Delete(destFile); + } + + if (srcTemplateObjectTO.s3DataStoreTO != null) + { + // Download from S3 to destination data storage + DownloadS3ObjectToFile(srcTemplateObjectTO.path, srcTemplateObjectTO.s3DataStoreTO, destFile); + } + else if (srcTemplateObjectTO.nfsDataStoreTO != null) + { + // Download from S3 to destination data storage + Utils.DownloadCifsFileToLocalFile(srcTemplateObjectTO.path, srcTemplateObjectTO.nfsDataStoreTO, destFile); + } + + // Uncompress, as required + if (srcTemplateObjectTO.path.EndsWith(".bz2")) + { + String uncompressedFile = destFile + ".tmp"; + String compressedFile = destFile; + using (var uncompressedOutStrm = new FileStream(uncompressedFile, FileMode.CreateNew, FileAccess.Write)) + { + using (var compressedInStrm = new FileStream(destFile, FileMode.Open, FileAccess.Read)) + { + using (var bz2UncompressorStrm = new Ionic.BZip2.BZip2InputStream(compressedInStrm, true) /* outer 'using' statement will close FileStream*/ ) + { + int count = 0; + int bufsize = 1024 * 1024; + byte[] buf = new byte[bufsize]; + + // EOF returns -1, see http://dotnetzip.codeplex.com/workitem/16069 + while (0 < (count = bz2UncompressorStrm.Read(buf, 0, bufsize))) + { + uncompressedOutStrm.Write(buf, 0, count); + } + } + } + } + File.Delete(compressedFile); + File.Move(uncompressedFile, compressedFile); + if (File.Exists(uncompressedFile)) + { + String errMsg = "Extra file left around called " + uncompressedFile + " when creating " + destFile; + logger.Error(errMsg); + throw new IOException(errMsg); + } + } + + // assert + if (!File.Exists(destFile)) + { + String errMsg = "Failed to create " + destFile + " , because the file is missing"; + logger.Error(errMsg); + throw new IOException(errMsg); + } + + newData = cmd.destTO; + result = true; + } + else + { + details = "Data store combination not supported"; + } + } + // Create volume from a template? + else if (srcTemplateObjectTO != null && destVolumeObjectTO != null) + { + // VolumeObjectTO guesses file extension based on existing files + // this can be wrong if the previous file had a different file type + var guessedDestFile = destVolumeObjectTO.FullFileName; + if (File.Exists(guessedDestFile)) + { + logger.Info("Deleting existing file " + guessedDestFile); + File.Delete(guessedDestFile); + } + + destVolumeObjectTO.format = srcTemplateObjectTO.format; + destFile = destVolumeObjectTO.FullFileName; + if (File.Exists(destFile)) + { + logger.Info("Deleting existing file " + destFile); + File.Delete(destFile); + } + + string srcFile = srcTemplateObjectTO.FullFileName; + if (!File.Exists(srcFile)) + { + details = "Local template file missing from " + srcFile; + } + else + { + // TODO: thin provision instead of copying the full file. + File.Copy(srcFile, destFile); + destVolumeObjectTO.path = destVolumeObjectTO.uuid; + JObject ansObj = Utils.CreateCloudStackObject(CloudStackTypes.VolumeObjectTO, destVolumeObjectTO); + newData = ansObj; + result = true; + } + } + else if (srcVolumeObjectTO != null && destVolumeObjectTO != null) + { + var guessedDestFile = destVolumeObjectTO.FullFileName; + if (File.Exists(guessedDestFile)) + { + logger.Info("Deleting existing file " + guessedDestFile); + File.Delete(guessedDestFile); + } + + destVolumeObjectTO.format = srcVolumeObjectTO.format; + destFile = destVolumeObjectTO.FullFileName; + if (File.Exists(destFile)) + { + logger.Info("Deleting existing file " + destFile); + File.Delete(destFile); + } + + string srcFile = srcVolumeObjectTO.FullFileName; + if (!File.Exists(srcFile)) + { + details = "Local template file missing from " + srcFile; + } + else + { + // Create the directory before copying the files. CreateDirectory + // doesn't do anything if the directory is already present. + Directory.CreateDirectory(Path.GetDirectoryName(destFile)); + File.Copy(srcFile, destFile); + + if (srcVolumeObjectTO.nfsDataStore != null && srcVolumeObjectTO.primaryDataStore == null) + { + logger.Info("Copied volume from secondary data store to primary. Path: " + destVolumeObjectTO.path); + } + else if (srcVolumeObjectTO.primaryDataStore != null && srcVolumeObjectTO.nfsDataStore == null) + { + destVolumeObjectTO.path = destVolumeObjectTO.path + "/" + destVolumeObjectTO.uuid; + if (destVolumeObjectTO.format != null) + { + destVolumeObjectTO.path += "." + destVolumeObjectTO.format.ToLower(); + } + } + else + { + logger.Error("Destination volume path wasn't set. Unsupported source volume data store."); + } + + // Create volumeto object deserialize and send it + JObject ansObj = Utils.CreateCloudStackObject(CloudStackTypes.VolumeObjectTO, destVolumeObjectTO); + newData = ansObj; + result = true; + } + } + else if (srcVolumeObjectTO != null && destTemplateObjectTO != null) + { + var guessedDestFile = destTemplateObjectTO.FullFileName; + if (File.Exists(guessedDestFile)) + { + logger.Info("Deleting existing file " + guessedDestFile); + File.Delete(guessedDestFile); + } + + destTemplateObjectTO.format = srcVolumeObjectTO.format; + destFile = destTemplateObjectTO.FullFileName; + if (File.Exists(destFile)) + { + logger.Info("Deleting existing file " + destFile); + File.Delete(destFile); + } + + string srcFile = srcVolumeObjectTO.FullFileName; + if (!File.Exists(srcFile)) + { + details = "Local template file missing from " + srcFile; + } + else + { + // Create the directory before copying the files. CreateDirectory + // doesn't do anything if the directory is already present. + Directory.CreateDirectory(Path.GetDirectoryName(destFile)); + File.Copy(srcFile, destFile); + + FileInfo destFileInfo = new FileInfo(destFile); + // Write the template.properties file + PostCreateTemplate(Path.GetDirectoryName(destFile), destTemplateObjectTO.id, destTemplateObjectTO.name, + destFileInfo.Length.ToString(), srcVolumeObjectTO.size.ToString(), destTemplateObjectTO.format); + + TemplateObjectTO destTemplateObject = new TemplateObjectTO(); + destTemplateObject.size = srcVolumeObjectTO.size.ToString(); + destTemplateObject.format = srcVolumeObjectTO.format; + destTemplateObject.path = destTemplateObjectTO.path + "/" + destTemplateObjectTO.uuid; + if (destTemplateObject.format != null) + { + destTemplateObject.path += "." + destTemplateObject.format.ToLower(); + } + destTemplateObject.nfsDataStoreTO = destTemplateObjectTO.nfsDataStoreTO; + destTemplateObject.checksum = destTemplateObjectTO.checksum; + newData = destTemplateObject; + JObject ansObj = Utils.CreateCloudStackObject(CloudStackTypes.TemplateObjectTO, destTemplateObject); + newData = ansObj; + result = true; + } + } + else + { + details = "Data store combination not supported"; + } + } + } + catch (Exception ex) + { + // Test by providing wrong key + details = CloudStackTypes.CopyCommand + " failed on exception, " + ex.Message; + logger.Error(details, ex); + } + + object ansContent = new + { + result = result, + details = details, + newData = newData, + contextMap = contextMap + }; + return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.CopyCmdAnswer); + } + } + + private static void PostCreateTemplate(string path, string templateId, string templateUuid, string physicalSize, string virtualSize, string format) + { + string templatePropFile = Path.Combine(path, "template.properties"); + using (StreamWriter sw = new StreamWriter(File.Open(templatePropFile, FileMode.Create), Encoding.GetEncoding("iso-8859-1"))) + { + if (format != null) + { + format = format.ToLower(); + } + + sw.NewLine = "\n"; + sw.WriteLine("id=" + templateId); + sw.WriteLine("filename=" + templateUuid + "." + format); + sw.WriteLine(format + ".filename=" + templateUuid + "." + format); + sw.WriteLine("uniquename=" + templateUuid); + sw.WriteLine(format + "=true"); + sw.WriteLine("virtualsize=" + virtualSize); + sw.WriteLine(format + ".virtualsize=" + virtualSize); + sw.WriteLine("size=" + physicalSize); + sw.WriteLine(format + ".size=" + physicalSize); + sw.WriteLine("public=false"); + } + } + + private static bool VerifyChecksum(string destFile, string checksum) + { + string localChecksum = BitConverter.ToString(CalcFileChecksum(destFile)).Replace("-", "").ToLower(); + logger.Debug("Checksum of " + destFile + " is " + checksum); + if (checksum.Equals(localChecksum)) + { + return true; + } + return false; + } + + /// + /// Match implmentation of DownloadManagerImpl.computeCheckSum + /// + /// + /// + private static byte[] CalcFileChecksum(string destFile) + { + // TODO: Add unit test to verify that checksum algorithm has not changed. + using (MD5 md5 = MD5.Create()) + { + using (FileStream stream = File.OpenRead(destFile)) + { + return md5.ComputeHash(stream); + } + } + } + + private static void DownloadS3ObjectToFile(string srcObjectKey, S3TO srcS3TO, string destFile) + { + AmazonS3Config S3Config = new AmazonS3Config + { + ServiceURL = srcS3TO.endpoint, + CommunicationProtocol = Amazon.S3.Model.Protocol.HTTP + }; + + if (srcS3TO.httpsFlag) + { + S3Config.CommunicationProtocol = Protocol.HTTPS; + } + + try + { + using (AmazonS3 client = Amazon.AWSClientFactory.CreateAmazonS3Client(srcS3TO.accessKey, srcS3TO.secretKey, S3Config)) + { + GetObjectRequest getObjectRequest = new GetObjectRequest().WithBucketName(srcS3TO.bucketName).WithKey(srcObjectKey); + + using (S3Response getObjectResponse = client.GetObject(getObjectRequest)) + { + using (Stream s = getObjectResponse.ResponseStream) + { + using (FileStream fs = new FileStream(destFile, FileMode.Create, FileAccess.Write)) + { + byte[] data = new byte[524288]; + int bytesRead = 0; + do + { + bytesRead = s.Read(data, 0, data.Length); + fs.Write(data, 0, bytesRead); + } + while (bytesRead > 0); + fs.Flush(); + } + } + } + } + } + catch (Exception ex) + { + string errMsg = "Download from S3 url" + srcS3TO.endpoint + " said: " + ex.Message; + logger.Error(errMsg, ex); + throw new Exception(errMsg, ex); + } + } + + // POST api/HypervResource/GetStorageStatsCommand + [HttpPost] + [ActionName(CloudStackTypes.GetStorageStatsCommand)] + public JContainer GetStorageStatsCommand([FromBody]dynamic cmd) + { + using (log4net.NDC.Push(Guid.NewGuid().ToString())) + { + logger.Info(CloudStackTypes.GetStorageStatsCommand + Utils.CleanString(cmd.ToString())); + bool result = false; + string details = null; + long capacity = 0; + long available = 0; + long used = 0; + try + { + StoragePoolType poolType; + string hostPath = null; + if (!Enum.TryParse((string)cmd.pooltype, out poolType)) + { + details = "Request to get unsupported pool type: " + ((string)cmd.pooltype == null ? "NULL" : (string)cmd.pooltype) + "in cmd " + + JsonConvert.SerializeObject(cmd); + logger.Error(details); + } + else if (poolType == StoragePoolType.Filesystem) + { + hostPath = (string)cmd.localPath;; + GetCapacityForLocalPath(hostPath, out capacity, out available); + used = capacity - available; + result = true; + } + else if (poolType == StoragePoolType.NetworkFilesystem || poolType == StoragePoolType.SMB) + { + string sharePath = config.getPrimaryStorage((string)cmd.id); + if (sharePath != null) + { + hostPath = sharePath; + Utils.GetShareDetails(sharePath, out capacity, out available); + used = capacity - available; + result = true; + } + } + else + { + result = false; + } + + if (result) + { + logger.Debug(CloudStackTypes.GetStorageStatsCommand + " set used bytes for " + hostPath + " to " + used); + } + } + catch (Exception ex) + { + details = CloudStackTypes.GetStorageStatsCommand + " failed on exception" + ex.Message; + logger.Error(details, ex); + } + + object ansContent = new + { + result = result, + details = details, + capacity = capacity, + used = used, + contextMap = contextMap + }; + return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.GetStorageStatsAnswer); + } + } + + // POST api/HypervResource/GetHostStatsCommand + [HttpPost] + [ActionName(CloudStackTypes.GetHostStatsCommand)] + public JContainer GetHostStatsCommand([FromBody]dynamic cmd) + { + using (log4net.NDC.Push(Guid.NewGuid().ToString())) + { logger.Info(CloudStackTypes.GetHostStatsCommand + Utils.CleanString(cmd.ToString())); - bool result = false; - string details = null; - object hostStats = null; - - var entityType = "host"; - ulong totalMemoryKBs; - ulong freeMemoryKBs; - double networkReadKBs; - double networkWriteKBs; - double cpuUtilization; - - try - { - long hostId = (long)cmd.hostId; - wmiCallsV2.GetMemoryResources(out totalMemoryKBs, out freeMemoryKBs); - wmiCallsV2.GetProcessorUsageInfo(out cpuUtilization); - - // TODO: can we assume that the host has only one adaptor? - string tmp; - var privateNic = GetNicInfoFromIpAddress(config.PrivateIpAddress, out tmp); - var nicStats = privateNic.GetIPv4Statistics(); //TODO: add IPV6 support, currentl - networkReadKBs = nicStats.BytesReceived; - networkWriteKBs = nicStats.BytesSent; - - // Generate GetHostStatsAnswer - hostStats = new - { - hostId = hostId, - entityType = entityType, - cpuUtilization = cpuUtilization, - networkReadKBs = networkReadKBs, - networkWriteKBs = networkWriteKBs, - totalMemoryKBs = (double)totalMemoryKBs, - freeMemoryKBs = (double)freeMemoryKBs - }; - result = true; - } - catch (Exception ex) - { - details = CloudStackTypes.GetHostStatsCommand + " failed on exception" + ex.Message; - logger.Error(details, ex); - } - - object ansContent = new - { - result = result, - hostStats = hostStats, - details = details, - contextMap = contextMap - }; - return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.GetHostStatsAnswer); - } - } - - // POST api/HypervResource/PrepareForMigrationCommand - [HttpPost] - [ActionName(CloudStackTypes.PrepareForMigrationCommand)] - public JContainer PrepareForMigrationCommand([FromBody]dynamic cmd) - { - using (log4net.NDC.Push(Guid.NewGuid().ToString())) - { + bool result = false; + string details = null; + object hostStats = null; + + var entityType = "host"; + ulong totalMemoryKBs; + ulong freeMemoryKBs; + double networkReadKBs; + double networkWriteKBs; + double cpuUtilization; + + try + { + long hostId = (long)cmd.hostId; + wmiCallsV2.GetMemoryResources(out totalMemoryKBs, out freeMemoryKBs); + wmiCallsV2.GetProcessorUsageInfo(out cpuUtilization); + + // TODO: can we assume that the host has only one adaptor? + string tmp; + var privateNic = GetNicInfoFromIpAddress(config.PrivateIpAddress, out tmp); + var nicStats = privateNic.GetIPv4Statistics(); //TODO: add IPV6 support, currentl + networkReadKBs = nicStats.BytesReceived; + networkWriteKBs = nicStats.BytesSent; + + // Generate GetHostStatsAnswer + hostStats = new + { + hostId = hostId, + entityType = entityType, + cpuUtilization = cpuUtilization, + networkReadKBs = networkReadKBs, + networkWriteKBs = networkWriteKBs, + totalMemoryKBs = (double)totalMemoryKBs, + freeMemoryKBs = (double)freeMemoryKBs + }; + result = true; + } + catch (Exception ex) + { + details = CloudStackTypes.GetHostStatsCommand + " failed on exception" + ex.Message; + logger.Error(details, ex); + } + + object ansContent = new + { + result = result, + hostStats = hostStats, + details = details, + contextMap = contextMap + }; + return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.GetHostStatsAnswer); + } + } + + // POST api/HypervResource/PrepareForMigrationCommand + [HttpPost] + [ActionName(CloudStackTypes.PrepareForMigrationCommand)] + public JContainer PrepareForMigrationCommand([FromBody]dynamic cmd) + { + using (log4net.NDC.Push(Guid.NewGuid().ToString())) + { logger.Info(CloudStackTypes.PrepareForMigrationCommand + Utils.CleanString(cmd.ToString())); - - string details = null; - bool result = true; - - try - { - details = "NOP - success"; - } - catch (Exception sysEx) - { - result = false; - details = CloudStackTypes.PrepareForMigrationCommand + " failed due to " + sysEx.Message; - logger.Error(details, sysEx); - } - - object ansContent = new - { - result = result, - details = details, - contextMap = contextMap - }; - - return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.PrepareForMigrationAnswer); - } - } - - // POST api/HypervResource/MigrateCommand - [HttpPost] - [ActionName(CloudStackTypes.MigrateCommand)] - public JContainer MigrateCommand([FromBody]dynamic cmd) - { - using (log4net.NDC.Push(Guid.NewGuid().ToString())) - { + + string details = null; + bool result = true; + + try + { + details = "NOP - success"; + } + catch (Exception sysEx) + { + result = false; + details = CloudStackTypes.PrepareForMigrationCommand + " failed due to " + sysEx.Message; + logger.Error(details, sysEx); + } + + object ansContent = new + { + result = result, + details = details, + contextMap = contextMap + }; + + return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.PrepareForMigrationAnswer); + } + } + + // POST api/HypervResource/MigrateCommand + [HttpPost] + [ActionName(CloudStackTypes.MigrateCommand)] + public JContainer MigrateCommand([FromBody]dynamic cmd) + { + using (log4net.NDC.Push(Guid.NewGuid().ToString())) + { logger.Info(CloudStackTypes.MigrateCommand + Utils.CleanString(cmd.ToString())); - - string details = null; - bool result = false; - - try - { - string vm = (string)cmd.vmName; - string destination = (string)cmd.destIp; - wmiCallsV2.MigrateVm(vm, destination); - result = true; - } - catch (Exception sysEx) - { - details = CloudStackTypes.MigrateCommand + " failed due to " + sysEx.Message; - logger.Error(details, sysEx); - } - - object ansContent = new - { - result = result, - details = details, - contextMap = contextMap - }; - - return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.MigrateAnswer); - } - } - - // POST api/HypervResource/MigrateVolumeCommand - [HttpPost] - [ActionName(CloudStackTypes.MigrateVolumeCommand)] - public JContainer MigrateVolumeCommand([FromBody]dynamic cmd) - { - using (log4net.NDC.Push(Guid.NewGuid().ToString())) - { + + string details = null; + bool result = false; + + try + { + string vm = (string)cmd.vmName; + string destination = (string)cmd.destIp; + wmiCallsV2.MigrateVm(vm, destination); + result = true; + } + catch (Exception sysEx) + { + details = CloudStackTypes.MigrateCommand + " failed due to " + sysEx.Message; + logger.Error(details, sysEx); + } + + object ansContent = new + { + result = result, + details = details, + contextMap = contextMap + }; + + return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.MigrateAnswer); + } + } + + // POST api/HypervResource/MigrateVolumeCommand + [HttpPost] + [ActionName(CloudStackTypes.MigrateVolumeCommand)] + public JContainer MigrateVolumeCommand([FromBody]dynamic cmd) + { + using (log4net.NDC.Push(Guid.NewGuid().ToString())) + { logger.Info(CloudStackTypes.MigrateVolumeCommand + Utils.CleanString(cmd.ToString())); - - string details = null; - bool result = false; - - try - { - string vm = (string)cmd.attachedVmName; - string volume = (string)cmd.volumePath; - wmiCallsV2.MigrateVolume(vm, volume, GetStoragePoolPath(cmd.pool)); - result = true; - } - catch (Exception sysEx) - { - details = CloudStackTypes.MigrateVolumeCommand + " failed due to " + sysEx.Message; - logger.Error(details, sysEx); - } - - object ansContent = new - { - result = result, - volumePath = (string)cmd.volumePath, - details = details, - contextMap = contextMap - }; - - return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.MigrateVolumeAnswer); - } - } - - // POST api/HypervResource/MigrateWithStorageCommand - [HttpPost] - [ActionName(CloudStackTypes.MigrateWithStorageCommand)] - public JContainer MigrateWithStorageCommand([FromBody]dynamic cmd) - { - using (log4net.NDC.Push(Guid.NewGuid().ToString())) - { + + string details = null; + bool result = false; + + try + { + string vm = (string)cmd.attachedVmName; + string volume = (string)cmd.volumePath; + wmiCallsV2.MigrateVolume(vm, volume, GetStoragePoolPath(cmd.pool)); + result = true; + } + catch (Exception sysEx) + { + details = CloudStackTypes.MigrateVolumeCommand + " failed due to " + sysEx.Message; + logger.Error(details, sysEx); + } + + object ansContent = new + { + result = result, + volumePath = (string)cmd.volumePath, + details = details, + contextMap = contextMap + }; + + return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.MigrateVolumeAnswer); + } + } + + // POST api/HypervResource/MigrateWithStorageCommand + [HttpPost] + [ActionName(CloudStackTypes.MigrateWithStorageCommand)] + public JContainer MigrateWithStorageCommand([FromBody]dynamic cmd) + { + using (log4net.NDC.Push(Guid.NewGuid().ToString())) + { logger.Info(CloudStackTypes.MigrateWithStorageCommand + Utils.CleanString(cmd.ToString())); - - string details = null; - bool result = false; - List volumeTos = new List(); - - try - { - string vm = (string)cmd.vm.name; - string destination = (string)cmd.tgtHost; - var volumeToPoolList = cmd.volumeToFilerAsList; - var volumeToPool = new Dictionary(); - foreach (var item in volumeToPoolList) - { - volumeTos.Add(item.t); - string poolPath = GetStoragePoolPath(item.u); - volumeToPool.Add((string)item.t.path, poolPath); - } - - wmiCallsV2.MigrateVmWithVolume(vm, destination, volumeToPool); - result = true; - } - catch (Exception sysEx) - { - details = CloudStackTypes.MigrateWithStorageCommand + " failed due to " + sysEx.Message; - logger.Error(details, sysEx); - } - - object ansContent = new - { - result = result, - volumeTos = JArray.FromObject(volumeTos), - details = details, - contextMap = contextMap - }; - - return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.MigrateWithStorageAnswer); - } - } - - private string GetStoragePoolPath(dynamic pool) - { - string poolTypeStr = pool.type; - StoragePoolType poolType; - if (!Enum.TryParse(poolTypeStr, out poolType)) - { - throw new ArgumentException("Invalid pool type " + poolTypeStr); - } - else if (poolType == StoragePoolType.SMB) - { - NFSTO share = new NFSTO(); - String uriStr = "cifs://" + (string)pool.host + (string)pool.path; - share.uri = new Uri(uriStr); - return Utils.NormalizePath(share.UncPath); - } - else if (poolType == StoragePoolType.Filesystem) - { - return pool.path; - } - - throw new ArgumentException("Couldn't parse path for pool type " + poolTypeStr); - } - - // POST api/HypervResource/StartupCommand - [HttpPost] - [ActionName(CloudStackTypes.StartupCommand)] - public JContainer StartupCommand([FromBody]dynamic cmdArray) - { - using (log4net.NDC.Push(Guid.NewGuid().ToString())) - { - logger.Info(cmdArray.ToString()); - // Log agent configuration - logger.Info("Agent StartupRoutingCommand received " + cmdArray.ToString()); - dynamic strtRouteCmd = cmdArray[0][CloudStackTypes.StartupRoutingCommand]; - - // Insert networking details - string privateIpAddress = strtRouteCmd.privateIpAddress; + + string details = null; + bool result = false; + List volumeTos = new List(); + + try + { + string vm = (string)cmd.vm.name; + string destination = (string)cmd.tgtHost; + var volumeToPoolList = cmd.volumeToFilerAsList; + var volumeToPool = new Dictionary(); + foreach (var item in volumeToPoolList) + { + volumeTos.Add(item.t); + string poolPath = GetStoragePoolPath(item.u); + volumeToPool.Add((string)item.t.path, poolPath); + } + + wmiCallsV2.MigrateVmWithVolume(vm, destination, volumeToPool); + result = true; + } + catch (Exception sysEx) + { + details = CloudStackTypes.MigrateWithStorageCommand + " failed due to " + sysEx.Message; + logger.Error(details, sysEx); + } + + object ansContent = new + { + result = result, + volumeTos = JArray.FromObject(volumeTos), + details = details, + contextMap = contextMap + }; + + return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.MigrateWithStorageAnswer); + } + } + + private string GetStoragePoolPath(dynamic pool) + { + string poolTypeStr = pool.type; + StoragePoolType poolType; + if (!Enum.TryParse(poolTypeStr, out poolType)) + { + throw new ArgumentException("Invalid pool type " + poolTypeStr); + } + else if (poolType == StoragePoolType.SMB) + { + NFSTO share = new NFSTO(); + String uriStr = "cifs://" + (string)pool.host + (string)pool.path; + share.uri = new Uri(uriStr); + return Utils.NormalizePath(share.UncPath); + } + else if (poolType == StoragePoolType.Filesystem) + { + return pool.path; + } + + throw new ArgumentException("Couldn't parse path for pool type " + poolTypeStr); + } + + // POST api/HypervResource/StartupCommand + [HttpPost] + [ActionName(CloudStackTypes.StartupCommand)] + public JContainer StartupCommand([FromBody]dynamic cmdArray) + { + using (log4net.NDC.Push(Guid.NewGuid().ToString())) + { + logger.Info(cmdArray.ToString()); + // Log agent configuration + logger.Info("Agent StartupRoutingCommand received " + cmdArray.ToString()); + dynamic strtRouteCmd = cmdArray[0][CloudStackTypes.StartupRoutingCommand]; + + // Insert networking details + string privateIpAddress = strtRouteCmd.privateIpAddress; config.PrivateIpAddress = privateIpAddress; - string subnet; - System.Net.NetworkInformation.NetworkInterface privateNic = GetNicInfoFromIpAddress(privateIpAddress, out subnet); - strtRouteCmd.privateIpAddress = privateIpAddress; - strtRouteCmd.privateNetmask = subnet; - strtRouteCmd.privateMacAddress = privateNic.GetPhysicalAddress().ToString(); - string storageip = strtRouteCmd.storageIpAddress; - System.Net.NetworkInformation.NetworkInterface storageNic = GetNicInfoFromIpAddress(storageip, out subnet); - - strtRouteCmd.storageIpAddress = storageip; - strtRouteCmd.storageNetmask = subnet; - strtRouteCmd.storageMacAddress = storageNic.GetPhysicalAddress().ToString(); - strtRouteCmd.gatewayIpAddress = storageNic.GetPhysicalAddress().ToString(); - strtRouteCmd.hypervisorVersion = System.Environment.OSVersion.Version.Major.ToString() + "." + + string subnet; + System.Net.NetworkInformation.NetworkInterface privateNic = GetNicInfoFromIpAddress(privateIpAddress, out subnet); + strtRouteCmd.privateIpAddress = privateIpAddress; + strtRouteCmd.privateNetmask = subnet; + strtRouteCmd.privateMacAddress = privateNic.GetPhysicalAddress().ToString(); + string storageip = strtRouteCmd.storageIpAddress; + System.Net.NetworkInformation.NetworkInterface storageNic = GetNicInfoFromIpAddress(storageip, out subnet); + + strtRouteCmd.storageIpAddress = storageip; + strtRouteCmd.storageNetmask = subnet; + strtRouteCmd.storageMacAddress = storageNic.GetPhysicalAddress().ToString(); + strtRouteCmd.gatewayIpAddress = storageNic.GetPhysicalAddress().ToString(); + strtRouteCmd.hypervisorVersion = System.Environment.OSVersion.Version.Major.ToString() + "." + System.Environment.OSVersion.Version.Minor.ToString(); - strtRouteCmd.caps = "hvm"; - - dynamic details = strtRouteCmd.hostDetails; - if (details != null) - { - string productVersion = System.Environment.OSVersion.Version.Major.ToString() + "." + - System.Environment.OSVersion.Version.Minor.ToString(); - details.Add("product_version", productVersion); + strtRouteCmd.caps = "hvm"; + + dynamic details = strtRouteCmd.hostDetails; + if (details != null) + { + string productVersion = System.Environment.OSVersion.Version.Major.ToString() + "." + + System.Environment.OSVersion.Version.Minor.ToString(); + details.Add("product_version", productVersion); details.Add("rdp.server.port", 2179); - } - - // Detect CPUs, speed, memory - uint cores; - uint mhz; - uint sockets; - wmiCallsV2.GetProcessorResources(out sockets, out cores, out mhz); - strtRouteCmd.cpus = cores; - strtRouteCmd.speed = mhz; - strtRouteCmd.cpuSockets = sockets; - ulong memoryKBs; - ulong freeMemoryKBs; - wmiCallsV2.GetMemoryResources(out memoryKBs, out freeMemoryKBs); - strtRouteCmd.memory = memoryKBs * 1024; // Convert to bytes - - // Need 2 Gig for DOM0, see http://technet.microsoft.com/en-us/magazine/hh750394.aspx - strtRouteCmd.dom0MinMemory = config.ParentPartitionMinMemoryMb * 1024 * 1024; // Convert to bytes - - // Insert storage pool details. - // - // Read the localStoragePath for virtual disks from the Hyper-V configuration - // See http://blogs.msdn.com/b/virtual_pc_guy/archive/2010/05/06/managing-the-default-virtual-machine-location-with-hyper-v.aspx - // for discussion of Hyper-V file locations paths. - string localStoragePath = wmiCallsV2.GetDefaultVirtualDiskFolder(); - if (localStoragePath != null) - { - // GUID arbitrary. Host agents deals with storage pool in terms of localStoragePath. - // We use HOST guid. - string poolGuid = strtRouteCmd.guid; - - if (poolGuid == null) - { - poolGuid = Guid.NewGuid().ToString(); - logger.InfoFormat("Setting Startup StoragePool GUID to " + poolGuid); - } - else - { - logger.InfoFormat("Setting Startup StoragePool GUID same as HOST, i.e. " + poolGuid); - } - - long capacity; - long available; - GetCapacityForLocalPath(localStoragePath, out capacity, out available); - - logger.Debug(CloudStackTypes.StartupStorageCommand + " set available bytes to " + available); - - string ipAddr = strtRouteCmd.privateIpAddress; - var vmStates = wmiCallsV2.GetVmSync(config.PrivateIpAddress); - strtRouteCmd.vms = Utils.CreateCloudStackMapObject(vmStates); - - StoragePoolInfo pi = new StoragePoolInfo( - poolGuid.ToString(), - ipAddr, - localStoragePath, - localStoragePath, - StoragePoolType.Filesystem.ToString(), - capacity, - available); - - // Build StartupStorageCommand using an anonymous type - // See http://stackoverflow.com/a/6029228/939250 - object ansContent = new - { - poolInfo = pi, - guid = pi.uuid, - dataCenter = strtRouteCmd.dataCenter, - resourceType = StorageResourceType.STORAGE_POOL.ToString(), // TODO: check encoding - contextMap = contextMap - }; - JObject ansObj = Utils.CreateCloudStackObject(CloudStackTypes.StartupStorageCommand, ansContent); - cmdArray.Add(ansObj); - } - - // Convert result to array for type correctness? - logger.Info(CloudStackTypes.StartupCommand + " result is " + cmdArray.ToString()); - return cmdArray; - } - } - - // POST api/HypervResource/GetVncPortCommand - [HttpPost] - [ActionName(CloudStackTypes.GetVncPortCommand)] - public JContainer GetVncPortCommand([FromBody]dynamic cmd) - { - using (log4net.NDC.Push(Guid.NewGuid().ToString())) - { + } + + // Detect CPUs, speed, memory + uint cores; + uint mhz; + uint sockets; + wmiCallsV2.GetProcessorResources(out sockets, out cores, out mhz); + strtRouteCmd.cpus = cores; + strtRouteCmd.speed = mhz; + strtRouteCmd.cpuSockets = sockets; + ulong memoryKBs; + ulong freeMemoryKBs; + wmiCallsV2.GetMemoryResources(out memoryKBs, out freeMemoryKBs); + strtRouteCmd.memory = memoryKBs * 1024; // Convert to bytes + + // Need 2 Gig for DOM0, see http://technet.microsoft.com/en-us/magazine/hh750394.aspx + strtRouteCmd.dom0MinMemory = config.ParentPartitionMinMemoryMb * 1024 * 1024; // Convert to bytes + + // Insert storage pool details. + // + // Read the localStoragePath for virtual disks from the Hyper-V configuration + // See http://blogs.msdn.com/b/virtual_pc_guy/archive/2010/05/06/managing-the-default-virtual-machine-location-with-hyper-v.aspx + // for discussion of Hyper-V file locations paths. + string localStoragePath = wmiCallsV2.GetDefaultVirtualDiskFolder(); + if (localStoragePath != null) + { + // GUID arbitrary. Host agents deals with storage pool in terms of localStoragePath. + // We use HOST guid. + string poolGuid = strtRouteCmd.guid; + + if (poolGuid == null) + { + poolGuid = Guid.NewGuid().ToString(); + logger.InfoFormat("Setting Startup StoragePool GUID to " + poolGuid); + } + else + { + logger.InfoFormat("Setting Startup StoragePool GUID same as HOST, i.e. " + poolGuid); + } + + long capacity; + long available; + GetCapacityForLocalPath(localStoragePath, out capacity, out available); + + logger.Debug(CloudStackTypes.StartupStorageCommand + " set available bytes to " + available); + + string ipAddr = strtRouteCmd.privateIpAddress; + var vmStates = wmiCallsV2.GetVmSync(config.PrivateIpAddress); + strtRouteCmd.vms = Utils.CreateCloudStackMapObject(vmStates); + + StoragePoolInfo pi = new StoragePoolInfo( + poolGuid.ToString(), + ipAddr, + localStoragePath, + localStoragePath, + StoragePoolType.Filesystem.ToString(), + capacity, + available); + + // Build StartupStorageCommand using an anonymous type + // See http://stackoverflow.com/a/6029228/939250 + object ansContent = new + { + poolInfo = pi, + guid = pi.uuid, + dataCenter = strtRouteCmd.dataCenter, + resourceType = StorageResourceType.STORAGE_POOL.ToString(), // TODO: check encoding + contextMap = contextMap + }; + JObject ansObj = Utils.CreateCloudStackObject(CloudStackTypes.StartupStorageCommand, ansContent); + cmdArray.Add(ansObj); + } + + // Convert result to array for type correctness? + logger.Info(CloudStackTypes.StartupCommand + " result is " + cmdArray.ToString()); + return cmdArray; + } + } + + // POST api/HypervResource/GetVncPortCommand + [HttpPost] + [ActionName(CloudStackTypes.GetVncPortCommand)] + public JContainer GetVncPortCommand([FromBody]dynamic cmd) + { + using (log4net.NDC.Push(Guid.NewGuid().ToString())) + { logger.Info(CloudStackTypes.GetVncPortCommand + Utils.CleanString(cmd.ToString())); - - string details = null; - bool result = false; - string address = null; - int port = -9; - - try - { - string vmName = (string)cmd.name; - var sys = wmiCallsV2.GetComputerSystem(vmName); - address = "instanceId=" + sys.Name ; - result = true; - } - catch (Exception sysEx) - { - details = CloudStackTypes.GetVncPortAnswer + " failed due to " + sysEx.Message; - logger.Error(details, sysEx); - } - - object ansContent = new - { - result = result, - details = details, - address = address, - port = port - }; - - return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.GetVncPortAnswer); - } - } - + + string details = null; + bool result = false; + string address = null; + int port = -9; + + try + { + string vmName = (string)cmd.name; + var sys = wmiCallsV2.GetComputerSystem(vmName); + address = "instanceId=" + sys.Name ; + result = true; + } + catch (Exception sysEx) + { + details = CloudStackTypes.GetVncPortAnswer + " failed due to " + sysEx.Message; + logger.Error(details, sysEx); + } + + object ansContent = new + { + result = result, + details = details, + address = address, + port = port + }; + + return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.GetVncPortAnswer); + } + } + // POST api/HypervResource/HostVmStateReportCommand [HttpPost] [ActionName(CloudStackTypes.HostVmStateReportCommand)] @@ -2442,53 +2442,53 @@ namespace HypervResource } } - public static System.Net.NetworkInformation.NetworkInterface GetNicInfoFromIpAddress(string ipAddress, out string subnet) - { - System.Net.NetworkInformation.NetworkInterface[] nics = System.Net.NetworkInformation.NetworkInterface.GetAllNetworkInterfaces(); - System.Net.NetworkInformation.NetworkInterface defaultnic = null; - foreach (var nic in nics) - { - subnet = null; - defaultnic = nic; - // TODO: use to remove NETMASK and MAC from the config file, and to validate the IPAddress. - var nicProps = nic.GetIPProperties(); - bool found = false; - foreach (var addr in nicProps.UnicastAddresses) - { - if (addr.Address.Equals(IPAddress.Parse(ipAddress))) - { - subnet = addr.IPv4Mask.ToString(); - found = true; - } - } - if (!found) - { - continue; - } - return nic; - } - var defaultSubnet = defaultnic.GetIPProperties().UnicastAddresses[0]; - subnet = defaultSubnet.IPv4Mask.ToString(); - return defaultnic; - } - - public static void GetCapacityForLocalPath(string localStoragePath, out long capacityBytes, out long availableBytes) - { - // NB: DriveInfo does not work for remote folders (http://stackoverflow.com/q/1799984/939250) - // DriveInfo requires a driver letter... - string fullPath = Path.GetFullPath(localStoragePath); - System.IO.DriveInfo poolInfo = new System.IO.DriveInfo(fullPath); - capacityBytes = poolInfo.TotalSize; - availableBytes = poolInfo.AvailableFreeSpace; - - // Don't allow all of the Root Device to be used for virtual disks - if (poolInfo.RootDirectory.Name.ToLower().Equals(config.RootDeviceName)) - { - availableBytes -= config.RootDeviceReservedSpaceBytes; - availableBytes = availableBytes > 0 ? availableBytes : 0; - capacityBytes -= config.RootDeviceReservedSpaceBytes; - capacityBytes = capacityBytes > 0 ? capacityBytes : 0; - } - } - } -} + public static System.Net.NetworkInformation.NetworkInterface GetNicInfoFromIpAddress(string ipAddress, out string subnet) + { + System.Net.NetworkInformation.NetworkInterface[] nics = System.Net.NetworkInformation.NetworkInterface.GetAllNetworkInterfaces(); + System.Net.NetworkInformation.NetworkInterface defaultnic = null; + foreach (var nic in nics) + { + subnet = null; + defaultnic = nic; + // TODO: use to remove NETMASK and MAC from the config file, and to validate the IPAddress. + var nicProps = nic.GetIPProperties(); + bool found = false; + foreach (var addr in nicProps.UnicastAddresses) + { + if (addr.Address.Equals(IPAddress.Parse(ipAddress))) + { + subnet = addr.IPv4Mask.ToString(); + found = true; + } + } + if (!found) + { + continue; + } + return nic; + } + var defaultSubnet = defaultnic.GetIPProperties().UnicastAddresses[0]; + subnet = defaultSubnet.IPv4Mask.ToString(); + return defaultnic; + } + + public static void GetCapacityForLocalPath(string localStoragePath, out long capacityBytes, out long availableBytes) + { + // NB: DriveInfo does not work for remote folders (http://stackoverflow.com/q/1799984/939250) + // DriveInfo requires a driver letter... + string fullPath = Path.GetFullPath(localStoragePath); + System.IO.DriveInfo poolInfo = new System.IO.DriveInfo(fullPath); + capacityBytes = poolInfo.TotalSize; + availableBytes = poolInfo.AvailableFreeSpace; + + // Don't allow all of the Root Device to be used for virtual disks + if (poolInfo.RootDirectory.Name.ToLower().Equals(config.RootDeviceName)) + { + availableBytes -= config.RootDeviceReservedSpaceBytes; + availableBytes = availableBytes > 0 ? availableBytes : 0; + capacityBytes -= config.RootDeviceReservedSpaceBytes; + capacityBytes = capacityBytes > 0 ? capacityBytes : 0; + } + } + } +} diff --git a/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/IWmiCallsV2.cs b/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/IWmiCallsV2.cs index 68731987649..0a64f4bc7e8 100644 --- a/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/IWmiCallsV2.cs +++ b/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/IWmiCallsV2.cs @@ -1,78 +1,78 @@ -// 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 System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using CloudStack.Plugin.WmiWrappers.ROOT.VIRTUALIZATION.V2; -using System.Management; - -namespace HypervResource -{ - public interface IWmiCallsV2 - { - System.Management.ManagementPath AddDiskDriveToIdeController(ComputerSystem vm, string vhdfile, string cntrllerAddr, string driveResourceType); - ComputerSystem AddUserData(ComputerSystem vm, string userData); - void AttachIso(string displayName, string iso); - void AttachDisk(string vmName, string diskPath, string addressOnController); - void CreateDynamicVirtualHardDisk(ulong MaxInternalSize, string Path); - SyntheticEthernetPortSettingData CreateNICforVm(ComputerSystem vm, string mac); - ComputerSystem CreateVM(string name, long memory_mb, int vcpus); - void DeleteHostKvpItem(ComputerSystem vm, string key); - void DeleteSwitchPort(string elementName); - ComputerSystem DeployVirtualMachine(dynamic jsonObj, string systemVmIso); - void DestroyVm(dynamic jsonObj); - void DestroyVm(string displayName); - void MigrateVm(string vmName, string destination); - void MigrateVolume(string vmName, string volume, string destination); - void MigrateVmWithVolume(string vmName, string destination, Dictionary volumeToPool); - void DetachDisk(string displayName, string diskFileName); - ComputerSystem GetComputerSystem(string displayName); +// 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 System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using CloudStack.Plugin.WmiWrappers.ROOT.VIRTUALIZATION.V2; +using System.Management; + +namespace HypervResource +{ + public interface IWmiCallsV2 + { + System.Management.ManagementPath AddDiskDriveToIdeController(ComputerSystem vm, string vhdfile, string cntrllerAddr, string driveResourceType); + ComputerSystem AddUserData(ComputerSystem vm, string userData); + void AttachIso(string displayName, string iso); + void AttachDisk(string vmName, string diskPath, string addressOnController); + void CreateDynamicVirtualHardDisk(ulong MaxInternalSize, string Path); + SyntheticEthernetPortSettingData CreateNICforVm(ComputerSystem vm, string mac); + ComputerSystem CreateVM(string name, long memory_mb, int vcpus); + void DeleteHostKvpItem(ComputerSystem vm, string key); + void DeleteSwitchPort(string elementName); + ComputerSystem DeployVirtualMachine(dynamic jsonObj, string systemVmIso); + void DestroyVm(dynamic jsonObj); + void DestroyVm(string displayName); + void MigrateVm(string vmName, string destination); + void MigrateVolume(string vmName, string volume, string destination); + void MigrateVmWithVolume(string vmName, string destination, Dictionary volumeToPool); + void DetachDisk(string displayName, string diskFileName); + ComputerSystem GetComputerSystem(string displayName); ComputerSystem.ComputerSystemCollection GetComputerSystemCollection(); - string GetDefaultDataRoot(); - string GetDefaultVirtualDiskFolder(); - ResourceAllocationSettingData GetDvdDriveSettings(VirtualSystemSettingData vmSettings); - EthernetPortAllocationSettingData[] GetEthernetConnections(ComputerSystem vm); - SyntheticEthernetPortSettingData[] GetEthernetPortSettings(ComputerSystem vm); - ResourceAllocationSettingData GetIDEControllerSettings(VirtualSystemSettingData vmSettings, string cntrllerAddr); - ImageManagementService GetImageManagementService(); - KvpExchangeComponentSettingData GetKvpSettings(VirtualSystemSettingData vmSettings); - void GetMemoryResources(out ulong physicalRamKBs, out ulong freeMemoryKBs); - MemorySettingData GetMemSettings(VirtualSystemSettingData vmSettings); - void GetProcessorResources(out uint sockets, out uint cores, out uint mhz); - void GetProcessorUsageInfo(out double cpuUtilization); - ProcessorSettingData GetProcSettings(VirtualSystemSettingData vmSettings); - ResourceAllocationSettingData.ResourceAllocationSettingDataCollection GetResourceAllocationSettings(VirtualSystemSettingData vmSettings); - void GetSummaryInfo(System.Collections.Generic.Dictionary vmProcessorInfo, System.Collections.Generic.List vmsToInspect); - SyntheticEthernetPortSettingData GetSyntheticEthernetPortSettings(EthernetSwitchPort port); - VirtualSystemManagementService GetVirtualisationSystemManagementService(); - VirtualEthernetSwitchManagementService GetVirtualSwitchManagementService(); - EthernetSwitchPortVlanSettingData GetVlanSettings(EthernetPortAllocationSettingData ethernetConnection); - System.Collections.Generic.List GetVmElementNames(); - VirtualSystemSettingData GetVmSettings(ComputerSystem vm); - void patchSystemVmIso(string vmName, string systemVmIso); - void SetState(ComputerSystem vm, ushort requiredState); - Dictionary GetVmSync(String privateIpAddress); + string GetDefaultDataRoot(); + string GetDefaultVirtualDiskFolder(); + ResourceAllocationSettingData GetDvdDriveSettings(VirtualSystemSettingData vmSettings); + EthernetPortAllocationSettingData[] GetEthernetConnections(ComputerSystem vm); + SyntheticEthernetPortSettingData[] GetEthernetPortSettings(ComputerSystem vm); + ResourceAllocationSettingData GetIDEControllerSettings(VirtualSystemSettingData vmSettings, string cntrllerAddr); + ImageManagementService GetImageManagementService(); + KvpExchangeComponentSettingData GetKvpSettings(VirtualSystemSettingData vmSettings); + void GetMemoryResources(out ulong physicalRamKBs, out ulong freeMemoryKBs); + MemorySettingData GetMemSettings(VirtualSystemSettingData vmSettings); + void GetProcessorResources(out uint sockets, out uint cores, out uint mhz); + void GetProcessorUsageInfo(out double cpuUtilization); + ProcessorSettingData GetProcSettings(VirtualSystemSettingData vmSettings); + ResourceAllocationSettingData.ResourceAllocationSettingDataCollection GetResourceAllocationSettings(VirtualSystemSettingData vmSettings); + void GetSummaryInfo(System.Collections.Generic.Dictionary vmProcessorInfo, System.Collections.Generic.List vmsToInspect); + SyntheticEthernetPortSettingData GetSyntheticEthernetPortSettings(EthernetSwitchPort port); + VirtualSystemManagementService GetVirtualisationSystemManagementService(); + VirtualEthernetSwitchManagementService GetVirtualSwitchManagementService(); + EthernetSwitchPortVlanSettingData GetVlanSettings(EthernetPortAllocationSettingData ethernetConnection); + System.Collections.Generic.List GetVmElementNames(); + VirtualSystemSettingData GetVmSettings(ComputerSystem vm); + void patchSystemVmIso(string vmName, string systemVmIso); + void SetState(ComputerSystem vm, ushort requiredState); + Dictionary GetVmSync(String privateIpAddress); string GetVmNote(System.Management.ManagementPath sysPath); void ModifyVmVLan(string vmName, String vlanid, string mac); - void ModifyVmVLan(string vmName, String vlanid, uint pos, bool enable, string switchLabelName); - void DisableVmNics(); + void ModifyVmVLan(string vmName, String vlanid, uint pos, bool enable, string switchLabelName); + void DisableVmNics(); void DisableNicVlan(String mac, String vmName); - } -} + } +} diff --git a/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/WmiCallsV2.cs b/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/WmiCallsV2.cs index fb14a0f7c63..7dbb8c14fa1 100644 --- a/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/WmiCallsV2.cs +++ b/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/WmiCallsV2.cs @@ -1,261 +1,261 @@ -// 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 System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using CloudStack.Plugin.WmiWrappers.ROOT.VIRTUALIZATION.V2; -using log4net; -using System.Globalization; -using System.Management; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; -using CloudStack.Plugin.WmiWrappers.ROOT.CIMV2; -using System.IO; -using System.Net.NetworkInformation; -using System.Net; - -namespace HypervResource -{ - public class WmiCallsV2 : IWmiCallsV2 - { - public static String CloudStackUserDataKey = "cloudstack-vm-userdata"; - - /// - /// Defines the migration types. - /// - public enum MigrationType - { - VirtualSystem = 32768, - Storage = 32769, - Staged = 32770, - VirtualSystemAndStorage = 32771 - }; - - /// - /// Defines migration transport types. - /// - public enum TransportType - { - TCP = 5, - SMB = 32768 - }; - - public static void Initialize() - { - // Trigger assembly load into curren appdomain - } - - private static ILog logger = LogManager.GetLogger(typeof(WmiCallsV2)); - - /// - /// Returns ping status of the given ip - /// - public static String PingHost(String ip) - { - return "Success"; - } - - /// - /// Returns ComputerSystem lacking any NICs and VOLUMEs - /// - public ComputerSystem AddUserData(ComputerSystem vm, string userData) - { - // Obtain controller for Hyper-V virtualisation subsystem - VirtualSystemManagementService vmMgmtSvc = GetVirtualisationSystemManagementService(); - - // Create object to hold the data. - KvpExchangeDataItem kvpItem = KvpExchangeDataItem.CreateInstance(); - kvpItem.LateBoundObject["Name"] = WmiCallsV2.CloudStackUserDataKey; - kvpItem.LateBoundObject["Data"] = userData; - kvpItem.LateBoundObject["Source"] = 0; - logger.Debug("VM " + vm.Name + " gets userdata " + userData); - - // Update the resource settings for the VM. - System.Management.ManagementBaseObject kvpMgmtObj = kvpItem.LateBoundObject; - System.Management.ManagementPath jobPath; - String kvpStr = kvpMgmtObj.GetText(System.Management.TextFormat.CimDtd20); - uint ret_val = vmMgmtSvc.AddKvpItems(new String[] { kvpStr }, vm.Path, out jobPath); - - // If the Job is done asynchronously - if (ret_val == ReturnCode.Started) - { - JobCompleted(jobPath); - } - else if (ret_val != ReturnCode.Completed) - { - var errMsg = string.Format( - "Failed to update VM {0} (GUID {1}) due to {2} (ModifyVirtualSystem call), existing VM not deleted", - vm.ElementName, - vm.Name, - ReturnCode.ToString(ret_val)); - var ex = new WmiException(errMsg); - logger.Error(errMsg, ex); - throw ex; - } - - return vm; - } - - /// - /// Returns ComputerSystem lacking any NICs and VOLUMEs - /// - public ComputerSystem CreateVM(string name, long memory_mb, int vcpus) - { - // Obtain controller for Hyper-V virtualisation subsystem - VirtualSystemManagementService vmMgmtSvc = GetVirtualisationSystemManagementService(); - - // Create VM with correct name and default resources - ComputerSystem vm = CreateDefaultVm(vmMgmtSvc, name); - - // Update the resource settings for the VM. - - // Resource settings are referenced through the Msvm_VirtualSystemSettingData object. - VirtualSystemSettingData vmSettings = GetVmSettings(vm); - - // For memory settings, there is no Dynamic Memory, so reservation, limit and quantity are identical. - MemorySettingData memSettings = GetMemSettings(vmSettings); - memSettings.LateBoundObject["VirtualQuantity"] = memory_mb; - memSettings.LateBoundObject["Reservation"] = memory_mb; - memSettings.LateBoundObject["Limit"] = memory_mb; - - // Update the processor settings for the VM, static assignment of 100% for CPU limit - ProcessorSettingData procSettings = GetProcSettings(vmSettings); - procSettings.LateBoundObject["VirtualQuantity"] = vcpus; - procSettings.LateBoundObject["Reservation"] = vcpus; - procSettings.LateBoundObject["Limit"] = 100000; - - ModifyVmResources(vmMgmtSvc, vm, new String[] { - memSettings.LateBoundObject.GetText(TextFormat.CimDtd20), - procSettings.LateBoundObject.GetText(TextFormat.CimDtd20) - }); - logger.InfoFormat("VM with display name {0} has GUID {1}", vm.ElementName, vm.Name); - logger.DebugFormat("Resources for vm {0}: {1} MB memory, {2} vcpus", name, memory_mb, vcpus); - - return vm; - } - - /// - /// Create a (synthetic) nic, and attach it to the vm - /// - /// - /// - /// - /// - public SyntheticEthernetPortSettingData CreateNICforVm(ComputerSystem vm, string mac) - { - logger.DebugFormat("Creating nic for VM {0} (GUID {1})", vm.ElementName, vm.Name); - - // Obtain controller for Hyper-V networking subsystem - var vmNetMgmtSvc = GetVirtualSwitchManagementService(); - - // Create NIC resource by cloning the default NIC - var synthNICsSettings = SyntheticEthernetPortSettingData.GetInstances(vmNetMgmtSvc.Scope, "InstanceID LIKE \"%Default\""); - - // Assert - if (synthNICsSettings.Count != 1) - { - var errMsg = string.Format("Internal error, coudl not find default SyntheticEthernetPort instance"); - var ex = new WmiException(errMsg); - logger.Error(errMsg, ex); - throw ex; - } - var defaultSynthNICSettings = synthNICsSettings.OfType().First(); - - var newSynthNICSettings = new SyntheticEthernetPortSettingData((ManagementBaseObject)defaultSynthNICSettings.LateBoundObject.Clone()); - - // Assign configuration to new NIC - string normalisedMAC = string.Join("", (mac.Split(new char[] { ':' }))); - newSynthNICSettings.LateBoundObject["ElementName"] = vm.ElementName; - newSynthNICSettings.LateBoundObject["Address"] = normalisedMAC; - newSynthNICSettings.LateBoundObject["StaticMacAddress"] = "TRUE"; - newSynthNICSettings.LateBoundObject["VirtualSystemIdentifiers"] = new string[] { "{" + Guid.NewGuid().ToString() + "}" }; - newSynthNICSettings.CommitObject(); - - // Insert NIC into vm - string[] newResources = new string[] { newSynthNICSettings.LateBoundObject.GetText(System.Management.TextFormat.CimDtd20)}; - ManagementPath[] newResourcePaths = AddVirtualResource(newResources, vm ); - - // assert - if (newResourcePaths.Length != 1) - { - var errMsg = string.Format( - "Failed to properly insert a single NIC on VM {0} (GUID {1}): number of resource created {2}", - vm.ElementName, - vm.Name, - newResourcePaths.Length); - var ex = new WmiException(errMsg); - logger.Error(errMsg, ex); - throw ex; - } - - return new SyntheticEthernetPortSettingData(newResourcePaths[0]); - } - - public const string IDE_CONTROLLER = "Microsoft:Hyper-V:Emulated IDE Controller"; - public const string SCSI_CONTROLLER = "Microsoft:Hyper-V:Synthetic SCSI Controller"; - public const string HARDDISK_DRIVE = "Microsoft:Hyper-V:Synthetic Disk Drive"; - public const string ISO_DRIVE = "Microsoft:Hyper-V:Synthetic DVD Drive"; - - // TODO: names harvested from Msvm_ResourcePool, not clear how to create new instances - public const string ISO_DISK = "Microsoft:Hyper-V:Virtual CD/DVD Disk"; // For IDE_ISO_DRIVE - public const string HARDDISK_DISK = "Microsoft:Hyper-V:Virtual Hard Disk"; // For IDE_HARDDISK_DRIVE - - /// - /// Create new VM. By default we start it. - /// - public ComputerSystem DeployVirtualMachine(dynamic jsonObj, string systemVmIso) - { - var vmInfo = jsonObj.vm; - string vmName = vmInfo.name; - var nicInfo = vmInfo.nics; - int vcpus = vmInfo.cpus; - int memSize = vmInfo.maxRam / 1048576; - string errMsg = vmName; - var diskDrives = vmInfo.disks; - var bootArgs = vmInfo.bootArgs; - - // assert - errMsg = vmName + ": missing disk information, array empty or missing, agent expects *at least* one disk for a VM"; - if (diskDrives == null) - { - logger.Error(errMsg); - throw new ArgumentException(errMsg); - } - // assert - errMsg = vmName + ": missing NIC information, array empty or missing, agent expects at least an empty array."; - if (nicInfo == null ) - { - logger.Error(errMsg); - throw new ArgumentException(errMsg); - } - - - // For existing VMs, return when we spot one of this name not stopped. In the meantime, remove any existing VMs of same name. - ComputerSystem vmWmiObj = null; - while ((vmWmiObj = GetComputerSystem(vmName)) != null) - { - logger.WarnFormat("Create request for existing vm, name {0}", vmName); - if (vmWmiObj.EnabledState == EnabledState.Disabled) - { - logger.InfoFormat("Deleting existing VM with name {0}, before we go on to create a VM with the same name", vmName); - DestroyVm(vmName); - } +// 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 System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using CloudStack.Plugin.WmiWrappers.ROOT.VIRTUALIZATION.V2; +using log4net; +using System.Globalization; +using System.Management; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using CloudStack.Plugin.WmiWrappers.ROOT.CIMV2; +using System.IO; +using System.Net.NetworkInformation; +using System.Net; + +namespace HypervResource +{ + public class WmiCallsV2 : IWmiCallsV2 + { + public static String CloudStackUserDataKey = "cloudstack-vm-userdata"; + + /// + /// Defines the migration types. + /// + public enum MigrationType + { + VirtualSystem = 32768, + Storage = 32769, + Staged = 32770, + VirtualSystemAndStorage = 32771 + }; + + /// + /// Defines migration transport types. + /// + public enum TransportType + { + TCP = 5, + SMB = 32768 + }; + + public static void Initialize() + { + // Trigger assembly load into curren appdomain + } + + private static ILog logger = LogManager.GetLogger(typeof(WmiCallsV2)); + + /// + /// Returns ping status of the given ip + /// + public static String PingHost(String ip) + { + return "Success"; + } + + /// + /// Returns ComputerSystem lacking any NICs and VOLUMEs + /// + public ComputerSystem AddUserData(ComputerSystem vm, string userData) + { + // Obtain controller for Hyper-V virtualisation subsystem + VirtualSystemManagementService vmMgmtSvc = GetVirtualisationSystemManagementService(); + + // Create object to hold the data. + KvpExchangeDataItem kvpItem = KvpExchangeDataItem.CreateInstance(); + kvpItem.LateBoundObject["Name"] = WmiCallsV2.CloudStackUserDataKey; + kvpItem.LateBoundObject["Data"] = userData; + kvpItem.LateBoundObject["Source"] = 0; + logger.Debug("VM " + vm.Name + " gets userdata " + userData); + + // Update the resource settings for the VM. + System.Management.ManagementBaseObject kvpMgmtObj = kvpItem.LateBoundObject; + System.Management.ManagementPath jobPath; + String kvpStr = kvpMgmtObj.GetText(System.Management.TextFormat.CimDtd20); + uint ret_val = vmMgmtSvc.AddKvpItems(new String[] { kvpStr }, vm.Path, out jobPath); + + // If the Job is done asynchronously + if (ret_val == ReturnCode.Started) + { + JobCompleted(jobPath); + } + else if (ret_val != ReturnCode.Completed) + { + var errMsg = string.Format( + "Failed to update VM {0} (GUID {1}) due to {2} (ModifyVirtualSystem call), existing VM not deleted", + vm.ElementName, + vm.Name, + ReturnCode.ToString(ret_val)); + var ex = new WmiException(errMsg); + logger.Error(errMsg, ex); + throw ex; + } + + return vm; + } + + /// + /// Returns ComputerSystem lacking any NICs and VOLUMEs + /// + public ComputerSystem CreateVM(string name, long memory_mb, int vcpus) + { + // Obtain controller for Hyper-V virtualisation subsystem + VirtualSystemManagementService vmMgmtSvc = GetVirtualisationSystemManagementService(); + + // Create VM with correct name and default resources + ComputerSystem vm = CreateDefaultVm(vmMgmtSvc, name); + + // Update the resource settings for the VM. + + // Resource settings are referenced through the Msvm_VirtualSystemSettingData object. + VirtualSystemSettingData vmSettings = GetVmSettings(vm); + + // For memory settings, there is no Dynamic Memory, so reservation, limit and quantity are identical. + MemorySettingData memSettings = GetMemSettings(vmSettings); + memSettings.LateBoundObject["VirtualQuantity"] = memory_mb; + memSettings.LateBoundObject["Reservation"] = memory_mb; + memSettings.LateBoundObject["Limit"] = memory_mb; + + // Update the processor settings for the VM, static assignment of 100% for CPU limit + ProcessorSettingData procSettings = GetProcSettings(vmSettings); + procSettings.LateBoundObject["VirtualQuantity"] = vcpus; + procSettings.LateBoundObject["Reservation"] = vcpus; + procSettings.LateBoundObject["Limit"] = 100000; + + ModifyVmResources(vmMgmtSvc, vm, new String[] { + memSettings.LateBoundObject.GetText(TextFormat.CimDtd20), + procSettings.LateBoundObject.GetText(TextFormat.CimDtd20) + }); + logger.InfoFormat("VM with display name {0} has GUID {1}", vm.ElementName, vm.Name); + logger.DebugFormat("Resources for vm {0}: {1} MB memory, {2} vcpus", name, memory_mb, vcpus); + + return vm; + } + + /// + /// Create a (synthetic) nic, and attach it to the vm + /// + /// + /// + /// + /// + public SyntheticEthernetPortSettingData CreateNICforVm(ComputerSystem vm, string mac) + { + logger.DebugFormat("Creating nic for VM {0} (GUID {1})", vm.ElementName, vm.Name); + + // Obtain controller for Hyper-V networking subsystem + var vmNetMgmtSvc = GetVirtualSwitchManagementService(); + + // Create NIC resource by cloning the default NIC + var synthNICsSettings = SyntheticEthernetPortSettingData.GetInstances(vmNetMgmtSvc.Scope, "InstanceID LIKE \"%Default\""); + + // Assert + if (synthNICsSettings.Count != 1) + { + var errMsg = string.Format("Internal error, coudl not find default SyntheticEthernetPort instance"); + var ex = new WmiException(errMsg); + logger.Error(errMsg, ex); + throw ex; + } + var defaultSynthNICSettings = synthNICsSettings.OfType().First(); + + var newSynthNICSettings = new SyntheticEthernetPortSettingData((ManagementBaseObject)defaultSynthNICSettings.LateBoundObject.Clone()); + + // Assign configuration to new NIC + string normalisedMAC = string.Join("", (mac.Split(new char[] { ':' }))); + newSynthNICSettings.LateBoundObject["ElementName"] = vm.ElementName; + newSynthNICSettings.LateBoundObject["Address"] = normalisedMAC; + newSynthNICSettings.LateBoundObject["StaticMacAddress"] = "TRUE"; + newSynthNICSettings.LateBoundObject["VirtualSystemIdentifiers"] = new string[] { "{" + Guid.NewGuid().ToString() + "}" }; + newSynthNICSettings.CommitObject(); + + // Insert NIC into vm + string[] newResources = new string[] { newSynthNICSettings.LateBoundObject.GetText(System.Management.TextFormat.CimDtd20)}; + ManagementPath[] newResourcePaths = AddVirtualResource(newResources, vm ); + + // assert + if (newResourcePaths.Length != 1) + { + var errMsg = string.Format( + "Failed to properly insert a single NIC on VM {0} (GUID {1}): number of resource created {2}", + vm.ElementName, + vm.Name, + newResourcePaths.Length); + var ex = new WmiException(errMsg); + logger.Error(errMsg, ex); + throw ex; + } + + return new SyntheticEthernetPortSettingData(newResourcePaths[0]); + } + + public const string IDE_CONTROLLER = "Microsoft:Hyper-V:Emulated IDE Controller"; + public const string SCSI_CONTROLLER = "Microsoft:Hyper-V:Synthetic SCSI Controller"; + public const string HARDDISK_DRIVE = "Microsoft:Hyper-V:Synthetic Disk Drive"; + public const string ISO_DRIVE = "Microsoft:Hyper-V:Synthetic DVD Drive"; + + // TODO: names harvested from Msvm_ResourcePool, not clear how to create new instances + public const string ISO_DISK = "Microsoft:Hyper-V:Virtual CD/DVD Disk"; // For IDE_ISO_DRIVE + public const string HARDDISK_DISK = "Microsoft:Hyper-V:Virtual Hard Disk"; // For IDE_HARDDISK_DRIVE + + /// + /// Create new VM. By default we start it. + /// + public ComputerSystem DeployVirtualMachine(dynamic jsonObj, string systemVmIso) + { + var vmInfo = jsonObj.vm; + string vmName = vmInfo.name; + var nicInfo = vmInfo.nics; + int vcpus = vmInfo.cpus; + int memSize = vmInfo.maxRam / 1048576; + string errMsg = vmName; + var diskDrives = vmInfo.disks; + var bootArgs = vmInfo.bootArgs; + + // assert + errMsg = vmName + ": missing disk information, array empty or missing, agent expects *at least* one disk for a VM"; + if (diskDrives == null) + { + logger.Error(errMsg); + throw new ArgumentException(errMsg); + } + // assert + errMsg = vmName + ": missing NIC information, array empty or missing, agent expects at least an empty array."; + if (nicInfo == null ) + { + logger.Error(errMsg); + throw new ArgumentException(errMsg); + } + + + // For existing VMs, return when we spot one of this name not stopped. In the meantime, remove any existing VMs of same name. + ComputerSystem vmWmiObj = null; + while ((vmWmiObj = GetComputerSystem(vmName)) != null) + { + logger.WarnFormat("Create request for existing vm, name {0}", vmName); + if (vmWmiObj.EnabledState == EnabledState.Disabled) + { + logger.InfoFormat("Deleting existing VM with name {0}, before we go on to create a VM with the same name", vmName); + DestroyVm(vmName); + } else if (vmWmiObj.EnabledState == EnabledState.Enabled) { string infoMsg = string.Format("Create VM discovered there exists a VM with name {0}, state {1}", @@ -264,666 +264,666 @@ namespace HypervResource logger.Info(infoMsg); return vmWmiObj; } - else - { + else + { errMsg = string.Format("Create VM failing, because there exists a VM with name {0}, state {1}", - vmName, - EnabledState.ToString(vmWmiObj.EnabledState)); - var ex = new WmiException(errMsg); - logger.Error(errMsg, ex); - throw ex; - } - } - - // Create vm carcase - logger.DebugFormat("Going ahead with create VM {0}, {1} vcpus, {2}MB RAM", vmName, vcpus, memSize); - var newVm = CreateVM(vmName, memSize, vcpus); - - // Add a SCSI controller for attaching/detaching data volumes. - AddScsiController(newVm); - - foreach (var diskDrive in diskDrives) - { - string vhdFile = null; - string diskName = null; - string isoPath = null; - VolumeObjectTO volInfo = VolumeObjectTO.ParseJson(diskDrive.data); - TemplateObjectTO templateInfo = TemplateObjectTO.ParseJson(diskDrive.data); - - if (volInfo != null) - { - // assert - errMsg = vmName + ": volume missing primaryDataStore for disk " + diskDrive.ToString(); - if (volInfo.primaryDataStore == null) - { - logger.Error(errMsg); - throw new ArgumentException(errMsg); - } - diskName = volInfo.name; - - // assert - errMsg = vmName + ": can't deal with DataStore type for disk " + diskDrive.ToString(); - if (volInfo.primaryDataStore == null) - { - logger.Error(errMsg); - throw new ArgumentException(errMsg); - } - errMsg = vmName + ": Malformed PrimaryDataStore for disk " + diskDrive.ToString(); - if (String.IsNullOrEmpty(volInfo.primaryDataStore.Path)) - { - logger.Error(errMsg); - throw new ArgumentException(errMsg); - } - errMsg = vmName + ": Missing folder PrimaryDataStore for disk " + diskDrive.ToString() + ", missing path: " + volInfo.primaryDataStore.Path; - if (!Directory.Exists(volInfo.primaryDataStore.Path)) - { - logger.Error(errMsg); - throw new ArgumentException(errMsg); - } - - vhdFile = volInfo.FullFileName; - if (!System.IO.File.Exists(vhdFile)) - { - errMsg = vmName + ": non-existent volume, missing " + vhdFile + " for drive " + diskDrive.ToString(); - logger.Error(errMsg); - throw new ArgumentException(errMsg); - } - logger.Debug("Going to create " + vmName + " with attached voluem " + diskName + " at " + vhdFile); - } - else if (templateInfo != null && templateInfo.nfsDataStoreTO != null) - { - NFSTO share = templateInfo.nfsDataStoreTO; - Utils.ConnectToRemote(share.UncPath, share.Domain, share.User, share.Password); - // The share is mapped, now attach the iso - isoPath = Utils.NormalizePath(Path.Combine(share.UncPath, templateInfo.path)); - } - - string driveType = diskDrive.type; - string ideCtrllr = "0"; - string driveResourceType = null; - switch (driveType) { - case "ROOT": - ideCtrllr = "0"; - driveResourceType = HARDDISK_DRIVE; - break; - case "ISO": - ideCtrllr = "1"; - driveResourceType = ISO_DRIVE; - break; - case "DATADISK": - break; - default: - // TODO: double check exception type - errMsg = string.Format("Unknown disk type {0} for disk {1}, vm named {2}", - string.IsNullOrEmpty(driveType) ? "NULL" : driveType, - string.IsNullOrEmpty(diskName) ? "NULL" : diskName, vmName); - var ex = new WmiException(errMsg); - logger.Error(errMsg, ex); - throw ex; - } - - logger.DebugFormat("Create disk type {1} (Named: {0}), on vm {2} {3}", diskName, driveResourceType, vmName, - string.IsNullOrEmpty(vhdFile) ? " no disk to insert" : ", inserting disk" + vhdFile); - if (driveType.Equals("DATADISK")) - { - AttachDisk(vmName, vhdFile, (string)diskDrive.diskSeq); - } - else - { - AddDiskDriveToIdeController(newVm, vhdFile, ideCtrllr, driveResourceType); - if (isoPath != null) - { - AttachIso(vmName, isoPath); - } - } - } - - int nicCount = 0; - int enableState = 2; - - // Add the Nics to the VM in the deviceId order. - foreach (var nc in nicInfo) - { - foreach (var nic in nicInfo) - { - - int nicid = nic.deviceId; + vmName, + EnabledState.ToString(vmWmiObj.EnabledState)); + var ex = new WmiException(errMsg); + logger.Error(errMsg, ex); + throw ex; + } + } + + // Create vm carcase + logger.DebugFormat("Going ahead with create VM {0}, {1} vcpus, {2}MB RAM", vmName, vcpus, memSize); + var newVm = CreateVM(vmName, memSize, vcpus); + + // Add a SCSI controller for attaching/detaching data volumes. + AddScsiController(newVm); + + foreach (var diskDrive in diskDrives) + { + string vhdFile = null; + string diskName = null; + string isoPath = null; + VolumeObjectTO volInfo = VolumeObjectTO.ParseJson(diskDrive.data); + TemplateObjectTO templateInfo = TemplateObjectTO.ParseJson(diskDrive.data); + + if (volInfo != null) + { + // assert + errMsg = vmName + ": volume missing primaryDataStore for disk " + diskDrive.ToString(); + if (volInfo.primaryDataStore == null) + { + logger.Error(errMsg); + throw new ArgumentException(errMsg); + } + diskName = volInfo.name; + + // assert + errMsg = vmName + ": can't deal with DataStore type for disk " + diskDrive.ToString(); + if (volInfo.primaryDataStore == null) + { + logger.Error(errMsg); + throw new ArgumentException(errMsg); + } + errMsg = vmName + ": Malformed PrimaryDataStore for disk " + diskDrive.ToString(); + if (String.IsNullOrEmpty(volInfo.primaryDataStore.Path)) + { + logger.Error(errMsg); + throw new ArgumentException(errMsg); + } + errMsg = vmName + ": Missing folder PrimaryDataStore for disk " + diskDrive.ToString() + ", missing path: " + volInfo.primaryDataStore.Path; + if (!Directory.Exists(volInfo.primaryDataStore.Path)) + { + logger.Error(errMsg); + throw new ArgumentException(errMsg); + } + + vhdFile = volInfo.FullFileName; + if (!System.IO.File.Exists(vhdFile)) + { + errMsg = vmName + ": non-existent volume, missing " + vhdFile + " for drive " + diskDrive.ToString(); + logger.Error(errMsg); + throw new ArgumentException(errMsg); + } + logger.Debug("Going to create " + vmName + " with attached voluem " + diskName + " at " + vhdFile); + } + else if (templateInfo != null && templateInfo.nfsDataStoreTO != null) + { + NFSTO share = templateInfo.nfsDataStoreTO; + Utils.ConnectToRemote(share.UncPath, share.Domain, share.User, share.Password); + // The share is mapped, now attach the iso + isoPath = Utils.NormalizePath(Path.Combine(share.UncPath, templateInfo.path)); + } + + string driveType = diskDrive.type; + string ideCtrllr = "0"; + string driveResourceType = null; + switch (driveType) { + case "ROOT": + ideCtrllr = "0"; + driveResourceType = HARDDISK_DRIVE; + break; + case "ISO": + ideCtrllr = "1"; + driveResourceType = ISO_DRIVE; + break; + case "DATADISK": + break; + default: + // TODO: double check exception type + errMsg = string.Format("Unknown disk type {0} for disk {1}, vm named {2}", + string.IsNullOrEmpty(driveType) ? "NULL" : driveType, + string.IsNullOrEmpty(diskName) ? "NULL" : diskName, vmName); + var ex = new WmiException(errMsg); + logger.Error(errMsg, ex); + throw ex; + } + + logger.DebugFormat("Create disk type {1} (Named: {0}), on vm {2} {3}", diskName, driveResourceType, vmName, + string.IsNullOrEmpty(vhdFile) ? " no disk to insert" : ", inserting disk" + vhdFile); + if (driveType.Equals("DATADISK")) + { + AttachDisk(vmName, vhdFile, (string)diskDrive.diskSeq); + } + else + { + AddDiskDriveToIdeController(newVm, vhdFile, ideCtrllr, driveResourceType); + if (isoPath != null) + { + AttachIso(vmName, isoPath); + } + } + } + + int nicCount = 0; + int enableState = 2; + + // Add the Nics to the VM in the deviceId order. + foreach (var nc in nicInfo) + { + foreach (var nic in nicInfo) + { + + int nicid = nic.deviceId; Int32 networkRateMbps = nic.networkRateMbps; - string mac = nic.mac; - string vlan = null; - string isolationUri = nic.isolationUri; - string broadcastUri = nic.broadcastUri; + string mac = nic.mac; + string vlan = null; + string isolationUri = nic.isolationUri; + string broadcastUri = nic.broadcastUri; string nicIp = nic.ip; string nicNetmask = nic.netmask; - if ( (broadcastUri != null ) || (isolationUri != null && isolationUri.StartsWith("vlan://"))) - { - if (broadcastUri != null && broadcastUri.StartsWith("storage")) - { - vlan = broadcastUri.Substring("storage://".Length); - } - else - { - vlan = isolationUri.Substring("vlan://".Length); - } - int tmp; + if ( (broadcastUri != null ) || (isolationUri != null && isolationUri.StartsWith("vlan://"))) + { + if (broadcastUri != null && broadcastUri.StartsWith("storage")) + { + vlan = broadcastUri.Substring("storage://".Length); + } + else + { + vlan = isolationUri.Substring("vlan://".Length); + } + int tmp; if (vlan.Equals("untagged", StringComparison.CurrentCultureIgnoreCase) ) { // recevied vlan is untagged, don't parse for the vlan in the isolation uri vlan = null; } - else if (!int.TryParse(vlan, out tmp)) - { - // TODO: double check exception type - errMsg = string.Format("Invalid VLAN value {0} for on vm {1} for nic uuid {2}", isolationUri, vmName, nic.uuid); - var ex = new WmiException(errMsg); - logger.Error(errMsg, ex); - throw ex; - } - } - - - if (nicid == nicCount) - { - if (nicIp.Equals("0.0.0.0") && nicNetmask.Equals("255.255.255.255")) - { - // this is the extra nic added to VR. - vlan = null; - enableState = 3; + else if (!int.TryParse(vlan, out tmp)) + { + // TODO: double check exception type + errMsg = string.Format("Invalid VLAN value {0} for on vm {1} for nic uuid {2}", isolationUri, vmName, nic.uuid); + var ex = new WmiException(errMsg); + logger.Error(errMsg, ex); + throw ex; } - - // Create network adapter - var newAdapter = CreateNICforVm(newVm, mac); - String switchName =""; - if (nic.name != null) - { - switchName = nic.name; - } - EthernetPortAllocationSettingData portSettings = null; - // connection to vswitch - portSettings = AttachNicToPort(newVm, newAdapter, switchName, enableState); - //reset the flag for other nics - enableState = 2; - // set vlan - if (vlan != null) - { - SetPortVlan(vlan, portSettings); - } - + } + + + if (nicid == nicCount) + { + if (nicIp.Equals("0.0.0.0") && nicNetmask.Equals("255.255.255.255")) + { + // this is the extra nic added to VR. + vlan = null; + enableState = 3; + } + + // Create network adapter + var newAdapter = CreateNICforVm(newVm, mac); + String switchName =""; + if (nic.name != null) + { + switchName = nic.name; + } + EthernetPortAllocationSettingData portSettings = null; + // connection to vswitch + portSettings = AttachNicToPort(newVm, newAdapter, switchName, enableState); + //reset the flag for other nics + enableState = 2; + // set vlan + if (vlan != null) + { + SetPortVlan(vlan, portSettings); + } + if (networkRateMbps > 0) { SetBandWidthLimit((ulong)networkRateMbps, portSettings); } - logger.DebugFormat("Created adapter {0} on port {1}, {2}", - newAdapter.Path, portSettings.Path, (vlan == null ? "No VLAN" : "VLAN " + vlan)); - // logger.DebugFormat("Created adapter {0} on port {1}, {2}", - // newAdapter.Path, portSettings.Path, (vlan == null ? "No VLAN" : "VLAN " + vlan)); - } - } - nicCount++; - } - + logger.DebugFormat("Created adapter {0} on port {1}, {2}", + newAdapter.Path, portSettings.Path, (vlan == null ? "No VLAN" : "VLAN " + vlan)); + // logger.DebugFormat("Created adapter {0} on port {1}, {2}", + // newAdapter.Path, portSettings.Path, (vlan == null ? "No VLAN" : "VLAN " + vlan)); + } + } + nicCount++; + } - // pass the boot args for the VM using KVP component. - // We need to pass the boot args to system vm's to get them configured with cloudstack configuration. - // Add new user data - var vm = GetComputerSystem(vmName); - if (bootArgs != null && !String.IsNullOrEmpty((string)bootArgs)) - { - - String bootargs = bootArgs; - AddUserData(vm, bootargs); - } - - // call patch systemvm iso only for systemvms - if (vmName.StartsWith("r-") || vmName.StartsWith("s-") || vmName.StartsWith("v-")) - { - if (systemVmIso != null && systemVmIso.Length != 0) - { - patchSystemVmIso(vmName, systemVmIso); - } - } - - logger.DebugFormat("Starting VM {0}", vmName); - SetState(newVm, RequiredState.Enabled); + + // pass the boot args for the VM using KVP component. + // We need to pass the boot args to system vm's to get them configured with cloudstack configuration. + // Add new user data + var vm = GetComputerSystem(vmName); + if (bootArgs != null && !String.IsNullOrEmpty((string)bootArgs)) + { + + String bootargs = bootArgs; + AddUserData(vm, bootargs); + } + + // call patch systemvm iso only for systemvms + if (vmName.StartsWith("r-") || vmName.StartsWith("s-") || vmName.StartsWith("v-")) + { + if (systemVmIso != null && systemVmIso.Length != 0) + { + patchSystemVmIso(vmName, systemVmIso); + } + } + + logger.DebugFormat("Starting VM {0}", vmName); + SetState(newVm, RequiredState.Enabled); // Mark the VM as created by cloudstack tag TagVm(newVm); - - // we need to reboot to get the hv kvp daemon get started vr gets configured. - if (vmName.StartsWith("r-") || vmName.StartsWith("s-") || vmName.StartsWith("v-")) - { - System.Threading.Thread.Sleep(90000); - } - logger.InfoFormat("Started VM {0}", vmName); - return newVm; - } - - public static Boolean pingResource(String ip) - { - PingOptions pingOptions = null; - PingReply pingReply = null; - IPAddress ipAddress = null; - Ping pingSender = new Ping(); - int numberOfPings = 6; - int pingTimeout = 1000; - int byteSize = 32; - byte[] buffer = new byte[byteSize]; - ipAddress = IPAddress.Parse(ip); - pingOptions = new PingOptions(); - for (int i = 0; i < numberOfPings; i++) - { - pingReply = pingSender.Send(ipAddress, pingTimeout, buffer, pingOptions); - if (pingReply.Status == IPStatus.Success) - { - System.Threading.Thread.Sleep(30000); - return true; - } - else - { - // wait for the second boot and then return with suces - System.Threading.Thread.Sleep(30000); - } - } - return false; - } - - private EthernetPortAllocationSettingData AttachNicToPort(ComputerSystem newVm, SyntheticEthernetPortSettingData newAdapter, String vSwitchName, int enableState) - { - // Get the virtual switch - VirtualEthernetSwitch vSwitch = GetExternalVirtSwitch(vSwitchName); - //check the the recevied vSwitch is the same as vSwitchName. - if (!vSwitchName.Equals("") && !vSwitch.ElementName.Equals(vSwitchName)) - { - var errMsg = string.Format("Internal error, coudl not find Virtual Switch with the name : " +vSwitchName); - var ex = new WmiException(errMsg); - logger.Error(errMsg, ex); - throw ex; - } - - // Create port for adapter - var defaultEthernetPortSettings = EthernetPortAllocationSettingData.GetInstances(vSwitch.Scope, "InstanceID LIKE \"%Default\""); - - // assert - if (defaultEthernetPortSettings.Count != 1) - { - var errMsg = string.Format("Internal error, coudl not find default EthernetPortAllocationSettingData instance"); - var ex = new WmiException(errMsg); - logger.Error(errMsg, ex); - throw ex; - } - - var defaultEthernetPortSettingsObj = defaultEthernetPortSettings.OfType().First(); - var newEthernetPortSettings = new EthernetPortAllocationSettingData((ManagementBaseObject)defaultEthernetPortSettingsObj.LateBoundObject.Clone()); - newEthernetPortSettings.LateBoundObject["Parent"] = newAdapter.Path.Path; - newEthernetPortSettings.LateBoundObject["HostResource"] = new string[] { vSwitch.Path.Path }; - newEthernetPortSettings.LateBoundObject["EnabledState"] = enableState; //3 disabled 2 Enabled - // Insert NIC into vm - string[] newResources = new string[] { newEthernetPortSettings.LateBoundObject.GetText(System.Management.TextFormat.CimDtd20) }; - ManagementPath[] newResourcePaths = AddVirtualResource(newResources, newVm); - - // assert - if (newResourcePaths.Length != 1) - { - var errMsg = string.Format( - "Failed to properly insert a single NIC on VM {0} (GUID {1}): number of resource created {2}", - newVm.ElementName, - newVm.Name, - newResourcePaths.Length); - var ex = new WmiException(errMsg); - logger.Error(errMsg, ex); - throw ex; - } - - return new EthernetPortAllocationSettingData(newResourcePaths[0]); - } - - /// this method is to add a dvd drive and attach the systemvm iso. - /// - public void patchSystemVmIso(String vmName, String systemVmIso) - { - ComputerSystem vmObject = GetComputerSystem(vmName); - AddDiskDriveToIdeController(vmObject, "", "1", ISO_DRIVE); - AttachIso(vmName, systemVmIso); - } - - public void AttachDisk(string vmName, string diskPath, string addressOnController) - { - logger.DebugFormat("Got request to attach disk {0} to vm {1}", diskPath, vmName); - - ComputerSystem vm = GetComputerSystem(vmName); - if (vm == null) - { - logger.DebugFormat("VM {0} not found", vmName); - return; - } - else - { - ManagementPath newDrivePath = GetDiskDriveOnScsiController(vm, addressOnController); - if (newDrivePath == null) - { - newDrivePath = AttachDiskDriveToScsiController(vm, addressOnController); - } - InsertDiskImage(vm, diskPath, HARDDISK_DISK, newDrivePath); - } - } - - /// - /// - /// - /// IDE_HARDDISK_DRIVE or IDE_ISO_DRIVE - public ManagementPath AddDiskDriveToIdeController(ComputerSystem vm, string vhdfile, string cntrllerAddr, string driveResourceType) - { - logger.DebugFormat("Creating DISK for VM {0} (GUID {1}) by attaching {2}", - vm.ElementName, - vm.Name, - vhdfile); - - // Determine disk type for drive and assert drive type valid - string diskResourceSubType = null; - switch(driveResourceType) { - case HARDDISK_DRIVE: - diskResourceSubType = HARDDISK_DISK; - break; - case ISO_DRIVE: - diskResourceSubType = ISO_DISK; - break; - default: - var errMsg = string.Format( - "Unrecognised disk drive type {0} for VM {1} (GUID {2})", - string.IsNullOrEmpty(driveResourceType) ? "NULL": driveResourceType, - vm.ElementName, - vm.Name); - var ex = new WmiException(errMsg); - logger.Error(errMsg, ex); - throw ex; - } - - ManagementPath newDrivePath = AttachNewDrive(vm, cntrllerAddr, driveResourceType); - - // If there's not disk to insert, we are done. - if (String.IsNullOrEmpty(vhdfile)) - { - logger.DebugFormat("No disk to be added to drive, disk drive {0} is complete", newDrivePath.Path); - } - else - { - InsertDiskImage(vm, vhdfile, diskResourceSubType, newDrivePath); - } - return newDrivePath; - } - - - public void DetachDisk(string displayName, string diskFileName) - { - logger.DebugFormat("Got request to detach virtual disk {0} from vm {1}", diskFileName, displayName); - - ComputerSystem vm = GetComputerSystem(displayName); - if (vm == null) - { - logger.DebugFormat("VM {0} not found", displayName); - return; - } - else - { - RemoveStorageImage(vm, diskFileName); - } - } - - /// - /// Removes a disk image from a drive, but does not remove the drive itself. - /// - /// - /// - private void RemoveStorageImage(ComputerSystem vm, string diskFileName) - { - // Obtain StorageAllocationSettingData for disk - StorageAllocationSettingData.StorageAllocationSettingDataCollection storageSettingsObjs = StorageAllocationSettingData.GetInstances(); - - StorageAllocationSettingData imageToRemove = null; - foreach (StorageAllocationSettingData item in storageSettingsObjs) - { - if (item.HostResource == null || item.HostResource.Length != 1) - { - continue; - } - - string hostResource = item.HostResource[0]; - if (Path.Equals(hostResource, diskFileName)) - { - imageToRemove = item; - break; - } - } - - // assert - if (imageToRemove == null) - { - var errMsg = string.Format( - "Failed to remove disk image {0} from VM {1} (GUID {2}): the disk image is not attached.", - diskFileName, - vm.ElementName, - vm.Name); - var ex = new WmiException(errMsg); - logger.Error(errMsg, ex); - throw ex; - } - - RemoveStorageResource(imageToRemove.Path, vm); - - logger.InfoFormat("Removed disk image {0} from VM {1} (GUID {2}): the disk image is not attached.", - diskFileName, - vm.ElementName, - vm.Name); - } - - private ManagementPath AttachNewDrive(ComputerSystem vm, string cntrllerAddr, string driveType) - { - // Disk drives are attached to a 'Parent' IDE controller. We IDE Controller's settings for the 'Path', which our new Disk drive will use to reference it. - VirtualSystemSettingData vmSettings = GetVmSettings(vm); - var ctrller = GetIDEControllerSettings(vmSettings, cntrllerAddr); - - // A description of the drive is created by modifying a clone of the default ResourceAllocationSettingData for that drive type - string defaultDriveQuery = String.Format("ResourceSubType LIKE \"{0}\" AND InstanceID LIKE \"%Default\"", driveType); - var newDiskDriveSettings = CloneResourceAllocationSetting(defaultDriveQuery); - - // Set IDE controller and address on the controller for the new drive - newDiskDriveSettings.LateBoundObject["Parent"] = ctrller.Path.ToString(); - newDiskDriveSettings.LateBoundObject["AddressOnParent"] = "0"; - newDiskDriveSettings.CommitObject(); - - // Add this new disk drive to the VM - logger.DebugFormat("Creating disk drive type {0}, parent IDE controller is {1} and address on controller is {2}", - newDiskDriveSettings.ResourceSubType, - newDiskDriveSettings.Parent, - newDiskDriveSettings.AddressOnParent); - string[] newDriveResource = new string[] { newDiskDriveSettings.LateBoundObject.GetText(System.Management.TextFormat.CimDtd20) }; - ManagementPath[] newDrivePaths = AddVirtualResource(newDriveResource, vm); - - // assert - if (newDrivePaths.Length != 1) - { - var errMsg = string.Format( - "Failed to add disk drive type {3} to VM {0} (GUID {1}): number of resource created {2}", - vm.ElementName, - vm.Name, - newDrivePaths.Length, - driveType); - var ex = new WmiException(errMsg); - logger.Error(errMsg, ex); - throw ex; - } - logger.DebugFormat("New disk drive type {0} WMI path is {1}s", - newDiskDriveSettings.ResourceSubType, - newDrivePaths[0].Path); - return newDrivePaths[0]; - } - - private ManagementPath AddScsiController(ComputerSystem vm) - { - // A description of the controller is created by modifying a clone of the default ResourceAllocationSettingData for scsi controller - string scsiQuery = String.Format("ResourceSubType LIKE \"{0}\" AND InstanceID LIKE \"%Default\"", SCSI_CONTROLLER); - var scsiSettings = CloneResourceAllocationSetting(scsiQuery); - - scsiSettings.LateBoundObject["ElementName"] = "SCSI Controller"; - scsiSettings.CommitObject(); - - // Insert SCSI controller into vm - string[] newResources = new string[] { scsiSettings.LateBoundObject.GetText(System.Management.TextFormat.CimDtd20) }; - ManagementPath[] newResourcePaths = AddVirtualResource(newResources, vm); - - // assert - if (newResourcePaths.Length != 1) - { - var errMsg = string.Format( - "Failed to add scsi controller to VM {0} (GUID {1}): number of resource created {2}", - vm.ElementName, - vm.Name, - newResourcePaths.Length); - var ex = new WmiException(errMsg); - logger.Error(errMsg, ex); - throw ex; - } - - logger.DebugFormat("New controller type {0} WMI path is {1}s", - scsiSettings.ResourceSubType, - newResourcePaths[0].Path); - return newResourcePaths[0]; - } - - private ManagementPath GetDiskDriveOnScsiController(ComputerSystem vm, string addrOnController) - { - VirtualSystemSettingData vmSettings = GetVmSettings(vm); - var wmiObjCollection = GetResourceAllocationSettings(vmSettings); - foreach (ResourceAllocationSettingData wmiObj in wmiObjCollection) - { - if (wmiObj.ResourceSubType == HARDDISK_DRIVE) - { - ResourceAllocationSettingData parent = new ResourceAllocationSettingData(new ManagementObject(wmiObj.Parent)); - if (parent.ResourceSubType == SCSI_CONTROLLER && wmiObj.AddressOnParent == addrOnController) - { - return wmiObj.Path; - } - } - } - return null; - } - - private ManagementPath AttachDiskDriveToScsiController(ComputerSystem vm, string addrOnController) - { - // Disk drives are attached to a 'Parent' Scsi controller. - VirtualSystemSettingData vmSettings = GetVmSettings(vm); - var ctrller = GetScsiControllerSettings(vmSettings); - - // A description of the drive is created by modifying a clone of the default ResourceAllocationSettingData for that drive type - string defaultDriveQuery = String.Format("ResourceSubType LIKE \"{0}\" AND InstanceID LIKE \"%Default\"", HARDDISK_DRIVE); - var newDiskDriveSettings = CloneResourceAllocationSetting(defaultDriveQuery); - - // Set IDE controller and address on the controller for the new drive - newDiskDriveSettings.LateBoundObject["Parent"] = ctrller.Path.ToString(); - newDiskDriveSettings.LateBoundObject["AddressOnParent"] = addrOnController; - newDiskDriveSettings.CommitObject(); - - // Add this new disk drive to the VM - logger.DebugFormat("Creating disk drive type {0}, parent IDE controller is {1} and address on controller is {2}", - newDiskDriveSettings.ResourceSubType, - newDiskDriveSettings.Parent, - newDiskDriveSettings.AddressOnParent); - string[] newDriveResource = new string[] { newDiskDriveSettings.LateBoundObject.GetText(System.Management.TextFormat.CimDtd20) }; - ManagementPath[] newDrivePaths = AddVirtualResource(newDriveResource, vm); - - // assert - if (newDrivePaths.Length != 1) - { - var errMsg = string.Format( - "Failed to add disk drive type {3} to VM {0} (GUID {1}): number of resource created {2}", - vm.ElementName, - vm.Name, - newDrivePaths.Length, - HARDDISK_DRIVE); - var ex = new WmiException(errMsg); - logger.Error(errMsg, ex); - throw ex; - } - logger.DebugFormat("New disk drive type {0} WMI path is {1}s", - newDiskDriveSettings.ResourceSubType, - newDrivePaths[0].Path); - return newDrivePaths[0]; - } - - - private void InsertDiskImage(ComputerSystem vm, string diskImagePath, string diskResourceSubType, ManagementPath drivePath) - { - // A description of the disk is created by modifying a clone of the default ResourceAllocationSettingData for that disk type - string defaultDiskQuery = String.Format("ResourceSubType LIKE \"{0}\" AND InstanceID LIKE \"%Default\"", diskResourceSubType); - var newDiskSettings = CloneStorageAllocationSetting(defaultDiskQuery); - - // Set file containing the disk image - newDiskSettings.LateBoundObject["Parent"] = drivePath.Path; - - // V2 API uses HostResource to specify image, see http://msdn.microsoft.com/en-us/library/hh859775(v=vs.85).aspx - newDiskSettings.LateBoundObject["HostResource"] = new string[] { diskImagePath }; - newDiskSettings.CommitObject(); - - // Add the new Msvm_StorageAllocationSettingData object as a virtual hard disk to the vm. - string[] newDiskResource = new string[] { newDiskSettings.LateBoundObject.GetText(System.Management.TextFormat.CimDtd20) }; - ManagementPath[] newDiskPaths = AddStorageResource(newDiskResource, vm); - // assert - if (newDiskPaths.Length != 1) - { - var errMsg = string.Format( - "Failed to add disk image type {3} to VM {0} (GUID {1}): number of resource created {2}", - vm.ElementName, - vm.Name, - newDiskPaths.Length, - diskResourceSubType); - var ex = new WmiException(errMsg); - logger.Error(errMsg, ex); - throw ex; - } - logger.InfoFormat("Created disk {2} for VM {0} (GUID {1}), image {3} ", - vm.ElementName, - vm.Name, - newDiskPaths[0].Path, - diskImagePath); - } - - /// - /// Create Msvm_StorageAllocationSettingData corresponding to the ISO image, and - /// associate this with the VM's DVD drive. - /// - private void AttachIso(ComputerSystem vm, string isoPath) - { - // Disk drives are attached to a 'Parent' IDE controller. We IDE Controller's settings for the 'Path', which our new Disk drive will use to reference it. - VirtualSystemSettingData vmSettings = GetVmSettings(vm); - var driveWmiObj = GetDvdDriveSettings(vmSettings); - InsertDiskImage(vm, isoPath, ISO_DISK, driveWmiObj.Path); - } - - private static ResourceAllocationSettingData CloneResourceAllocationSetting(string wmiQuery) - { - var defaultDiskDriveSettingsObjs = ResourceAllocationSettingData.GetInstances(wmiQuery); - - // assert - if (defaultDiskDriveSettingsObjs.Count != 1) - { - var errMsg = string.Format("Failed to find Msvm_ResourceAllocationSettingData for the query {0}", wmiQuery); - var ex = new WmiException(errMsg); - logger.Error(errMsg, ex); - throw ex; - } - - ResourceAllocationSettingData defaultDiskDriveSettings = defaultDiskDriveSettingsObjs.OfType().First(); - return new ResourceAllocationSettingData((ManagementBaseObject)defaultDiskDriveSettings.LateBoundObject.Clone()); - } - // Modify the systemvm nic's VLAN id + // we need to reboot to get the hv kvp daemon get started vr gets configured. + if (vmName.StartsWith("r-") || vmName.StartsWith("s-") || vmName.StartsWith("v-")) + { + System.Threading.Thread.Sleep(90000); + } + logger.InfoFormat("Started VM {0}", vmName); + return newVm; + } + + public static Boolean pingResource(String ip) + { + PingOptions pingOptions = null; + PingReply pingReply = null; + IPAddress ipAddress = null; + Ping pingSender = new Ping(); + int numberOfPings = 6; + int pingTimeout = 1000; + int byteSize = 32; + byte[] buffer = new byte[byteSize]; + ipAddress = IPAddress.Parse(ip); + pingOptions = new PingOptions(); + for (int i = 0; i < numberOfPings; i++) + { + pingReply = pingSender.Send(ipAddress, pingTimeout, buffer, pingOptions); + if (pingReply.Status == IPStatus.Success) + { + System.Threading.Thread.Sleep(30000); + return true; + } + else + { + // wait for the second boot and then return with suces + System.Threading.Thread.Sleep(30000); + } + } + return false; + } + + private EthernetPortAllocationSettingData AttachNicToPort(ComputerSystem newVm, SyntheticEthernetPortSettingData newAdapter, String vSwitchName, int enableState) + { + // Get the virtual switch + VirtualEthernetSwitch vSwitch = GetExternalVirtSwitch(vSwitchName); + //check the the recevied vSwitch is the same as vSwitchName. + if (!vSwitchName.Equals("") && !vSwitch.ElementName.Equals(vSwitchName)) + { + var errMsg = string.Format("Internal error, coudl not find Virtual Switch with the name : " +vSwitchName); + var ex = new WmiException(errMsg); + logger.Error(errMsg, ex); + throw ex; + } + + // Create port for adapter + var defaultEthernetPortSettings = EthernetPortAllocationSettingData.GetInstances(vSwitch.Scope, "InstanceID LIKE \"%Default\""); + + // assert + if (defaultEthernetPortSettings.Count != 1) + { + var errMsg = string.Format("Internal error, coudl not find default EthernetPortAllocationSettingData instance"); + var ex = new WmiException(errMsg); + logger.Error(errMsg, ex); + throw ex; + } + + var defaultEthernetPortSettingsObj = defaultEthernetPortSettings.OfType().First(); + var newEthernetPortSettings = new EthernetPortAllocationSettingData((ManagementBaseObject)defaultEthernetPortSettingsObj.LateBoundObject.Clone()); + newEthernetPortSettings.LateBoundObject["Parent"] = newAdapter.Path.Path; + newEthernetPortSettings.LateBoundObject["HostResource"] = new string[] { vSwitch.Path.Path }; + newEthernetPortSettings.LateBoundObject["EnabledState"] = enableState; //3 disabled 2 Enabled + // Insert NIC into vm + string[] newResources = new string[] { newEthernetPortSettings.LateBoundObject.GetText(System.Management.TextFormat.CimDtd20) }; + ManagementPath[] newResourcePaths = AddVirtualResource(newResources, newVm); + + // assert + if (newResourcePaths.Length != 1) + { + var errMsg = string.Format( + "Failed to properly insert a single NIC on VM {0} (GUID {1}): number of resource created {2}", + newVm.ElementName, + newVm.Name, + newResourcePaths.Length); + var ex = new WmiException(errMsg); + logger.Error(errMsg, ex); + throw ex; + } + + return new EthernetPortAllocationSettingData(newResourcePaths[0]); + } + + /// this method is to add a dvd drive and attach the systemvm iso. + /// + public void patchSystemVmIso(String vmName, String systemVmIso) + { + ComputerSystem vmObject = GetComputerSystem(vmName); + AddDiskDriveToIdeController(vmObject, "", "1", ISO_DRIVE); + AttachIso(vmName, systemVmIso); + } + + public void AttachDisk(string vmName, string diskPath, string addressOnController) + { + logger.DebugFormat("Got request to attach disk {0} to vm {1}", diskPath, vmName); + + ComputerSystem vm = GetComputerSystem(vmName); + if (vm == null) + { + logger.DebugFormat("VM {0} not found", vmName); + return; + } + else + { + ManagementPath newDrivePath = GetDiskDriveOnScsiController(vm, addressOnController); + if (newDrivePath == null) + { + newDrivePath = AttachDiskDriveToScsiController(vm, addressOnController); + } + InsertDiskImage(vm, diskPath, HARDDISK_DISK, newDrivePath); + } + } + + /// + /// + /// + /// IDE_HARDDISK_DRIVE or IDE_ISO_DRIVE + public ManagementPath AddDiskDriveToIdeController(ComputerSystem vm, string vhdfile, string cntrllerAddr, string driveResourceType) + { + logger.DebugFormat("Creating DISK for VM {0} (GUID {1}) by attaching {2}", + vm.ElementName, + vm.Name, + vhdfile); + + // Determine disk type for drive and assert drive type valid + string diskResourceSubType = null; + switch(driveResourceType) { + case HARDDISK_DRIVE: + diskResourceSubType = HARDDISK_DISK; + break; + case ISO_DRIVE: + diskResourceSubType = ISO_DISK; + break; + default: + var errMsg = string.Format( + "Unrecognised disk drive type {0} for VM {1} (GUID {2})", + string.IsNullOrEmpty(driveResourceType) ? "NULL": driveResourceType, + vm.ElementName, + vm.Name); + var ex = new WmiException(errMsg); + logger.Error(errMsg, ex); + throw ex; + } + + ManagementPath newDrivePath = AttachNewDrive(vm, cntrllerAddr, driveResourceType); + + // If there's not disk to insert, we are done. + if (String.IsNullOrEmpty(vhdfile)) + { + logger.DebugFormat("No disk to be added to drive, disk drive {0} is complete", newDrivePath.Path); + } + else + { + InsertDiskImage(vm, vhdfile, diskResourceSubType, newDrivePath); + } + return newDrivePath; + } + + + public void DetachDisk(string displayName, string diskFileName) + { + logger.DebugFormat("Got request to detach virtual disk {0} from vm {1}", diskFileName, displayName); + + ComputerSystem vm = GetComputerSystem(displayName); + if (vm == null) + { + logger.DebugFormat("VM {0} not found", displayName); + return; + } + else + { + RemoveStorageImage(vm, diskFileName); + } + } + + /// + /// Removes a disk image from a drive, but does not remove the drive itself. + /// + /// + /// + private void RemoveStorageImage(ComputerSystem vm, string diskFileName) + { + // Obtain StorageAllocationSettingData for disk + StorageAllocationSettingData.StorageAllocationSettingDataCollection storageSettingsObjs = StorageAllocationSettingData.GetInstances(); + + StorageAllocationSettingData imageToRemove = null; + foreach (StorageAllocationSettingData item in storageSettingsObjs) + { + if (item.HostResource == null || item.HostResource.Length != 1) + { + continue; + } + + string hostResource = item.HostResource[0]; + if (Path.Equals(hostResource, diskFileName)) + { + imageToRemove = item; + break; + } + } + + // assert + if (imageToRemove == null) + { + var errMsg = string.Format( + "Failed to remove disk image {0} from VM {1} (GUID {2}): the disk image is not attached.", + diskFileName, + vm.ElementName, + vm.Name); + var ex = new WmiException(errMsg); + logger.Error(errMsg, ex); + throw ex; + } + + RemoveStorageResource(imageToRemove.Path, vm); + + logger.InfoFormat("Removed disk image {0} from VM {1} (GUID {2}): the disk image is not attached.", + diskFileName, + vm.ElementName, + vm.Name); + } + + private ManagementPath AttachNewDrive(ComputerSystem vm, string cntrllerAddr, string driveType) + { + // Disk drives are attached to a 'Parent' IDE controller. We IDE Controller's settings for the 'Path', which our new Disk drive will use to reference it. + VirtualSystemSettingData vmSettings = GetVmSettings(vm); + var ctrller = GetIDEControllerSettings(vmSettings, cntrllerAddr); + + // A description of the drive is created by modifying a clone of the default ResourceAllocationSettingData for that drive type + string defaultDriveQuery = String.Format("ResourceSubType LIKE \"{0}\" AND InstanceID LIKE \"%Default\"", driveType); + var newDiskDriveSettings = CloneResourceAllocationSetting(defaultDriveQuery); + + // Set IDE controller and address on the controller for the new drive + newDiskDriveSettings.LateBoundObject["Parent"] = ctrller.Path.ToString(); + newDiskDriveSettings.LateBoundObject["AddressOnParent"] = "0"; + newDiskDriveSettings.CommitObject(); + + // Add this new disk drive to the VM + logger.DebugFormat("Creating disk drive type {0}, parent IDE controller is {1} and address on controller is {2}", + newDiskDriveSettings.ResourceSubType, + newDiskDriveSettings.Parent, + newDiskDriveSettings.AddressOnParent); + string[] newDriveResource = new string[] { newDiskDriveSettings.LateBoundObject.GetText(System.Management.TextFormat.CimDtd20) }; + ManagementPath[] newDrivePaths = AddVirtualResource(newDriveResource, vm); + + // assert + if (newDrivePaths.Length != 1) + { + var errMsg = string.Format( + "Failed to add disk drive type {3} to VM {0} (GUID {1}): number of resource created {2}", + vm.ElementName, + vm.Name, + newDrivePaths.Length, + driveType); + var ex = new WmiException(errMsg); + logger.Error(errMsg, ex); + throw ex; + } + logger.DebugFormat("New disk drive type {0} WMI path is {1}s", + newDiskDriveSettings.ResourceSubType, + newDrivePaths[0].Path); + return newDrivePaths[0]; + } + + private ManagementPath AddScsiController(ComputerSystem vm) + { + // A description of the controller is created by modifying a clone of the default ResourceAllocationSettingData for scsi controller + string scsiQuery = String.Format("ResourceSubType LIKE \"{0}\" AND InstanceID LIKE \"%Default\"", SCSI_CONTROLLER); + var scsiSettings = CloneResourceAllocationSetting(scsiQuery); + + scsiSettings.LateBoundObject["ElementName"] = "SCSI Controller"; + scsiSettings.CommitObject(); + + // Insert SCSI controller into vm + string[] newResources = new string[] { scsiSettings.LateBoundObject.GetText(System.Management.TextFormat.CimDtd20) }; + ManagementPath[] newResourcePaths = AddVirtualResource(newResources, vm); + + // assert + if (newResourcePaths.Length != 1) + { + var errMsg = string.Format( + "Failed to add scsi controller to VM {0} (GUID {1}): number of resource created {2}", + vm.ElementName, + vm.Name, + newResourcePaths.Length); + var ex = new WmiException(errMsg); + logger.Error(errMsg, ex); + throw ex; + } + + logger.DebugFormat("New controller type {0} WMI path is {1}s", + scsiSettings.ResourceSubType, + newResourcePaths[0].Path); + return newResourcePaths[0]; + } + + private ManagementPath GetDiskDriveOnScsiController(ComputerSystem vm, string addrOnController) + { + VirtualSystemSettingData vmSettings = GetVmSettings(vm); + var wmiObjCollection = GetResourceAllocationSettings(vmSettings); + foreach (ResourceAllocationSettingData wmiObj in wmiObjCollection) + { + if (wmiObj.ResourceSubType == HARDDISK_DRIVE) + { + ResourceAllocationSettingData parent = new ResourceAllocationSettingData(new ManagementObject(wmiObj.Parent)); + if (parent.ResourceSubType == SCSI_CONTROLLER && wmiObj.AddressOnParent == addrOnController) + { + return wmiObj.Path; + } + } + } + return null; + } + + private ManagementPath AttachDiskDriveToScsiController(ComputerSystem vm, string addrOnController) + { + // Disk drives are attached to a 'Parent' Scsi controller. + VirtualSystemSettingData vmSettings = GetVmSettings(vm); + var ctrller = GetScsiControllerSettings(vmSettings); + + // A description of the drive is created by modifying a clone of the default ResourceAllocationSettingData for that drive type + string defaultDriveQuery = String.Format("ResourceSubType LIKE \"{0}\" AND InstanceID LIKE \"%Default\"", HARDDISK_DRIVE); + var newDiskDriveSettings = CloneResourceAllocationSetting(defaultDriveQuery); + + // Set IDE controller and address on the controller for the new drive + newDiskDriveSettings.LateBoundObject["Parent"] = ctrller.Path.ToString(); + newDiskDriveSettings.LateBoundObject["AddressOnParent"] = addrOnController; + newDiskDriveSettings.CommitObject(); + + // Add this new disk drive to the VM + logger.DebugFormat("Creating disk drive type {0}, parent IDE controller is {1} and address on controller is {2}", + newDiskDriveSettings.ResourceSubType, + newDiskDriveSettings.Parent, + newDiskDriveSettings.AddressOnParent); + string[] newDriveResource = new string[] { newDiskDriveSettings.LateBoundObject.GetText(System.Management.TextFormat.CimDtd20) }; + ManagementPath[] newDrivePaths = AddVirtualResource(newDriveResource, vm); + + // assert + if (newDrivePaths.Length != 1) + { + var errMsg = string.Format( + "Failed to add disk drive type {3} to VM {0} (GUID {1}): number of resource created {2}", + vm.ElementName, + vm.Name, + newDrivePaths.Length, + HARDDISK_DRIVE); + var ex = new WmiException(errMsg); + logger.Error(errMsg, ex); + throw ex; + } + logger.DebugFormat("New disk drive type {0} WMI path is {1}s", + newDiskDriveSettings.ResourceSubType, + newDrivePaths[0].Path); + return newDrivePaths[0]; + } + + + private void InsertDiskImage(ComputerSystem vm, string diskImagePath, string diskResourceSubType, ManagementPath drivePath) + { + // A description of the disk is created by modifying a clone of the default ResourceAllocationSettingData for that disk type + string defaultDiskQuery = String.Format("ResourceSubType LIKE \"{0}\" AND InstanceID LIKE \"%Default\"", diskResourceSubType); + var newDiskSettings = CloneStorageAllocationSetting(defaultDiskQuery); + + // Set file containing the disk image + newDiskSettings.LateBoundObject["Parent"] = drivePath.Path; + + // V2 API uses HostResource to specify image, see http://msdn.microsoft.com/en-us/library/hh859775(v=vs.85).aspx + newDiskSettings.LateBoundObject["HostResource"] = new string[] { diskImagePath }; + newDiskSettings.CommitObject(); + + // Add the new Msvm_StorageAllocationSettingData object as a virtual hard disk to the vm. + string[] newDiskResource = new string[] { newDiskSettings.LateBoundObject.GetText(System.Management.TextFormat.CimDtd20) }; + ManagementPath[] newDiskPaths = AddStorageResource(newDiskResource, vm); + // assert + if (newDiskPaths.Length != 1) + { + var errMsg = string.Format( + "Failed to add disk image type {3} to VM {0} (GUID {1}): number of resource created {2}", + vm.ElementName, + vm.Name, + newDiskPaths.Length, + diskResourceSubType); + var ex = new WmiException(errMsg); + logger.Error(errMsg, ex); + throw ex; + } + logger.InfoFormat("Created disk {2} for VM {0} (GUID {1}), image {3} ", + vm.ElementName, + vm.Name, + newDiskPaths[0].Path, + diskImagePath); + } + + /// + /// Create Msvm_StorageAllocationSettingData corresponding to the ISO image, and + /// associate this with the VM's DVD drive. + /// + private void AttachIso(ComputerSystem vm, string isoPath) + { + // Disk drives are attached to a 'Parent' IDE controller. We IDE Controller's settings for the 'Path', which our new Disk drive will use to reference it. + VirtualSystemSettingData vmSettings = GetVmSettings(vm); + var driveWmiObj = GetDvdDriveSettings(vmSettings); + InsertDiskImage(vm, isoPath, ISO_DISK, driveWmiObj.Path); + } + + private static ResourceAllocationSettingData CloneResourceAllocationSetting(string wmiQuery) + { + var defaultDiskDriveSettingsObjs = ResourceAllocationSettingData.GetInstances(wmiQuery); + + // assert + if (defaultDiskDriveSettingsObjs.Count != 1) + { + var errMsg = string.Format("Failed to find Msvm_ResourceAllocationSettingData for the query {0}", wmiQuery); + var ex = new WmiException(errMsg); + logger.Error(errMsg, ex); + throw ex; + } + + ResourceAllocationSettingData defaultDiskDriveSettings = defaultDiskDriveSettingsObjs.OfType().First(); + return new ResourceAllocationSettingData((ManagementBaseObject)defaultDiskDriveSettings.LateBoundObject.Clone()); + } + + // Modify the systemvm nic's VLAN id public void ModifyVmVLan(string vmName, String vlanid, String mac) - { - int enableState = 2; + { + int enableState = 2; bool enable = true; ComputerSystem vm = GetComputerSystem(vmName); SyntheticEthernetPortSettingData[] nicSettingsViaVm = GetEthernetPortSettings(vm); // Obtain controller for Hyper-V virtualisation subsystem - VirtualSystemManagementService vmMgmtSvc = GetVirtualisationSystemManagementService(); + VirtualSystemManagementService vmMgmtSvc = GetVirtualisationSystemManagementService(); EthernetPortAllocationSettingData networkAdapter = null; string normalisedMAC = string.Join("", (mac.Split(new char[] { ':' }))); int index = 0; @@ -934,268 +934,268 @@ namespace HypervResource break; } index++; - } - String vSwitchName = ""; + } + String vSwitchName = ""; VirtualEthernetSwitch vSwitch = GetExternalVirtSwitch(vSwitchName); - EthernetPortAllocationSettingData[] ethernetConnections = GetEthernetConnections(vm); - networkAdapter = ethernetConnections[index]; - networkAdapter.LateBoundObject["EnabledState"] = enableState; //3 disabled 2 Enabled - networkAdapter.LateBoundObject["HostResource"] = new string[] { vSwitch.Path.Path }; - - ModifyVmResources(vmMgmtSvc, vm, new String[] { - networkAdapter.LateBoundObject.GetText(TextFormat.CimDtd20) + EthernetPortAllocationSettingData[] ethernetConnections = GetEthernetConnections(vm); + networkAdapter = ethernetConnections[index]; + networkAdapter.LateBoundObject["EnabledState"] = enableState; //3 disabled 2 Enabled + networkAdapter.LateBoundObject["HostResource"] = new string[] { vSwitch.Path.Path }; + + ModifyVmResources(vmMgmtSvc, vm, new String[] { + networkAdapter.LateBoundObject.GetText(TextFormat.CimDtd20) }); - EthernetSwitchPortVlanSettingData vlanSettings = GetVlanSettings(ethernetConnections[index]); - - if (vlanSettings == null) - { - // when modifying nic to not connected dont create vlan - if (enable) - { - if (vlanid != null) - { - SetPortVlan(vlanid, networkAdapter); - } - } - } - else - { - if (enable) - { - if (vlanid != null) - { - //Assign vlan configuration to nic - vlanSettings.LateBoundObject["AccessVlanId"] = vlanid; - vlanSettings.LateBoundObject["OperationMode"] = 1; - ModifyFeatureVmResources(vmMgmtSvc, vm, new String[] { - vlanSettings.LateBoundObject.GetText(TextFormat.CimDtd20)}); - } - } - else - { - var virtSysMgmtSvc = GetVirtualisationSystemManagementService(); - - // This method will remove the vlan settings present on the Nic - ManagementPath jobPath; - var ret_val = virtSysMgmtSvc.RemoveFeatureSettings(new ManagementPath[] { vlanSettings.Path }, - out jobPath); - - // If the Job is done asynchronously - if (ret_val == ReturnCode.Started) - { - JobCompleted(jobPath); - } - else if (ret_val != ReturnCode.Completed) - { - var errMsg = string.Format( - "Failed to remove vlan resource {0} from VM {1} (GUID {2}) due to {3}", - vlanSettings.Path, - vm.ElementName, - vm.Name, - ReturnCode.ToString(ret_val)); - var ex = new WmiException(errMsg); - logger.Error(errMsg, ex); - } - } + EthernetSwitchPortVlanSettingData vlanSettings = GetVlanSettings(ethernetConnections[index]); + + if (vlanSettings == null) + { + // when modifying nic to not connected dont create vlan + if (enable) + { + if (vlanid != null) + { + SetPortVlan(vlanid, networkAdapter); + } + } + } + else + { + if (enable) + { + if (vlanid != null) + { + //Assign vlan configuration to nic + vlanSettings.LateBoundObject["AccessVlanId"] = vlanid; + vlanSettings.LateBoundObject["OperationMode"] = 1; + ModifyFeatureVmResources(vmMgmtSvc, vm, new String[] { + vlanSettings.LateBoundObject.GetText(TextFormat.CimDtd20)}); + } + } + else + { + var virtSysMgmtSvc = GetVirtualisationSystemManagementService(); + + // This method will remove the vlan settings present on the Nic + ManagementPath jobPath; + var ret_val = virtSysMgmtSvc.RemoveFeatureSettings(new ManagementPath[] { vlanSettings.Path }, + out jobPath); + + // If the Job is done asynchronously + if (ret_val == ReturnCode.Started) + { + JobCompleted(jobPath); + } + else if (ret_val != ReturnCode.Completed) + { + var errMsg = string.Format( + "Failed to remove vlan resource {0} from VM {1} (GUID {2}) due to {3}", + vlanSettings.Path, + vm.ElementName, + vm.Name, + ReturnCode.ToString(ret_val)); + var ex = new WmiException(errMsg); + logger.Error(errMsg, ex); + } + } } - } - - // This is disabling the VLAN settings on the specified nic. It works Awesome. - public void DisableNicVlan(String mac, String vmName) - { - ComputerSystem vm = GetComputerSystem(vmName); - SyntheticEthernetPortSettingData[] nicSettingsViaVm = GetEthernetPortSettings(vm); - // Obtain controller for Hyper-V virtualisation subsystem - VirtualSystemManagementService vmMgmtSvc = GetVirtualisationSystemManagementService(); - string normalisedMAC = string.Join("", (mac.Split(new char[] { ':' }))); - int index = 0; - foreach (SyntheticEthernetPortSettingData item in nicSettingsViaVm) - { - if (normalisedMAC.ToLower().Equals(item.Address.ToLower())) - { - break; - } - index++; - } - - //TODO: make sure the index wont be out of range. - - EthernetPortAllocationSettingData[] ethernetConnections = GetEthernetConnections(vm); - EthernetSwitchPortVlanSettingData vlanSettings = GetVlanSettings(ethernetConnections[index]); - - var virtSysMgmtSvc = GetVirtualisationSystemManagementService(); - - // This method will remove the vlan settings present on the Nic - ManagementPath jobPath; - var ret_val = virtSysMgmtSvc.RemoveFeatureSettings(new ManagementPath[]{ vlanSettings.Path}, - out jobPath); - - // If the Job is done asynchronously - if (ret_val == ReturnCode.Started) - { - JobCompleted(jobPath); - } - else if (ret_val != ReturnCode.Completed) - { - var errMsg = string.Format( - "Failed to remove vlan resource {0} from VM {1} (GUID {2}) due to {3}", - vlanSettings.Path, - vm.ElementName, - vm.Name, - ReturnCode.ToString(ret_val)); - var ex = new WmiException(errMsg); - logger.Error(errMsg, ex); - throw ex; - } } - // Modify All VM Nics to disable - public void DisableVmNics() - { - ComputerSystem vm = GetComputerSystem("test"); - EthernetPortAllocationSettingData[] ethernetConnections = GetEthernetConnections(vm); - // Get the virtual switch - VirtualEthernetSwitch vSwitch = GetExternalVirtSwitch("vswitch2"); - - foreach (EthernetPortAllocationSettingData epasd in ethernetConnections) - { - epasd.LateBoundObject["EnabledState"] = 2; //3 disabled 2 Enabled - epasd.LateBoundObject["HostResource"] = new string[] { vSwitch.Path.Path }; - - VirtualSystemManagementService vmMgmtSvc = GetVirtualisationSystemManagementService(); - ModifyVmResources(vmMgmtSvc, vm, new String[] { - epasd.LateBoundObject.GetText(TextFormat.CimDtd20) - }); - } + // This is disabling the VLAN settings on the specified nic. It works Awesome. + public void DisableNicVlan(String mac, String vmName) + { + ComputerSystem vm = GetComputerSystem(vmName); + SyntheticEthernetPortSettingData[] nicSettingsViaVm = GetEthernetPortSettings(vm); + // Obtain controller for Hyper-V virtualisation subsystem + VirtualSystemManagementService vmMgmtSvc = GetVirtualisationSystemManagementService(); + string normalisedMAC = string.Join("", (mac.Split(new char[] { ':' }))); + int index = 0; + foreach (SyntheticEthernetPortSettingData item in nicSettingsViaVm) + { + if (normalisedMAC.ToLower().Equals(item.Address.ToLower())) + { + break; + } + index++; + } + + //TODO: make sure the index wont be out of range. + + EthernetPortAllocationSettingData[] ethernetConnections = GetEthernetConnections(vm); + EthernetSwitchPortVlanSettingData vlanSettings = GetVlanSettings(ethernetConnections[index]); + + var virtSysMgmtSvc = GetVirtualisationSystemManagementService(); + + // This method will remove the vlan settings present on the Nic + ManagementPath jobPath; + var ret_val = virtSysMgmtSvc.RemoveFeatureSettings(new ManagementPath[]{ vlanSettings.Path}, + out jobPath); + + // If the Job is done asynchronously + if (ret_val == ReturnCode.Started) + { + JobCompleted(jobPath); + } + else if (ret_val != ReturnCode.Completed) + { + var errMsg = string.Format( + "Failed to remove vlan resource {0} from VM {1} (GUID {2}) due to {3}", + vlanSettings.Path, + vm.ElementName, + vm.Name, + ReturnCode.ToString(ret_val)); + var ex = new WmiException(errMsg); + logger.Error(errMsg, ex); + throw ex; + } } - // Modify the systemvm nic's VLAN id + // Modify All VM Nics to disable + public void DisableVmNics() + { + ComputerSystem vm = GetComputerSystem("test"); + EthernetPortAllocationSettingData[] ethernetConnections = GetEthernetConnections(vm); + // Get the virtual switch + VirtualEthernetSwitch vSwitch = GetExternalVirtSwitch("vswitch2"); + + foreach (EthernetPortAllocationSettingData epasd in ethernetConnections) + { + epasd.LateBoundObject["EnabledState"] = 2; //3 disabled 2 Enabled + epasd.LateBoundObject["HostResource"] = new string[] { vSwitch.Path.Path }; + + VirtualSystemManagementService vmMgmtSvc = GetVirtualisationSystemManagementService(); + ModifyVmResources(vmMgmtSvc, vm, new String[] { + epasd.LateBoundObject.GetText(TextFormat.CimDtd20) + }); + } + } + + // Modify the systemvm nic's VLAN id public void ModifyVmVLan(string vmName, String vlanid, uint pos, bool enable, string switchLabelName) - { + { // This if to modify the VPC VR nics // 1. Enable the network adapter and connect to a switch - // 2. modify the vlan id - int enableState = 2; - ComputerSystem vm = GetComputerSystem(vmName); - EthernetPortAllocationSettingData[] ethernetConnections = GetEthernetConnections(vm); - // Obtain controller for Hyper-V virtualisation subsystem - EthernetPortAllocationSettingData networkAdapter = null; - VirtualSystemManagementService vmMgmtSvc = GetVirtualisationSystemManagementService(); - - String vSwitchName = ""; - if (switchLabelName != null) - vSwitchName = switchLabelName; - VirtualEthernetSwitch vSwitch = GetExternalVirtSwitch(vSwitchName); - if (pos <= ethernetConnections.Length) - { - if (enable == false) - { - enableState = 3; - } - - networkAdapter = ethernetConnections[pos]; - networkAdapter.LateBoundObject["EnabledState"] = enableState; //3 disabled 2 Enabled - networkAdapter.LateBoundObject["HostResource"] = new string[] { vSwitch.Path.Path }; - ModifyVmResources(vmMgmtSvc, vm, new String[] { - networkAdapter.LateBoundObject.GetText(TextFormat.CimDtd20) - }); + // 2. modify the vlan id + int enableState = 2; + ComputerSystem vm = GetComputerSystem(vmName); + EthernetPortAllocationSettingData[] ethernetConnections = GetEthernetConnections(vm); + // Obtain controller for Hyper-V virtualisation subsystem + EthernetPortAllocationSettingData networkAdapter = null; + VirtualSystemManagementService vmMgmtSvc = GetVirtualisationSystemManagementService(); + + String vSwitchName = ""; + if (switchLabelName != null) + vSwitchName = switchLabelName; + VirtualEthernetSwitch vSwitch = GetExternalVirtSwitch(vSwitchName); + if (pos <= ethernetConnections.Length) + { + if (enable == false) + { + enableState = 3; + } + + networkAdapter = ethernetConnections[pos]; + networkAdapter.LateBoundObject["EnabledState"] = enableState; //3 disabled 2 Enabled + networkAdapter.LateBoundObject["HostResource"] = new string[] { vSwitch.Path.Path }; + ModifyVmResources(vmMgmtSvc, vm, new String[] { + networkAdapter.LateBoundObject.GetText(TextFormat.CimDtd20) + }); } // check when nic is disabled, removing vlan is required or not. - EthernetPortAllocationSettingData[] vmEthernetConnections = GetEthernetConnections(vm); - EthernetSwitchPortVlanSettingData vlanSettings = GetVlanSettings(vmEthernetConnections[pos]); - - if (vlanSettings == null) - { - // when modifying nic to not connected dont create vlan - if (enable) - { - if (vlanid != null) - { - SetPortVlan(vlanid, networkAdapter); - } - } - } - else - { - if (enable) - { - if (vlanid != null) - { - //Assign vlan configuration to nic - vlanSettings.LateBoundObject["AccessVlanId"] = vlanid; - vlanSettings.LateBoundObject["OperationMode"] = 1; + EthernetPortAllocationSettingData[] vmEthernetConnections = GetEthernetConnections(vm); + EthernetSwitchPortVlanSettingData vlanSettings = GetVlanSettings(vmEthernetConnections[pos]); + + if (vlanSettings == null) + { + // when modifying nic to not connected dont create vlan + if (enable) + { + if (vlanid != null) + { + SetPortVlan(vlanid, networkAdapter); + } + } + } + else + { + if (enable) + { + if (vlanid != null) + { + //Assign vlan configuration to nic + vlanSettings.LateBoundObject["AccessVlanId"] = vlanid; + vlanSettings.LateBoundObject["OperationMode"] = 1; ModifyFeatureVmResources(vmMgmtSvc, vm, new String[] { - vlanSettings.LateBoundObject.GetText(TextFormat.CimDtd20)}); - } - } - else - { - var virtSysMgmtSvc = GetVirtualisationSystemManagementService(); - - // This method will remove the vlan settings present on the Nic - ManagementPath jobPath; - var ret_val = virtSysMgmtSvc.RemoveFeatureSettings(new ManagementPath[] { vlanSettings.Path }, - out jobPath); - - // If the Job is done asynchronously - if (ret_val == ReturnCode.Started) - { - JobCompleted(jobPath); - } - else if (ret_val != ReturnCode.Completed) - { - var errMsg = string.Format( - "Failed to remove vlan resource {0} from VM {1} (GUID {2}) due to {3}", - vlanSettings.Path, - vm.ElementName, - vm.Name, - ReturnCode.ToString(ret_val)); - var ex = new WmiException(errMsg); - logger.Error(errMsg, ex); - } - } + vlanSettings.LateBoundObject.GetText(TextFormat.CimDtd20)}); + } + } + else + { + var virtSysMgmtSvc = GetVirtualisationSystemManagementService(); + + // This method will remove the vlan settings present on the Nic + ManagementPath jobPath; + var ret_val = virtSysMgmtSvc.RemoveFeatureSettings(new ManagementPath[] { vlanSettings.Path }, + out jobPath); + + // If the Job is done asynchronously + if (ret_val == ReturnCode.Started) + { + JobCompleted(jobPath); + } + else if (ret_val != ReturnCode.Completed) + { + var errMsg = string.Format( + "Failed to remove vlan resource {0} from VM {1} (GUID {2}) due to {3}", + vlanSettings.Path, + vm.ElementName, + vm.Name, + ReturnCode.ToString(ret_val)); + var ex = new WmiException(errMsg); + logger.Error(errMsg, ex); + } + } } } - public void AttachIso(string displayName, string iso) - { - logger.DebugFormat("Got request to attach iso {0} to vm {1}", iso, displayName); - - ComputerSystem vm = GetComputerSystem(displayName); - if (vm == null) - { - logger.DebugFormat("VM {0} not found", displayName); - return; - } - else - { - AttachIso(vm, iso); - } - } - - public void DestroyVm(dynamic jsonObj) - { - string vmToDestroy = jsonObj.vmName; - DestroyVm(vmToDestroy); - } - - /// - /// Remove all VMs and all SwitchPorts with the displayName. VHD gets deleted elsewhere. - /// - /// - public void DestroyVm(string displayName) - { - logger.DebugFormat("Got request to destroy vm {0}", displayName); - - var vm = GetComputerSystem(displayName); - if ( vm == null ) - { - logger.DebugFormat("VM {0} already destroyed (or never existed)", displayName); - return; - } - + public void AttachIso(string displayName, string iso) + { + logger.DebugFormat("Got request to attach iso {0} to vm {1}", iso, displayName); + + ComputerSystem vm = GetComputerSystem(displayName); + if (vm == null) + { + logger.DebugFormat("VM {0} not found", displayName); + return; + } + else + { + AttachIso(vm, iso); + } + } + + public void DestroyVm(dynamic jsonObj) + { + string vmToDestroy = jsonObj.vmName; + DestroyVm(vmToDestroy); + } + + /// + /// Remove all VMs and all SwitchPorts with the displayName. VHD gets deleted elsewhere. + /// + /// + public void DestroyVm(string displayName) + { + logger.DebugFormat("Got request to destroy vm {0}", displayName); + + var vm = GetComputerSystem(displayName); + if ( vm == null ) + { + logger.DebugFormat("VM {0} already destroyed (or never existed)", displayName); + return; + } + //try to shutdown vm first ShutdownVm(vm); @@ -1206,41 +1206,41 @@ namespace HypervResource // Remove VM logger.DebugFormat("Remove VM {0} (GUID {1})", vm.ElementName, vm.Name); - SetState(vm, RequiredState.Disabled); - - // Delete SwitchPort - logger.DebugFormat("Remove associated switch ports for VM {0} (GUID {1})", vm.ElementName, vm.Name); - DeleteSwitchPort(vm.ElementName); - - // Delete VM - var virtSysMgmtSvc = GetVirtualisationSystemManagementService(); - ManagementPath jobPath; - - do - { - logger.DebugFormat("Delete VM {0} (GUID {1})", vm.ElementName, vm.Name); - var ret_val = virtSysMgmtSvc.DestroySystem(vm.Path, out jobPath); - - if (ret_val == ReturnCode.Started) - { - JobCompleted(jobPath); - } - else if (ret_val != ReturnCode.Completed) - { - var errMsg = string.Format( - "Failed Delete VM {0} (GUID {1}) due to {2}", - vm.ElementName, - vm.Name, - ReturnCode.ToString(ret_val)); - var ex = new WmiException(errMsg); - logger.Error(errMsg, ex); - throw ex; - } - vm = GetComputerSystem(displayName); - } - while (vm != null); - } - + SetState(vm, RequiredState.Disabled); + + // Delete SwitchPort + logger.DebugFormat("Remove associated switch ports for VM {0} (GUID {1})", vm.ElementName, vm.Name); + DeleteSwitchPort(vm.ElementName); + + // Delete VM + var virtSysMgmtSvc = GetVirtualisationSystemManagementService(); + ManagementPath jobPath; + + do + { + logger.DebugFormat("Delete VM {0} (GUID {1})", vm.ElementName, vm.Name); + var ret_val = virtSysMgmtSvc.DestroySystem(vm.Path, out jobPath); + + if (ret_val == ReturnCode.Started) + { + JobCompleted(jobPath); + } + else if (ret_val != ReturnCode.Completed) + { + var errMsg = string.Format( + "Failed Delete VM {0} (GUID {1}) due to {2}", + vm.ElementName, + vm.Name, + ReturnCode.ToString(ret_val)); + var ex = new WmiException(errMsg); + logger.Error(errMsg, ex); + throw ex; + } + vm = GetComputerSystem(displayName); + } + while (vm != null); + } + public void ShutdownVm(ComputerSystem vm) { ShutdownComponent sc = GetShutdownComponent(vm); @@ -1267,464 +1267,464 @@ namespace HypervResource } } - /// - /// Migrates a vm to the given destination host - /// - /// - /// - public void MigrateVm(string vmName, string destination) - { - ComputerSystem vm = GetComputerSystem(vmName); - VirtualSystemMigrationSettingData migrationSettingData = VirtualSystemMigrationSettingData.CreateInstance(); - VirtualSystemMigrationService service = GetVirtualisationSystemMigrationService(); - - IPAddress addr = IPAddress.Parse(destination); - IPHostEntry entry = Dns.GetHostEntry(addr); - string[] destinationHost = new string[] { destination }; - - migrationSettingData.LateBoundObject["MigrationType"] = MigrationType.VirtualSystem; - migrationSettingData.LateBoundObject["TransportType"] = TransportType.TCP; - migrationSettingData.LateBoundObject["DestinationIPAddressList"] = destinationHost; - string migrationSettings = migrationSettingData.LateBoundObject.GetText(System.Management.TextFormat.CimDtd20); - - ManagementPath jobPath; - var ret_val = service.MigrateVirtualSystemToHost(vm.Path, entry.HostName, migrationSettings, null, null, out jobPath); - if (ret_val == ReturnCode.Started) - { - MigrationJobCompleted(jobPath); - } - else if (ret_val != ReturnCode.Completed) - { - var errMsg = string.Format( - "Failed migrating VM {0} (GUID {1}) due to {2}", - vm.ElementName, - vm.Name, - ReturnCode.ToString(ret_val)); - var ex = new WmiException(errMsg); - logger.Error(errMsg, ex); - throw ex; - } - } - - /// - /// Migrates the volume of a vm to a given destination storage - /// - /// - /// - /// - public void MigrateVolume(string vmName, string volume, string destination) - { - ComputerSystem vm = GetComputerSystem(vmName); - VirtualSystemMigrationSettingData migrationSettingData = VirtualSystemMigrationSettingData.CreateInstance(); - VirtualSystemMigrationService service = GetVirtualisationSystemMigrationService(); - StorageAllocationSettingData[] sasd = GetStorageSettings(vm); - - string[] rasds = null; - if (sasd != null) - { + /// + /// Migrates a vm to the given destination host + /// + /// + /// + public void MigrateVm(string vmName, string destination) + { + ComputerSystem vm = GetComputerSystem(vmName); + VirtualSystemMigrationSettingData migrationSettingData = VirtualSystemMigrationSettingData.CreateInstance(); + VirtualSystemMigrationService service = GetVirtualisationSystemMigrationService(); + + IPAddress addr = IPAddress.Parse(destination); + IPHostEntry entry = Dns.GetHostEntry(addr); + string[] destinationHost = new string[] { destination }; + + migrationSettingData.LateBoundObject["MigrationType"] = MigrationType.VirtualSystem; + migrationSettingData.LateBoundObject["TransportType"] = TransportType.TCP; + migrationSettingData.LateBoundObject["DestinationIPAddressList"] = destinationHost; + string migrationSettings = migrationSettingData.LateBoundObject.GetText(System.Management.TextFormat.CimDtd20); + + ManagementPath jobPath; + var ret_val = service.MigrateVirtualSystemToHost(vm.Path, entry.HostName, migrationSettings, null, null, out jobPath); + if (ret_val == ReturnCode.Started) + { + MigrationJobCompleted(jobPath); + } + else if (ret_val != ReturnCode.Completed) + { + var errMsg = string.Format( + "Failed migrating VM {0} (GUID {1}) due to {2}", + vm.ElementName, + vm.Name, + ReturnCode.ToString(ret_val)); + var ex = new WmiException(errMsg); + logger.Error(errMsg, ex); + throw ex; + } + } + + /// + /// Migrates the volume of a vm to a given destination storage + /// + /// + /// + /// + public void MigrateVolume(string vmName, string volume, string destination) + { + ComputerSystem vm = GetComputerSystem(vmName); + VirtualSystemMigrationSettingData migrationSettingData = VirtualSystemMigrationSettingData.CreateInstance(); + VirtualSystemMigrationService service = GetVirtualisationSystemMigrationService(); + StorageAllocationSettingData[] sasd = GetStorageSettings(vm); + + string[] rasds = null; + if (sasd != null) + { rasds = new string[1]; - foreach (StorageAllocationSettingData item in sasd) - { - string vhdFileName = Path.GetFileNameWithoutExtension(item.HostResource[0]); - if (!String.IsNullOrEmpty(vhdFileName) && vhdFileName.Equals(volume)) - { - string newVhdPath = Path.Combine(destination, Path.GetFileName(item.HostResource[0])); - item.LateBoundObject["HostResource"] = new string[] { newVhdPath }; - item.LateBoundObject["PoolId"] = ""; + foreach (StorageAllocationSettingData item in sasd) + { + string vhdFileName = Path.GetFileNameWithoutExtension(item.HostResource[0]); + if (!String.IsNullOrEmpty(vhdFileName) && vhdFileName.Equals(volume)) + { + string newVhdPath = Path.Combine(destination, Path.GetFileName(item.HostResource[0])); + item.LateBoundObject["HostResource"] = new string[] { newVhdPath }; + item.LateBoundObject["PoolId"] = ""; rasds[0] = item.LateBoundObject.GetText(System.Management.TextFormat.CimDtd20); break; - } - } - } - - migrationSettingData.LateBoundObject["MigrationType"] = MigrationType.Storage; - migrationSettingData.LateBoundObject["TransportType"] = TransportType.TCP; - string migrationSettings = migrationSettingData.LateBoundObject.GetText(System.Management.TextFormat.CimDtd20); - - ManagementPath jobPath; - var ret_val = service.MigrateVirtualSystemToHost(vm.Path, null, migrationSettings, rasds, null, out jobPath); - if (ret_val == ReturnCode.Started) - { - MigrationJobCompleted(jobPath); - } - else if (ret_val != ReturnCode.Completed) - { - var errMsg = string.Format( - "Failed migrating volume {0} of VM {1} (GUID {2}) due to {3}", - volume, - vm.ElementName, - vm.Name, - ReturnCode.ToString(ret_val)); - var ex = new WmiException(errMsg); - logger.Error(errMsg, ex); - throw ex; - } - } - - /// - /// Migrates the volume of a vm to a given destination storage - /// - /// - /// - /// volume to me migrated to which pool - public void MigrateVmWithVolume(string vmName, string destination, Dictionary volumeToPool) - { - ComputerSystem vm = GetComputerSystem(vmName); - VirtualSystemMigrationSettingData migrationSettingData = VirtualSystemMigrationSettingData.CreateInstance(); - VirtualSystemMigrationService service = GetVirtualisationSystemMigrationService(); - StorageAllocationSettingData[] sasd = GetStorageSettings(vm); - - string[] rasds = null; - if (sasd != null) - { - rasds = new string[sasd.Length]; - uint index = 0; - foreach (StorageAllocationSettingData item in sasd) - { - string vhdFileName = Path.GetFileNameWithoutExtension(item.HostResource[0]); - if (!String.IsNullOrEmpty(vhdFileName) && volumeToPool.ContainsKey(vhdFileName)) - { - string newVhdPath = Path.Combine(volumeToPool[vhdFileName], Path.GetFileName(item.HostResource[0])); - item.LateBoundObject["HostResource"] = new string[] { newVhdPath }; - item.LateBoundObject["PoolId"] = ""; - } - - rasds[index++] = item.LateBoundObject.GetText(System.Management.TextFormat.CimDtd20); - } - } - - IPAddress addr = IPAddress.Parse(destination); - IPHostEntry entry = Dns.GetHostEntry(addr); - string[] destinationHost = new string[] { destination }; - - migrationSettingData.LateBoundObject["MigrationType"] = MigrationType.VirtualSystemAndStorage; - migrationSettingData.LateBoundObject["TransportType"] = TransportType.TCP; - migrationSettingData.LateBoundObject["DestinationIPAddressList"] = destinationHost; - string migrationSettings = migrationSettingData.LateBoundObject.GetText(System.Management.TextFormat.CimDtd20); - - ManagementPath jobPath; - var ret_val = service.MigrateVirtualSystemToHost(vm.Path, entry.HostName, migrationSettings, rasds, null, out jobPath); - if (ret_val == ReturnCode.Started) - { - MigrationJobCompleted(jobPath); - } - else if (ret_val != ReturnCode.Completed) - { - var errMsg = string.Format( - "Failed migrating VM {0} and its volumes to destination {1} (GUID {2}) due to {3}", - vm.ElementName, - destination, - vm.Name, - ReturnCode.ToString(ret_val)); - var ex = new WmiException(errMsg); - logger.Error(errMsg, ex); - throw ex; - } - } - - /// - /// Create new storage media resources, e.g. hard disk images and ISO disk images - /// see http://msdn.microsoft.com/en-us/library/hh859775(v=vs.85).aspx - /// - /// - /// - private static StorageAllocationSettingData CloneStorageAllocationSetting(string wmiQuery) - { - var defaultDiskImageSettingsObjs = StorageAllocationSettingData.GetInstances(wmiQuery); - - // assert - if (defaultDiskImageSettingsObjs.Count != 1) - { - var errMsg = string.Format("Failed to find Msvm_StorageAllocationSettingData for the query {0}", wmiQuery); - var ex = new WmiException(errMsg); - logger.Error(errMsg, ex); - throw ex; - } - - StorageAllocationSettingData defaultDiskDriveSettings = defaultDiskImageSettingsObjs.OfType().First(); - return new StorageAllocationSettingData((ManagementBaseObject)defaultDiskDriveSettings.LateBoundObject.Clone()); - } - - /// < summary> - /// Removes a storage resource from a computer system. - /// - /// Path that uniquely identifies the resource. - /// VM to which the disk image will be attached. - // Add new - private void RemoveNetworkResource(ManagementPath resourcePath) - { - var virtSwitchMgmtSvc = GetVirtualSwitchManagementService(); - ManagementPath jobPath; - var ret_val = virtSwitchMgmtSvc.RemoveResourceSettings( - new ManagementPath[] { resourcePath }, - out jobPath); - - // If the Job is done asynchronously - if (ret_val == ReturnCode.Started) - { - JobCompleted(jobPath); - } - else if (ret_val != ReturnCode.Completed) - { - var errMsg = string.Format( - "Failed to remove network resources {0} from switch due to {1}", - resourcePath.Path, - ReturnCode.ToString(ret_val)); - var ex = new WmiException(errMsg); - logger.Error(errMsg, ex); - throw ex; - } - } - - /// < summary> - /// Removes a storage resource from a computer system. - /// - /// Path that uniquely identifies the resource. - /// VM to which the disk image will be attached. - private void RemoveStorageResource(ManagementPath resourcePath, ComputerSystem vm) - { - var virtSysMgmtSvc = GetVirtualisationSystemManagementService(); - - ManagementPath jobPath; - var ret_val = virtSysMgmtSvc.RemoveResourceSettings( - new ManagementPath[] { resourcePath }, - out jobPath); - - // If the Job is done asynchronously - if (ret_val == ReturnCode.Started) - { - JobCompleted(jobPath); - } - else if (ret_val != ReturnCode.Completed) - { - var errMsg = string.Format( - "Failed to remove resource {0} from VM {1} (GUID {2}) due to {3}", - resourcePath.Path, - vm.ElementName, - vm.Name, - ReturnCode.ToString(ret_val)); - var ex = new WmiException(errMsg); - logger.Error(errMsg, ex); - throw ex; - } - } - - public void SetState(ComputerSystem vm, ushort requiredState) - { - logger.InfoFormat( - "Changing state of {0} (GUID {1}) to {2}", - vm.ElementName, - vm.Name, - RequiredState.ToString(requiredState)); - - ManagementPath jobPath; - // DateTime is unused - var ret_val = vm.RequestStateChange(requiredState, new DateTime(), out jobPath); - - // If the Job is done asynchronously - if (ret_val == ReturnCode.Started) - { - JobCompleted(jobPath); - } - else if (ret_val == 32775) - { // TODO: check - logger.InfoFormat("RequestStateChange returned 32775, which means vm in wrong state for requested state change. Treating as if requested state was reached"); - } - else if (ret_val != ReturnCode.Completed) - { - var errMsg = string.Format( - "Failed to change state of VM {0} (GUID {1}) to {2} due to {3}", - vm.ElementName, - vm.Name, - RequiredState.ToString(requiredState), - ReturnCode.ToString(ret_val)); - var ex = new WmiException(errMsg); - logger.Error(errMsg, ex); - throw ex; - } - - logger.InfoFormat( - "Successfully changed vm state of {0} (GUID {1} to requested state {2}", - vm.ElementName, - vm.Name, - requiredState); - } - - - //TODO: Write method to delete SwitchPort based on Name - /// - /// Delete switch port by removing settings from the switch - /// - /// - /// - public void DeleteSwitchPort(string elementName) - { - // Get NIC path - var condition = string.Format("ElementName=\"{0}\"", elementName); - var virtSwitchMgmtSvc = GetVirtualSwitchManagementService(); - - var switchPortCollection = EthernetSwitchPort.GetInstances(virtSwitchMgmtSvc.Scope, condition); - if (switchPortCollection.Count == 0) - { - return; - } - - foreach (EthernetSwitchPort port in switchPortCollection) - { - var settings = GetSyntheticEthernetPortSettings(port); - RemoveNetworkResource(settings.Path); - } - } - - public SyntheticEthernetPortSettingData GetSyntheticEthernetPortSettings(EthernetSwitchPort port) - { - // An ASSOCIATOR object provides the cross reference from the EthernetSwitchPort and the - // SyntheticEthernetPortSettingData, but generated wrappers do not expose a ASSOCIATOR OF query as a method. - // Instead, we use the System.Management to code the equivalant of - // string query = string.Format( "ASSOCIATORS OF {{{0}}} WHERE ResultClass = {1}", vm.path, resultclassName); - // - var wmiObjQuery = new RelatedObjectQuery(port.Path.Path, SyntheticEthernetPortSettingData.CreatedClassName); - - // NB: default scope of ManagementObjectSearcher is '\\.\root\cimv2', which does not contain - // the virtualisation objects. - var wmiObjectSearch = new ManagementObjectSearcher(port.Scope, wmiObjQuery); - var wmiObjCollection = new SyntheticEthernetPortSettingData.SyntheticEthernetPortSettingDataCollection(wmiObjectSearch.Get()); - - // When snapshots are taken into account, there can be multiple settings objects - // take the first one that isn't a snapshot - foreach (SyntheticEthernetPortSettingData wmiObj in wmiObjCollection) - { - return wmiObj; - } - - var errMsg = string.Format("No SyntheticEthernetPortSettingData for port {0}, path {1}", port.ElementName, port.Path.Path); - var ex = new WmiException(errMsg); - logger.Error(errMsg, ex); - throw ex; - } - - /// - /// Adds storage images to coputer system (disk image, iso image). - /// - /// Msvm_StorageAllocationSettings with HostResource configured with image - /// file and Parent set to a controller associated with the ComputerSystem - /// VM to which the disk image will be attached. - // Add new - private ManagementPath[] AddStorageResource(string[] storageSettings, ComputerSystem vm) - { - return AddVirtualResource(storageSettings, vm); - } - - private ManagementPath[] AddVirtualResource(string[] resourceSettings, ComputerSystem vm ) - { - var virtSysMgmtSvc = GetVirtualisationSystemManagementService(); - - ManagementPath jobPath; - ManagementPath[] resourcePaths; - var ret_val = virtSysMgmtSvc.AddResourceSettings( - vm.Path, - resourceSettings, - out jobPath, - out resourcePaths); - - // If the Job is done asynchronously - if (ret_val == ReturnCode.Started) - { - JobCompleted(jobPath); - } - else if (ret_val != ReturnCode.Completed) - { - var errMsg = string.Format( - "Failed to add resources to VM {0} (GUID {1}) due to {2}", - vm.ElementName, - vm.Name, - ReturnCode.ToString(ret_val)); - var ex = new WmiException(errMsg); - logger.Error(errMsg, ex); - throw ex; - } - - return resourcePaths; - } - - private ManagementPath[] AddFeatureSettings(string[] featureSettings, ManagementPath affectedConfiguration) - { - var virtSysMgmtSvc = GetVirtualisationSystemManagementService(); - - ManagementPath jobPath; - ManagementPath[] resultSettings; - var ret_val = virtSysMgmtSvc.AddFeatureSettings( - affectedConfiguration, - featureSettings, - out jobPath, - out resultSettings); - - // If the Job is done asynchronously - if (ret_val == ReturnCode.Started) - { - JobCompleted(jobPath); - } - else if (ret_val != ReturnCode.Completed) - { - var errMsg = string.Format( - "Failed to add features settings {0} to resource {1} due to {2}", - featureSettings, - affectedConfiguration, - ReturnCode.ToString(ret_val)); - var ex = new WmiException(errMsg); - logger.Error(errMsg, ex); - throw ex; - } - - return resultSettings; - } - - private ManagementPath SetPortVlan(string vlan, EthernetPortAllocationSettingData portPath) - { - logger.DebugFormat("Setting VLAN to {0}", vlan); - - var vmVirtMgmtSvc = GetVirtualisationSystemManagementService(); - EthernetSwitchPortVlanSettingData.GetInstances(); - - // Create NIC resource by cloning the default NIC - var vlanSettings = EthernetSwitchPortVlanSettingData.GetInstances(vmVirtMgmtSvc.Scope, "InstanceID LIKE \"%Default\""); - - // Assert - if (vlanSettings.Count != 1) - { - var errMsg = string.Format("Internal error, could not find default EthernetSwitchPortVlanSettingData instance"); - var ex = new WmiException(errMsg); - logger.Error(errMsg, ex); - throw ex; - } - var defaultVlanSettings = vlanSettings.OfType().First(); - - var newVlanSettings = new EthernetSwitchPortVlanSettingData((ManagementBaseObject)defaultVlanSettings.LateBoundObject.Clone()); - - // Assign configuration to new NIC - newVlanSettings.LateBoundObject["AccessVlanId"] = vlan; - newVlanSettings.LateBoundObject["OperationMode"] = 1; // Access=1, trunk=2, private=3 ; - newVlanSettings.CommitObject(); - - // Insert NIC into vm - string[] newResources = new string[] { newVlanSettings.LateBoundObject.GetText(System.Management.TextFormat.CimDtd20) }; - ManagementPath[] newResourcePaths = AddFeatureSettings(newResources, portPath.Path); - - // assert - if (newResourcePaths.Length != 1) - { - var errMsg = string.Format( - "Failed to properly set VLAN to {0} for NIC on port {1}", - vlan, - portPath.Path); - var ex = new WmiException(errMsg); - logger.Error(errMsg, ex); - throw ex; - } - - return newResourcePaths[0]; - } - + } + } + } + + migrationSettingData.LateBoundObject["MigrationType"] = MigrationType.Storage; + migrationSettingData.LateBoundObject["TransportType"] = TransportType.TCP; + string migrationSettings = migrationSettingData.LateBoundObject.GetText(System.Management.TextFormat.CimDtd20); + + ManagementPath jobPath; + var ret_val = service.MigrateVirtualSystemToHost(vm.Path, null, migrationSettings, rasds, null, out jobPath); + if (ret_val == ReturnCode.Started) + { + MigrationJobCompleted(jobPath); + } + else if (ret_val != ReturnCode.Completed) + { + var errMsg = string.Format( + "Failed migrating volume {0} of VM {1} (GUID {2}) due to {3}", + volume, + vm.ElementName, + vm.Name, + ReturnCode.ToString(ret_val)); + var ex = new WmiException(errMsg); + logger.Error(errMsg, ex); + throw ex; + } + } + + /// + /// Migrates the volume of a vm to a given destination storage + /// + /// + /// + /// volume to me migrated to which pool + public void MigrateVmWithVolume(string vmName, string destination, Dictionary volumeToPool) + { + ComputerSystem vm = GetComputerSystem(vmName); + VirtualSystemMigrationSettingData migrationSettingData = VirtualSystemMigrationSettingData.CreateInstance(); + VirtualSystemMigrationService service = GetVirtualisationSystemMigrationService(); + StorageAllocationSettingData[] sasd = GetStorageSettings(vm); + + string[] rasds = null; + if (sasd != null) + { + rasds = new string[sasd.Length]; + uint index = 0; + foreach (StorageAllocationSettingData item in sasd) + { + string vhdFileName = Path.GetFileNameWithoutExtension(item.HostResource[0]); + if (!String.IsNullOrEmpty(vhdFileName) && volumeToPool.ContainsKey(vhdFileName)) + { + string newVhdPath = Path.Combine(volumeToPool[vhdFileName], Path.GetFileName(item.HostResource[0])); + item.LateBoundObject["HostResource"] = new string[] { newVhdPath }; + item.LateBoundObject["PoolId"] = ""; + } + + rasds[index++] = item.LateBoundObject.GetText(System.Management.TextFormat.CimDtd20); + } + } + + IPAddress addr = IPAddress.Parse(destination); + IPHostEntry entry = Dns.GetHostEntry(addr); + string[] destinationHost = new string[] { destination }; + + migrationSettingData.LateBoundObject["MigrationType"] = MigrationType.VirtualSystemAndStorage; + migrationSettingData.LateBoundObject["TransportType"] = TransportType.TCP; + migrationSettingData.LateBoundObject["DestinationIPAddressList"] = destinationHost; + string migrationSettings = migrationSettingData.LateBoundObject.GetText(System.Management.TextFormat.CimDtd20); + + ManagementPath jobPath; + var ret_val = service.MigrateVirtualSystemToHost(vm.Path, entry.HostName, migrationSettings, rasds, null, out jobPath); + if (ret_val == ReturnCode.Started) + { + MigrationJobCompleted(jobPath); + } + else if (ret_val != ReturnCode.Completed) + { + var errMsg = string.Format( + "Failed migrating VM {0} and its volumes to destination {1} (GUID {2}) due to {3}", + vm.ElementName, + destination, + vm.Name, + ReturnCode.ToString(ret_val)); + var ex = new WmiException(errMsg); + logger.Error(errMsg, ex); + throw ex; + } + } + + /// + /// Create new storage media resources, e.g. hard disk images and ISO disk images + /// see http://msdn.microsoft.com/en-us/library/hh859775(v=vs.85).aspx + /// + /// + /// + private static StorageAllocationSettingData CloneStorageAllocationSetting(string wmiQuery) + { + var defaultDiskImageSettingsObjs = StorageAllocationSettingData.GetInstances(wmiQuery); + + // assert + if (defaultDiskImageSettingsObjs.Count != 1) + { + var errMsg = string.Format("Failed to find Msvm_StorageAllocationSettingData for the query {0}", wmiQuery); + var ex = new WmiException(errMsg); + logger.Error(errMsg, ex); + throw ex; + } + + StorageAllocationSettingData defaultDiskDriveSettings = defaultDiskImageSettingsObjs.OfType().First(); + return new StorageAllocationSettingData((ManagementBaseObject)defaultDiskDriveSettings.LateBoundObject.Clone()); + } + + /// < summary> + /// Removes a storage resource from a computer system. + /// + /// Path that uniquely identifies the resource. + /// VM to which the disk image will be attached. + // Add new + private void RemoveNetworkResource(ManagementPath resourcePath) + { + var virtSwitchMgmtSvc = GetVirtualSwitchManagementService(); + ManagementPath jobPath; + var ret_val = virtSwitchMgmtSvc.RemoveResourceSettings( + new ManagementPath[] { resourcePath }, + out jobPath); + + // If the Job is done asynchronously + if (ret_val == ReturnCode.Started) + { + JobCompleted(jobPath); + } + else if (ret_val != ReturnCode.Completed) + { + var errMsg = string.Format( + "Failed to remove network resources {0} from switch due to {1}", + resourcePath.Path, + ReturnCode.ToString(ret_val)); + var ex = new WmiException(errMsg); + logger.Error(errMsg, ex); + throw ex; + } + } + + /// < summary> + /// Removes a storage resource from a computer system. + /// + /// Path that uniquely identifies the resource. + /// VM to which the disk image will be attached. + private void RemoveStorageResource(ManagementPath resourcePath, ComputerSystem vm) + { + var virtSysMgmtSvc = GetVirtualisationSystemManagementService(); + + ManagementPath jobPath; + var ret_val = virtSysMgmtSvc.RemoveResourceSettings( + new ManagementPath[] { resourcePath }, + out jobPath); + + // If the Job is done asynchronously + if (ret_val == ReturnCode.Started) + { + JobCompleted(jobPath); + } + else if (ret_val != ReturnCode.Completed) + { + var errMsg = string.Format( + "Failed to remove resource {0} from VM {1} (GUID {2}) due to {3}", + resourcePath.Path, + vm.ElementName, + vm.Name, + ReturnCode.ToString(ret_val)); + var ex = new WmiException(errMsg); + logger.Error(errMsg, ex); + throw ex; + } + } + + public void SetState(ComputerSystem vm, ushort requiredState) + { + logger.InfoFormat( + "Changing state of {0} (GUID {1}) to {2}", + vm.ElementName, + vm.Name, + RequiredState.ToString(requiredState)); + + ManagementPath jobPath; + // DateTime is unused + var ret_val = vm.RequestStateChange(requiredState, new DateTime(), out jobPath); + + // If the Job is done asynchronously + if (ret_val == ReturnCode.Started) + { + JobCompleted(jobPath); + } + else if (ret_val == 32775) + { // TODO: check + logger.InfoFormat("RequestStateChange returned 32775, which means vm in wrong state for requested state change. Treating as if requested state was reached"); + } + else if (ret_val != ReturnCode.Completed) + { + var errMsg = string.Format( + "Failed to change state of VM {0} (GUID {1}) to {2} due to {3}", + vm.ElementName, + vm.Name, + RequiredState.ToString(requiredState), + ReturnCode.ToString(ret_val)); + var ex = new WmiException(errMsg); + logger.Error(errMsg, ex); + throw ex; + } + + logger.InfoFormat( + "Successfully changed vm state of {0} (GUID {1} to requested state {2}", + vm.ElementName, + vm.Name, + requiredState); + } + + + //TODO: Write method to delete SwitchPort based on Name + /// + /// Delete switch port by removing settings from the switch + /// + /// + /// + public void DeleteSwitchPort(string elementName) + { + // Get NIC path + var condition = string.Format("ElementName=\"{0}\"", elementName); + var virtSwitchMgmtSvc = GetVirtualSwitchManagementService(); + + var switchPortCollection = EthernetSwitchPort.GetInstances(virtSwitchMgmtSvc.Scope, condition); + if (switchPortCollection.Count == 0) + { + return; + } + + foreach (EthernetSwitchPort port in switchPortCollection) + { + var settings = GetSyntheticEthernetPortSettings(port); + RemoveNetworkResource(settings.Path); + } + } + + public SyntheticEthernetPortSettingData GetSyntheticEthernetPortSettings(EthernetSwitchPort port) + { + // An ASSOCIATOR object provides the cross reference from the EthernetSwitchPort and the + // SyntheticEthernetPortSettingData, but generated wrappers do not expose a ASSOCIATOR OF query as a method. + // Instead, we use the System.Management to code the equivalant of + // string query = string.Format( "ASSOCIATORS OF {{{0}}} WHERE ResultClass = {1}", vm.path, resultclassName); + // + var wmiObjQuery = new RelatedObjectQuery(port.Path.Path, SyntheticEthernetPortSettingData.CreatedClassName); + + // NB: default scope of ManagementObjectSearcher is '\\.\root\cimv2', which does not contain + // the virtualisation objects. + var wmiObjectSearch = new ManagementObjectSearcher(port.Scope, wmiObjQuery); + var wmiObjCollection = new SyntheticEthernetPortSettingData.SyntheticEthernetPortSettingDataCollection(wmiObjectSearch.Get()); + + // When snapshots are taken into account, there can be multiple settings objects + // take the first one that isn't a snapshot + foreach (SyntheticEthernetPortSettingData wmiObj in wmiObjCollection) + { + return wmiObj; + } + + var errMsg = string.Format("No SyntheticEthernetPortSettingData for port {0}, path {1}", port.ElementName, port.Path.Path); + var ex = new WmiException(errMsg); + logger.Error(errMsg, ex); + throw ex; + } + + /// + /// Adds storage images to coputer system (disk image, iso image). + /// + /// Msvm_StorageAllocationSettings with HostResource configured with image + /// file and Parent set to a controller associated with the ComputerSystem + /// VM to which the disk image will be attached. + // Add new + private ManagementPath[] AddStorageResource(string[] storageSettings, ComputerSystem vm) + { + return AddVirtualResource(storageSettings, vm); + } + + private ManagementPath[] AddVirtualResource(string[] resourceSettings, ComputerSystem vm ) + { + var virtSysMgmtSvc = GetVirtualisationSystemManagementService(); + + ManagementPath jobPath; + ManagementPath[] resourcePaths; + var ret_val = virtSysMgmtSvc.AddResourceSettings( + vm.Path, + resourceSettings, + out jobPath, + out resourcePaths); + + // If the Job is done asynchronously + if (ret_val == ReturnCode.Started) + { + JobCompleted(jobPath); + } + else if (ret_val != ReturnCode.Completed) + { + var errMsg = string.Format( + "Failed to add resources to VM {0} (GUID {1}) due to {2}", + vm.ElementName, + vm.Name, + ReturnCode.ToString(ret_val)); + var ex = new WmiException(errMsg); + logger.Error(errMsg, ex); + throw ex; + } + + return resourcePaths; + } + + private ManagementPath[] AddFeatureSettings(string[] featureSettings, ManagementPath affectedConfiguration) + { + var virtSysMgmtSvc = GetVirtualisationSystemManagementService(); + + ManagementPath jobPath; + ManagementPath[] resultSettings; + var ret_val = virtSysMgmtSvc.AddFeatureSettings( + affectedConfiguration, + featureSettings, + out jobPath, + out resultSettings); + + // If the Job is done asynchronously + if (ret_val == ReturnCode.Started) + { + JobCompleted(jobPath); + } + else if (ret_val != ReturnCode.Completed) + { + var errMsg = string.Format( + "Failed to add features settings {0} to resource {1} due to {2}", + featureSettings, + affectedConfiguration, + ReturnCode.ToString(ret_val)); + var ex = new WmiException(errMsg); + logger.Error(errMsg, ex); + throw ex; + } + + return resultSettings; + } + + private ManagementPath SetPortVlan(string vlan, EthernetPortAllocationSettingData portPath) + { + logger.DebugFormat("Setting VLAN to {0}", vlan); + + var vmVirtMgmtSvc = GetVirtualisationSystemManagementService(); + EthernetSwitchPortVlanSettingData.GetInstances(); + + // Create NIC resource by cloning the default NIC + var vlanSettings = EthernetSwitchPortVlanSettingData.GetInstances(vmVirtMgmtSvc.Scope, "InstanceID LIKE \"%Default\""); + + // Assert + if (vlanSettings.Count != 1) + { + var errMsg = string.Format("Internal error, could not find default EthernetSwitchPortVlanSettingData instance"); + var ex = new WmiException(errMsg); + logger.Error(errMsg, ex); + throw ex; + } + var defaultVlanSettings = vlanSettings.OfType().First(); + + var newVlanSettings = new EthernetSwitchPortVlanSettingData((ManagementBaseObject)defaultVlanSettings.LateBoundObject.Clone()); + + // Assign configuration to new NIC + newVlanSettings.LateBoundObject["AccessVlanId"] = vlan; + newVlanSettings.LateBoundObject["OperationMode"] = 1; // Access=1, trunk=2, private=3 ; + newVlanSettings.CommitObject(); + + // Insert NIC into vm + string[] newResources = new string[] { newVlanSettings.LateBoundObject.GetText(System.Management.TextFormat.CimDtd20) }; + ManagementPath[] newResourcePaths = AddFeatureSettings(newResources, portPath.Path); + + // assert + if (newResourcePaths.Length != 1) + { + var errMsg = string.Format( + "Failed to properly set VLAN to {0} for NIC on port {1}", + vlan, + portPath.Path); + var ex = new WmiException(errMsg); + logger.Error(errMsg, ex); + throw ex; + } + + return newResourcePaths[0]; + } + private void SetBandWidthLimit(ulong limit, EthernetPortAllocationSettingData portPath) { logger.DebugFormat("Setting network rate limit to {0}", limit); @@ -1762,101 +1762,101 @@ namespace HypervResource } } - - /// - /// External VSwitch has an external NIC, and we assume there is only one external NIC and one external vswitch. - /// - /// - /// - /// Throws if there is no vswitch - /// - /// With V1 API, external ethernet port was attached to the land endpoint, which was attached to the switch. - /// e.g. Msvm_ExternalEthernetPort -> SwitchLANEndpoint -> SwitchPort -> VirtualSwitch - /// - /// With V2 API, there are two kinds of lan endpoint: one on the computer system and one on the switch - /// e.g. Msvm_ExternalEthernetPort -> LANEndpoint -> LANEdnpoint -> EthernetSwitchPort -> VirtualEthernetSwitch - /// - public static VirtualEthernetSwitch GetExternalVirtSwitch(String vSwitchName) - { - // Work back from the first *bound* external NIC we find. - var externNICs = ExternalEthernetPort.GetInstances("IsBound = TRUE"); - VirtualEthernetSwitch vSwitch = null; - // Assert - if (externNICs.Count == 0 ) - { - var errMsg = "No ExternalEthernetPort available to Hyper-V"; - var ex = new WmiException(errMsg); - logger.Error(errMsg, ex); - throw ex; - } - foreach(ExternalEthernetPort externNIC in externNICs.OfType()) { - // A sequence of ASSOCIATOR objects need to be traversed to get from external NIC the vswitch. - // We use ManagementObjectSearcher objects to execute this sequence of questions - // NB: default scope of ManagementObjectSearcher is '\\.\root\cimv2', which does not contain - // the virtualisation objects. - var endpointQuery = new RelatedObjectQuery(externNIC.Path.Path, LANEndpoint.CreatedClassName); - var endpointSearch = new ManagementObjectSearcher(externNIC.Scope, endpointQuery); - var endpointCollection = new LANEndpoint.LANEndpointCollection(endpointSearch.Get()); - - // assert - if (endpointCollection.Count < 1 ) - { - var errMsg = string.Format("No adapter-based LANEndpoint for external NIC {0} on Hyper-V server", externNIC.Name); - var ex = new WmiException(errMsg); - logger.Error(errMsg, ex); - throw ex; - } - - LANEndpoint adapterEndPoint = endpointCollection.OfType().First(); - var switchEndpointQuery = new RelatedObjectQuery(adapterEndPoint.Path.Path, LANEndpoint.CreatedClassName); - var switchEndpointSearch = new ManagementObjectSearcher(externNIC.Scope, switchEndpointQuery); - var switchEndpointCollection = new LANEndpoint.LANEndpointCollection(switchEndpointSearch.Get()); - - // assert - if (endpointCollection.Count < 1) - { - var errMsg = string.Format("No Switch-based LANEndpoint for external NIC {0} on Hyper-V server", externNIC.Name); - var ex = new WmiException(errMsg); - logger.Error(errMsg, ex); - throw ex; - } - - LANEndpoint switchEndPoint = switchEndpointCollection.OfType().First(); - var switchPortQuery = new RelatedObjectQuery(switchEndPoint.Path.Path, EthernetSwitchPort.CreatedClassName); - var switchPortSearch = new ManagementObjectSearcher(switchEndPoint.Scope, switchPortQuery); - var switchPortCollection = new EthernetSwitchPort.EthernetSwitchPortCollection(switchPortSearch.Get()); - - // assert - if (switchPortCollection.Count < 1 ) - { - var errMsg = string.Format("No SwitchPort for external NIC {0} on Hyper-V server", externNIC.Name); - var ex = new WmiException(errMsg); - logger.Error(errMsg, ex); - throw ex; - } - - EthernetSwitchPort switchPort = switchPortCollection.OfType().First(); - var vSwitchQuery = new RelatedObjectQuery(switchPort.Path.Path, VirtualEthernetSwitch.CreatedClassName); - var vSwitchSearch = new ManagementObjectSearcher(externNIC.Scope, vSwitchQuery); - var vSwitchCollection = new VirtualEthernetSwitch.VirtualEthernetSwitchCollection(vSwitchSearch.Get()); - - // assert - if (vSwitchCollection.Count < 1) - { - var errMsg = string.Format("No virtual switch for external NIC {0} on Hyper-V server", externNIC.Name); - var ex = new WmiException(errMsg); - logger.Error(errMsg, ex); - throw ex; - } - vSwitch = vSwitchCollection.OfType().First(); - if (vSwitch.ElementName.Equals(vSwitchName) == true) - { - return vSwitch; - } - } - return vSwitch; - } - + + /// + /// External VSwitch has an external NIC, and we assume there is only one external NIC and one external vswitch. + /// + /// + /// + /// Throws if there is no vswitch + /// + /// With V1 API, external ethernet port was attached to the land endpoint, which was attached to the switch. + /// e.g. Msvm_ExternalEthernetPort -> SwitchLANEndpoint -> SwitchPort -> VirtualSwitch + /// + /// With V2 API, there are two kinds of lan endpoint: one on the computer system and one on the switch + /// e.g. Msvm_ExternalEthernetPort -> LANEndpoint -> LANEdnpoint -> EthernetSwitchPort -> VirtualEthernetSwitch + /// + public static VirtualEthernetSwitch GetExternalVirtSwitch(String vSwitchName) + { + // Work back from the first *bound* external NIC we find. + var externNICs = ExternalEthernetPort.GetInstances("IsBound = TRUE"); + VirtualEthernetSwitch vSwitch = null; + // Assert + if (externNICs.Count == 0 ) + { + var errMsg = "No ExternalEthernetPort available to Hyper-V"; + var ex = new WmiException(errMsg); + logger.Error(errMsg, ex); + throw ex; + } + foreach(ExternalEthernetPort externNIC in externNICs.OfType()) { + // A sequence of ASSOCIATOR objects need to be traversed to get from external NIC the vswitch. + // We use ManagementObjectSearcher objects to execute this sequence of questions + // NB: default scope of ManagementObjectSearcher is '\\.\root\cimv2', which does not contain + // the virtualisation objects. + var endpointQuery = new RelatedObjectQuery(externNIC.Path.Path, LANEndpoint.CreatedClassName); + var endpointSearch = new ManagementObjectSearcher(externNIC.Scope, endpointQuery); + var endpointCollection = new LANEndpoint.LANEndpointCollection(endpointSearch.Get()); + + // assert + if (endpointCollection.Count < 1 ) + { + var errMsg = string.Format("No adapter-based LANEndpoint for external NIC {0} on Hyper-V server", externNIC.Name); + var ex = new WmiException(errMsg); + logger.Error(errMsg, ex); + throw ex; + } + + LANEndpoint adapterEndPoint = endpointCollection.OfType().First(); + var switchEndpointQuery = new RelatedObjectQuery(adapterEndPoint.Path.Path, LANEndpoint.CreatedClassName); + var switchEndpointSearch = new ManagementObjectSearcher(externNIC.Scope, switchEndpointQuery); + var switchEndpointCollection = new LANEndpoint.LANEndpointCollection(switchEndpointSearch.Get()); + + // assert + if (endpointCollection.Count < 1) + { + var errMsg = string.Format("No Switch-based LANEndpoint for external NIC {0} on Hyper-V server", externNIC.Name); + var ex = new WmiException(errMsg); + logger.Error(errMsg, ex); + throw ex; + } + + LANEndpoint switchEndPoint = switchEndpointCollection.OfType().First(); + var switchPortQuery = new RelatedObjectQuery(switchEndPoint.Path.Path, EthernetSwitchPort.CreatedClassName); + var switchPortSearch = new ManagementObjectSearcher(switchEndPoint.Scope, switchPortQuery); + var switchPortCollection = new EthernetSwitchPort.EthernetSwitchPortCollection(switchPortSearch.Get()); + + // assert + if (switchPortCollection.Count < 1 ) + { + var errMsg = string.Format("No SwitchPort for external NIC {0} on Hyper-V server", externNIC.Name); + var ex = new WmiException(errMsg); + logger.Error(errMsg, ex); + throw ex; + } + + EthernetSwitchPort switchPort = switchPortCollection.OfType().First(); + var vSwitchQuery = new RelatedObjectQuery(switchPort.Path.Path, VirtualEthernetSwitch.CreatedClassName); + var vSwitchSearch = new ManagementObjectSearcher(externNIC.Scope, vSwitchQuery); + var vSwitchCollection = new VirtualEthernetSwitch.VirtualEthernetSwitchCollection(vSwitchSearch.Get()); + + // assert + if (vSwitchCollection.Count < 1) + { + var errMsg = string.Format("No virtual switch for external NIC {0} on Hyper-V server", externNIC.Name); + var ex = new WmiException(errMsg); + logger.Error(errMsg, ex); + throw ex; + } + vSwitch = vSwitchCollection.OfType().First(); + if (vSwitch.ElementName.Equals(vSwitchName) == true) + { + return vSwitch; + } + } + return vSwitch; + } + private static void ModifyFeatureVmResources(VirtualSystemManagementService vmMgmtSvc, ComputerSystem vm, string[] resourceSettings) { @@ -1887,35 +1887,35 @@ namespace HypervResource } } - private static void ModifyVmResources(VirtualSystemManagementService vmMgmtSvc, ComputerSystem vm, string[] resourceSettings) - { - // Resource settings are changed through the management service - System.Management.ManagementPath jobPath; - System.Management.ManagementPath[] results; - - var ret_val = vmMgmtSvc.ModifyResourceSettings( - resourceSettings, - out jobPath, - out results); - - // If the Job is done asynchronously - if (ret_val == ReturnCode.Started) - { - JobCompleted(jobPath); - } - else if (ret_val != ReturnCode.Completed) - { - var errMsg = string.Format( - "Failed to update VM {0} (GUID {1}) due to {2} (ModifyVirtualSystem call), existing VM not deleted", - vm.ElementName, - vm.Name, - ReturnCode.ToString(ret_val)); - var ex = new WmiException(errMsg); - logger.Error(errMsg, ex); - throw ex; - } - } - + private static void ModifyVmResources(VirtualSystemManagementService vmMgmtSvc, ComputerSystem vm, string[] resourceSettings) + { + // Resource settings are changed through the management service + System.Management.ManagementPath jobPath; + System.Management.ManagementPath[] results; + + var ret_val = vmMgmtSvc.ModifyResourceSettings( + resourceSettings, + out jobPath, + out results); + + // If the Job is done asynchronously + if (ret_val == ReturnCode.Started) + { + JobCompleted(jobPath); + } + else if (ret_val != ReturnCode.Completed) + { + var errMsg = string.Format( + "Failed to update VM {0} (GUID {1}) due to {2} (ModifyVirtualSystem call), existing VM not deleted", + vm.ElementName, + vm.Name, + ReturnCode.ToString(ret_val)); + var ex = new WmiException(errMsg); + logger.Error(errMsg, ex); + throw ex; + } + } + private static void ModifySystemSetting(VirtualSystemManagementService vmMgmtSvc, string systemSettings) { // Resource settings are changed through the management service @@ -1941,43 +1941,43 @@ namespace HypervResource } } - public void DeleteHostKvpItem(ComputerSystem vm, string key) - { - // Obtain controller for Hyper-V virtualisation subsystem - VirtualSystemManagementService vmMgmtSvc = GetVirtualisationSystemManagementService(); - - // Create object to hold the data. - KvpExchangeDataItem kvpItem = KvpExchangeDataItem.CreateInstance(); - kvpItem.LateBoundObject["Name"] = WmiCallsV2.CloudStackUserDataKey; - kvpItem.LateBoundObject["Data"] = "dummy"; - kvpItem.LateBoundObject["Source"] = 0; - logger.Debug("VM " + vm.Name + " will have KVP key " + key + " removed."); - - String kvpStr = kvpItem.LateBoundObject.GetText(TextFormat.CimDtd20); - - // Update the resource settings for the VM. - ManagementPath jobPath; - - uint ret_val = vmMgmtSvc.RemoveKvpItems(new String[] { kvpStr }, vm.Path, out jobPath); - - // If the Job is done asynchronously - if (ret_val == ReturnCode.Started) - { - JobCompleted(jobPath); - } - else if (ret_val != ReturnCode.Completed) - { - var errMsg = string.Format( - "Failed to update VM {0} (GUID {1}) due to {2} (ModifyVirtualSystem call), existing VM not deleted", - vm.ElementName, - vm.Name, - ReturnCode.ToString(ret_val)); - var ex = new WmiException(errMsg); - logger.Error(errMsg, ex); - throw ex; - } - } - + public void DeleteHostKvpItem(ComputerSystem vm, string key) + { + // Obtain controller for Hyper-V virtualisation subsystem + VirtualSystemManagementService vmMgmtSvc = GetVirtualisationSystemManagementService(); + + // Create object to hold the data. + KvpExchangeDataItem kvpItem = KvpExchangeDataItem.CreateInstance(); + kvpItem.LateBoundObject["Name"] = WmiCallsV2.CloudStackUserDataKey; + kvpItem.LateBoundObject["Data"] = "dummy"; + kvpItem.LateBoundObject["Source"] = 0; + logger.Debug("VM " + vm.Name + " will have KVP key " + key + " removed."); + + String kvpStr = kvpItem.LateBoundObject.GetText(TextFormat.CimDtd20); + + // Update the resource settings for the VM. + ManagementPath jobPath; + + uint ret_val = vmMgmtSvc.RemoveKvpItems(new String[] { kvpStr }, vm.Path, out jobPath); + + // If the Job is done asynchronously + if (ret_val == ReturnCode.Started) + { + JobCompleted(jobPath); + } + else if (ret_val != ReturnCode.Completed) + { + var errMsg = string.Format( + "Failed to update VM {0} (GUID {1}) due to {2} (ModifyVirtualSystem call), existing VM not deleted", + vm.ElementName, + vm.Name, + ReturnCode.ToString(ret_val)); + var ex = new WmiException(errMsg); + logger.Error(errMsg, ex); + throw ex; + } + } + public Boolean TagVm(ComputerSystem vm) { VirtualSystemManagementService vmMgmtSvc = GetVirtualisationSystemManagementService(); @@ -1988,332 +1988,332 @@ namespace HypervResource return true; } - private static ComputerSystem CreateDefaultVm(VirtualSystemManagementService vmMgmtSvc, string name) - { - // Tweak default settings by basing new VM on default global setting object - // with designed display name. + private static ComputerSystem CreateDefaultVm(VirtualSystemManagementService vmMgmtSvc, string name) + { + // Tweak default settings by basing new VM on default global setting object + // with designed display name. UInt16 startupAction = 2; // Do nothing. UInt16 stopAction = 4; // Shutdown. - VirtualSystemSettingData vs_gs_data = VirtualSystemSettingData.CreateInstance(); - vs_gs_data.LateBoundObject["ElementName"] = name; + VirtualSystemSettingData vs_gs_data = VirtualSystemSettingData.CreateInstance(); + vs_gs_data.LateBoundObject["ElementName"] = name; vs_gs_data.LateBoundObject["AutomaticStartupAction"] = startupAction.ToString(); vs_gs_data.LateBoundObject["AutomaticShutdownAction"] = stopAction.ToString(); vs_gs_data.LateBoundObject["Notes"] = new string[] { "CloudStack creating VM, do not edit. \n" }; - - System.Management.ManagementPath jobPath; - System.Management.ManagementPath defined_sys; - var ret_val = vmMgmtSvc.DefineSystem( - null, - new string[0], - vs_gs_data.LateBoundObject.GetText(System.Management.TextFormat.CimDtd20), - out jobPath, - out defined_sys); - - // If the Job is done asynchronously - if (ret_val == ReturnCode.Started) - { - JobCompleted(jobPath); - } - else if (ret_val != ReturnCode.Completed) - { - var errMsg = string.Format( - "Failed to create VM {0} due to {1} (DefineVirtualSystem call)", - name, ReturnCode.ToString(ret_val)); - var ex = new WmiException(errMsg); - logger.Error(errMsg, ex); - throw ex; - } - - logger.DebugFormat(CultureInfo.InvariantCulture, "Created VM {0}", name); - - // Is the defined_system real? - var vm = new ComputerSystem(defined_sys); - - // Assertion - if (vm.ElementName.CompareTo(name) != 0) - { - var errMsg = string.Format( - "New VM created with wrong name (is {0}, should be {1}, GUID {2})", - vm.ElementName, - name, - vm.Name); - var ex = new WmiException(errMsg); - logger.Error(errMsg, ex); - throw ex; - } - - return vm; - } - - public VirtualEthernetSwitchManagementService GetVirtualSwitchManagementService() - { - // VirtualSwitchManagementService is a singleton, most anonymous way of lookup is by asking for the set - // of local instances, which should be size 1. - var virtSwtichSvcCollection = VirtualEthernetSwitchManagementService.GetInstances(); - foreach (VirtualEthernetSwitchManagementService item in virtSwtichSvcCollection) - { - return item; - } - - var errMsg = string.Format("No Hyper-V subsystem on server"); - var ex = new WmiException(errMsg); - logger.Error(errMsg, ex); - throw ex; - } - - /// - /// Always produces a VHDX. - /// - /// - /// - public void CreateDynamicVirtualHardDisk(ulong MaxInternalSize, string Path) - { - // Produce description of the virtual disk in the format of a Msvm_VirtualHardDiskSettings object - - // Example at http://www.getcodesamples.com/src/FC025DDC/76689747, but - // Is there a template we can use to fill in the settings? - var newVirtHDSettings = VirtualHardDiskSettingData.CreateInstance(); - newVirtHDSettings.LateBoundObject["Type"] = 3; // Dynamic - newVirtHDSettings.LateBoundObject["Format"] = 3; // VHDX - newVirtHDSettings.LateBoundObject["Path"] = Path; - newVirtHDSettings.LateBoundObject["MaxInternalSize"] = MaxInternalSize; - newVirtHDSettings.LateBoundObject["BlockSize"] = 0; // Use defaults - newVirtHDSettings.LateBoundObject["LogicalSectorSize"] = 0; // Use defaults - newVirtHDSettings.LateBoundObject["PhysicalSectorSize"] = 0; // Use defaults - - // Optional: newVirtHDSettings.CommitObject(); - - // Add the new vhd object as a virtual hard disk to the vm. - string newVirtHDSettingsString = newVirtHDSettings.LateBoundObject.GetText(System.Management.TextFormat.CimDtd20); - - // Resource settings are changed through the management service - System.Management.ManagementPath jobPath; - var imgMgr = GetImageManagementService(); - var ret_val = imgMgr.CreateVirtualHardDisk(newVirtHDSettingsString, out jobPath); - - // If the Job is done asynchronously - if (ret_val == ReturnCode.Started) - { - StorageJobCompleted(jobPath); - } - else if (ret_val != ReturnCode.Completed) - { - var errMsg = string.Format( - "Failed to CreateVirtualHardDisk size {0}, path {1} due to {2}", - MaxInternalSize, - Path, - ReturnCode.ToString(ret_val)); - var ex = new WmiException(errMsg); - logger.Error(errMsg, ex); - throw ex; - } - } - - public ImageManagementService GetImageManagementService() - { - // VirtualSystemManagementService is a singleton, most anonymous way of lookup is by asking for the set - // of local instances, which should be size 1. - - var coll = ImageManagementService.GetInstances(); - foreach (ImageManagementService item in coll) - { - return item; - } - - var errMsg = string.Format("No Hyper-V subsystem on server"); - var ex = new WmiException(errMsg); - logger.Error(errMsg, ex); - throw ex; - } - - - public VirtualSystemManagementService GetVirtualisationSystemManagementService() - { - // VirtualSystemManagementService is a singleton, most anonymous way of lookup is by asking for the set - // of local instances, which should be size 1. - - var virtSysMgmtSvcCollection = VirtualSystemManagementService.GetInstances(); - foreach (VirtualSystemManagementService item in virtSysMgmtSvcCollection) - { - return item; - } - - var errMsg = string.Format("No Hyper-V subsystem on server"); - var ex = new WmiException(errMsg); - logger.Error(errMsg, ex); - throw ex; - } - - public VirtualSystemMigrationService GetVirtualisationSystemMigrationService() - { - - var virtSysMigSvcCollection = VirtualSystemMigrationService.GetInstances(); - foreach (VirtualSystemMigrationService item in virtSysMigSvcCollection) - { - return item; - } - - var errMsg = string.Format("No Hyper-V migration service subsystem on server"); - var ex = new WmiException(errMsg); - logger.Error(errMsg, ex); - throw ex; - } - - /// - /// Similar to http://msdn.microsoft.com/en-us/library/hh850031%28v=vs.85%29.aspx - /// - /// - /// - private static void JobCompleted(ManagementPath jobPath) - { - ConcreteJob jobObj = null; - for(;;) - { - jobObj = new ConcreteJob(jobPath); - if (jobObj.JobState != JobState.Starting && jobObj.JobState != JobState.Running) - { - break; - } - logger.InfoFormat("In progress... {0}% completed.", jobObj.PercentComplete); - System.Threading.Thread.Sleep(1000); - } - - if (jobObj.JobState != JobState.Completed) - { - var errMsg = string.Format( - "Hyper-V Job failed, Error Code:{0}, Description: {1}", - jobObj.ErrorCode, - jobObj.ErrorDescription); - var ex = new WmiException(errMsg); - logger.Error(errMsg, ex); - throw ex; - } - - logger.DebugFormat("WMI job succeeded: {0}, Elapsed={1}", jobObj.Description, jobObj.ElapsedTime); - } - - private static void MigrationJobCompleted(ManagementPath jobPath) - { - MigrationJob jobObj = null; - for (;;) - { - jobObj = new MigrationJob(jobPath); - if (jobObj.JobState != JobState.Starting && jobObj.JobState != JobState.Running) - { - break; - } - logger.InfoFormat("In progress... {0}% completed.", jobObj.PercentComplete); - System.Threading.Thread.Sleep(1000); - } - - if (jobObj.JobState != JobState.Completed) - { - var errMsg = string.Format( - "Hyper-V Job failed, Error Code:{0}, Description: {1}", - jobObj.ErrorCode, - jobObj.ErrorDescription); - var ex = new WmiException(errMsg); - logger.Error(errMsg, ex); - throw ex; - } - } - - private static void StorageJobCompleted(ManagementPath jobPath) - { - StorageJob jobObj = null; - for (; ; ) - { - jobObj = new StorageJob(jobPath); - if (jobObj.JobState != JobState.Starting && jobObj.JobState != JobState.Running) - { - break; - } - logger.InfoFormat("In progress... {0}% completed.", jobObj.PercentComplete); - System.Threading.Thread.Sleep(1000); - } - - if (jobObj.JobState != JobState.Completed) - { - var errMsg = string.Format( - "Hyper-V Job failed, Error Code:{0}, Description: {1}", - jobObj.ErrorCode, - jobObj.ErrorDescription); - var ex = new WmiException(errMsg); - logger.Error(errMsg, ex); - throw ex; - } - } - - public void GetProcessorResources(out uint sockets, out uint cores, out uint mhz) - { - // Processor processors - cores = 0; - mhz = 0; - sockets = 0; - Processor.ProcessorCollection procCol = Processor.GetInstances(); - foreach (Processor procInfo in procCol) - { - cores += procInfo.NumberOfCores; - mhz = procInfo.MaxClockSpeed; - sockets++; - } - } - - public void GetProcessorUsageInfo(out double cpuUtilization) - { - PerfFormattedData_Counters_ProcessorInformation.PerfFormattedData_Counters_ProcessorInformationCollection coll = - PerfFormattedData_Counters_ProcessorInformation.GetInstances("Name=\"_Total\""); - cpuUtilization = 100; - // Use the first one - foreach (PerfFormattedData_Counters_ProcessorInformation procInfo in coll) - { - // Idle during a given internal - // See http://library.wmifun.net/cimv2/win32_perfformatteddata_counters_processorinformation.html - cpuUtilization = 100.0 - (double)procInfo.PercentIdleTime; - } - } - - - public void GetMemoryResources(out ulong physicalRamKBs, out ulong freeMemoryKBs) - { - OperatingSystem0 os = new OperatingSystem0(); - physicalRamKBs = os.TotalVisibleMemorySize; - freeMemoryKBs = os.FreePhysicalMemory; - } - - public string GetDefaultVirtualDiskFolder() - { - VirtualSystemManagementServiceSettingData.VirtualSystemManagementServiceSettingDataCollection coll = VirtualSystemManagementServiceSettingData.GetInstances(); - string defaultVirtualHardDiskPath = null; - foreach (VirtualSystemManagementServiceSettingData settings in coll) - { - defaultVirtualHardDiskPath = settings.DefaultVirtualHardDiskPath; - } - - // assert - if (!System.IO.Directory.Exists(defaultVirtualHardDiskPath) ){ - var errMsg = string.Format( - "Hyper-V DefaultVirtualHardDiskPath is invalid!"); - logger.Error(errMsg); - return null; - } - - return defaultVirtualHardDiskPath; - } - - public ComputerSystem GetComputerSystem(string displayName) - { - var wmiQuery = String.Format("ElementName=\"{0}\"", displayName); - ComputerSystem.ComputerSystemCollection vmCollection = ComputerSystem.GetInstances(wmiQuery); - - // Return the first one - foreach (ComputerSystem vm in vmCollection) - { - return vm; - } - return null; - } - + + System.Management.ManagementPath jobPath; + System.Management.ManagementPath defined_sys; + var ret_val = vmMgmtSvc.DefineSystem( + null, + new string[0], + vs_gs_data.LateBoundObject.GetText(System.Management.TextFormat.CimDtd20), + out jobPath, + out defined_sys); + + // If the Job is done asynchronously + if (ret_val == ReturnCode.Started) + { + JobCompleted(jobPath); + } + else if (ret_val != ReturnCode.Completed) + { + var errMsg = string.Format( + "Failed to create VM {0} due to {1} (DefineVirtualSystem call)", + name, ReturnCode.ToString(ret_val)); + var ex = new WmiException(errMsg); + logger.Error(errMsg, ex); + throw ex; + } + + logger.DebugFormat(CultureInfo.InvariantCulture, "Created VM {0}", name); + + // Is the defined_system real? + var vm = new ComputerSystem(defined_sys); + + // Assertion + if (vm.ElementName.CompareTo(name) != 0) + { + var errMsg = string.Format( + "New VM created with wrong name (is {0}, should be {1}, GUID {2})", + vm.ElementName, + name, + vm.Name); + var ex = new WmiException(errMsg); + logger.Error(errMsg, ex); + throw ex; + } + + return vm; + } + + public VirtualEthernetSwitchManagementService GetVirtualSwitchManagementService() + { + // VirtualSwitchManagementService is a singleton, most anonymous way of lookup is by asking for the set + // of local instances, which should be size 1. + var virtSwtichSvcCollection = VirtualEthernetSwitchManagementService.GetInstances(); + foreach (VirtualEthernetSwitchManagementService item in virtSwtichSvcCollection) + { + return item; + } + + var errMsg = string.Format("No Hyper-V subsystem on server"); + var ex = new WmiException(errMsg); + logger.Error(errMsg, ex); + throw ex; + } + + /// + /// Always produces a VHDX. + /// + /// + /// + public void CreateDynamicVirtualHardDisk(ulong MaxInternalSize, string Path) + { + // Produce description of the virtual disk in the format of a Msvm_VirtualHardDiskSettings object + + // Example at http://www.getcodesamples.com/src/FC025DDC/76689747, but + // Is there a template we can use to fill in the settings? + var newVirtHDSettings = VirtualHardDiskSettingData.CreateInstance(); + newVirtHDSettings.LateBoundObject["Type"] = 3; // Dynamic + newVirtHDSettings.LateBoundObject["Format"] = 3; // VHDX + newVirtHDSettings.LateBoundObject["Path"] = Path; + newVirtHDSettings.LateBoundObject["MaxInternalSize"] = MaxInternalSize; + newVirtHDSettings.LateBoundObject["BlockSize"] = 0; // Use defaults + newVirtHDSettings.LateBoundObject["LogicalSectorSize"] = 0; // Use defaults + newVirtHDSettings.LateBoundObject["PhysicalSectorSize"] = 0; // Use defaults + + // Optional: newVirtHDSettings.CommitObject(); + + // Add the new vhd object as a virtual hard disk to the vm. + string newVirtHDSettingsString = newVirtHDSettings.LateBoundObject.GetText(System.Management.TextFormat.CimDtd20); + + // Resource settings are changed through the management service + System.Management.ManagementPath jobPath; + var imgMgr = GetImageManagementService(); + var ret_val = imgMgr.CreateVirtualHardDisk(newVirtHDSettingsString, out jobPath); + + // If the Job is done asynchronously + if (ret_val == ReturnCode.Started) + { + StorageJobCompleted(jobPath); + } + else if (ret_val != ReturnCode.Completed) + { + var errMsg = string.Format( + "Failed to CreateVirtualHardDisk size {0}, path {1} due to {2}", + MaxInternalSize, + Path, + ReturnCode.ToString(ret_val)); + var ex = new WmiException(errMsg); + logger.Error(errMsg, ex); + throw ex; + } + } + + public ImageManagementService GetImageManagementService() + { + // VirtualSystemManagementService is a singleton, most anonymous way of lookup is by asking for the set + // of local instances, which should be size 1. + + var coll = ImageManagementService.GetInstances(); + foreach (ImageManagementService item in coll) + { + return item; + } + + var errMsg = string.Format("No Hyper-V subsystem on server"); + var ex = new WmiException(errMsg); + logger.Error(errMsg, ex); + throw ex; + } + + + public VirtualSystemManagementService GetVirtualisationSystemManagementService() + { + // VirtualSystemManagementService is a singleton, most anonymous way of lookup is by asking for the set + // of local instances, which should be size 1. + + var virtSysMgmtSvcCollection = VirtualSystemManagementService.GetInstances(); + foreach (VirtualSystemManagementService item in virtSysMgmtSvcCollection) + { + return item; + } + + var errMsg = string.Format("No Hyper-V subsystem on server"); + var ex = new WmiException(errMsg); + logger.Error(errMsg, ex); + throw ex; + } + + public VirtualSystemMigrationService GetVirtualisationSystemMigrationService() + { + + var virtSysMigSvcCollection = VirtualSystemMigrationService.GetInstances(); + foreach (VirtualSystemMigrationService item in virtSysMigSvcCollection) + { + return item; + } + + var errMsg = string.Format("No Hyper-V migration service subsystem on server"); + var ex = new WmiException(errMsg); + logger.Error(errMsg, ex); + throw ex; + } + + /// + /// Similar to http://msdn.microsoft.com/en-us/library/hh850031%28v=vs.85%29.aspx + /// + /// + /// + private static void JobCompleted(ManagementPath jobPath) + { + ConcreteJob jobObj = null; + for(;;) + { + jobObj = new ConcreteJob(jobPath); + if (jobObj.JobState != JobState.Starting && jobObj.JobState != JobState.Running) + { + break; + } + logger.InfoFormat("In progress... {0}% completed.", jobObj.PercentComplete); + System.Threading.Thread.Sleep(1000); + } + + if (jobObj.JobState != JobState.Completed) + { + var errMsg = string.Format( + "Hyper-V Job failed, Error Code:{0}, Description: {1}", + jobObj.ErrorCode, + jobObj.ErrorDescription); + var ex = new WmiException(errMsg); + logger.Error(errMsg, ex); + throw ex; + } + + logger.DebugFormat("WMI job succeeded: {0}, Elapsed={1}", jobObj.Description, jobObj.ElapsedTime); + } + + private static void MigrationJobCompleted(ManagementPath jobPath) + { + MigrationJob jobObj = null; + for (;;) + { + jobObj = new MigrationJob(jobPath); + if (jobObj.JobState != JobState.Starting && jobObj.JobState != JobState.Running) + { + break; + } + logger.InfoFormat("In progress... {0}% completed.", jobObj.PercentComplete); + System.Threading.Thread.Sleep(1000); + } + + if (jobObj.JobState != JobState.Completed) + { + var errMsg = string.Format( + "Hyper-V Job failed, Error Code:{0}, Description: {1}", + jobObj.ErrorCode, + jobObj.ErrorDescription); + var ex = new WmiException(errMsg); + logger.Error(errMsg, ex); + throw ex; + } + } + + private static void StorageJobCompleted(ManagementPath jobPath) + { + StorageJob jobObj = null; + for (; ; ) + { + jobObj = new StorageJob(jobPath); + if (jobObj.JobState != JobState.Starting && jobObj.JobState != JobState.Running) + { + break; + } + logger.InfoFormat("In progress... {0}% completed.", jobObj.PercentComplete); + System.Threading.Thread.Sleep(1000); + } + + if (jobObj.JobState != JobState.Completed) + { + var errMsg = string.Format( + "Hyper-V Job failed, Error Code:{0}, Description: {1}", + jobObj.ErrorCode, + jobObj.ErrorDescription); + var ex = new WmiException(errMsg); + logger.Error(errMsg, ex); + throw ex; + } + } + + public void GetProcessorResources(out uint sockets, out uint cores, out uint mhz) + { + // Processor processors + cores = 0; + mhz = 0; + sockets = 0; + Processor.ProcessorCollection procCol = Processor.GetInstances(); + foreach (Processor procInfo in procCol) + { + cores += procInfo.NumberOfCores; + mhz = procInfo.MaxClockSpeed; + sockets++; + } + } + + public void GetProcessorUsageInfo(out double cpuUtilization) + { + PerfFormattedData_Counters_ProcessorInformation.PerfFormattedData_Counters_ProcessorInformationCollection coll = + PerfFormattedData_Counters_ProcessorInformation.GetInstances("Name=\"_Total\""); + cpuUtilization = 100; + // Use the first one + foreach (PerfFormattedData_Counters_ProcessorInformation procInfo in coll) + { + // Idle during a given internal + // See http://library.wmifun.net/cimv2/win32_perfformatteddata_counters_processorinformation.html + cpuUtilization = 100.0 - (double)procInfo.PercentIdleTime; + } + } + + + public void GetMemoryResources(out ulong physicalRamKBs, out ulong freeMemoryKBs) + { + OperatingSystem0 os = new OperatingSystem0(); + physicalRamKBs = os.TotalVisibleMemorySize; + freeMemoryKBs = os.FreePhysicalMemory; + } + + public string GetDefaultVirtualDiskFolder() + { + VirtualSystemManagementServiceSettingData.VirtualSystemManagementServiceSettingDataCollection coll = VirtualSystemManagementServiceSettingData.GetInstances(); + string defaultVirtualHardDiskPath = null; + foreach (VirtualSystemManagementServiceSettingData settings in coll) + { + defaultVirtualHardDiskPath = settings.DefaultVirtualHardDiskPath; + } + + // assert + if (!System.IO.Directory.Exists(defaultVirtualHardDiskPath) ){ + var errMsg = string.Format( + "Hyper-V DefaultVirtualHardDiskPath is invalid!"); + logger.Error(errMsg); + return null; + } + + return defaultVirtualHardDiskPath; + } + + public ComputerSystem GetComputerSystem(string displayName) + { + var wmiQuery = String.Format("ElementName=\"{0}\"", displayName); + ComputerSystem.ComputerSystemCollection vmCollection = ComputerSystem.GetInstances(wmiQuery); + + // Return the first one + foreach (ComputerSystem vm in vmCollection) + { + return vm; + } + return null; + } + public ComputerSystem.ComputerSystemCollection GetComputerSystemCollection() { var wmiQuery = String.Format("Caption=\"Virtual Machine\""); @@ -2333,390 +2333,390 @@ namespace HypervResource return null; } - public Dictionary GetVmSync(String privateIpAddress) - { - List vms = GetVmElementNames(); - Dictionary vmSyncStates = new Dictionary(); - String vmState; - foreach (String vm in vms) - { - vmState = EnabledState.ToCloudStackState(GetComputerSystem(vm).EnabledState); - vmSyncStates.Add(vm, new VmState(vmState, privateIpAddress)); - } - return vmSyncStates; - } - - public List GetVmElementNames() - { - List result = new List(); - ComputerSystem.ComputerSystemCollection vmCollection = ComputerSystem.GetInstances(); - - // Return the first one - foreach (ComputerSystem vm in vmCollection) - { - if (vm.Caption.StartsWith("Hosting Computer System") ) - { - continue; - } - result.Add(vm.ElementName); - } - return result; - } - - public ProcessorSettingData GetProcSettings(VirtualSystemSettingData vmSettings) - { - // An ASSOCIATOR object provides the cross reference from the VirtualSystemSettingData and the - // ProcessorSettingData, but generated wrappers do not expose a ASSOCIATOR OF query as a method. - // Instead, we use the System.Management to code the equivalant of - // string query = string.Format( "ASSOCIATORS OF {{{0}}} WHERE ResultClass = {1}", vmSettings.path, resultclassName); - // - var wmiObjQuery = new RelatedObjectQuery(vmSettings.Path.Path, ProcessorSettingData.CreatedClassName); - - // NB: default scope of ManagementObjectSearcher is '\\.\root\cimv2', which does not contain - // the virtualisation objects. - var wmiObjectSearch = new ManagementObjectSearcher(vmSettings.Scope, wmiObjQuery); - var wmiObjCollection = new ProcessorSettingData.ProcessorSettingDataCollection(wmiObjectSearch.Get()); - - foreach (ProcessorSettingData wmiObj in wmiObjCollection) - { - return wmiObj; - } - - var errMsg = string.Format("No ProcessorSettingData in VirtualSystemSettingData {0}", vmSettings.Path.Path); - var ex = new WmiException(errMsg); - logger.Error(errMsg, ex); - throw ex; - } - - public MemorySettingData GetMemSettings(VirtualSystemSettingData vmSettings) - { - // An ASSOCIATOR object provides the cross reference from the VirtualSystemSettingData and the - // MemorySettingData, but generated wrappers do not expose a ASSOCIATOR OF query as a method. - // Instead, we use the System.Management to code the equivalant of - // string query = string.Format( "ASSOCIATORS OF {{{0}}} WHERE ResultClass = {1}", vmSettings.path, resultclassName); - // - var wmiObjQuery = new RelatedObjectQuery(vmSettings.Path.Path, MemorySettingData.CreatedClassName); - - // NB: default scope of ManagementObjectSearcher is '\\.\root\cimv2', which does not contain - // the virtualisation objects. - var wmiObjectSearch = new ManagementObjectSearcher(vmSettings.Scope, wmiObjQuery); - var wmiObjCollection = new MemorySettingData.MemorySettingDataCollection(wmiObjectSearch.Get()); - - foreach (MemorySettingData wmiObj in wmiObjCollection) - { - return wmiObj; - } - - var errMsg = string.Format("No MemorySettingData in VirtualSystemSettingData {0}", vmSettings.Path.Path); - var ex = new WmiException(errMsg); - logger.Error(errMsg, ex); - throw ex; - } - - - public ResourceAllocationSettingData GetDvdDriveSettings(VirtualSystemSettingData vmSettings) - { - var wmiObjCollection = GetResourceAllocationSettings(vmSettings); - - foreach (ResourceAllocationSettingData wmiObj in wmiObjCollection) - { - // DVD drive is '16', see http://msdn.microsoft.com/en-us/library/hh850200(v=vs.85).aspx - if (wmiObj.ResourceType == 16) - { - return wmiObj; - } - } - - var errMsg = string.Format( - "Cannot find the Dvd drive in VirtualSystemSettingData {0}", - vmSettings.Path.Path); - var ex = new WmiException(errMsg); - logger.Error(errMsg, ex); - throw ex; - } - - public ResourceAllocationSettingData GetIDEControllerSettings(VirtualSystemSettingData vmSettings, string cntrllerAddr) - { - var wmiObjCollection = GetResourceAllocationSettings(vmSettings); - - foreach (ResourceAllocationSettingData wmiObj in wmiObjCollection) - { - if (wmiObj.ResourceSubType == IDE_CONTROLLER && wmiObj.Address == cntrllerAddr) - { - return wmiObj; - } - } - - var errMsg = string.Format( - "Cannot find the Microsoft Emulated IDE Controlle at address {0} in VirtualSystemSettingData {1}", - cntrllerAddr, - vmSettings.Path.Path); - var ex = new WmiException(errMsg); - logger.Error(errMsg, ex); - throw ex; - } - - public ResourceAllocationSettingData GetScsiControllerSettings(VirtualSystemSettingData vmSettings) - { - var wmiObjCollection = GetResourceAllocationSettings(vmSettings); - - foreach (ResourceAllocationSettingData wmiObj in wmiObjCollection) - { - if (wmiObj.ResourceSubType == SCSI_CONTROLLER) - { - return wmiObj; - } - } - - var errMsg = string.Format( - "Cannot find the Microsoft Synthetic SCSI Controller in VirtualSystemSettingData {1}", - vmSettings.Path.Path); - var ex = new WmiException(errMsg); - logger.Error(errMsg, ex); - throw ex; - } - - /// - /// VM resources, typically hardware a described by a generic MSVM_ResourceAllocationSettingData object. The hardware type being - /// described is identified in two ways: in general terms using an enum in the ResourceType field, and in terms of the implementation - /// using text in the ResourceSubType field. - /// See http://msdn.microsoft.com/en-us/library/cc136877%28v=vs.85%29.aspx - /// - /// - /// - public ResourceAllocationSettingData.ResourceAllocationSettingDataCollection GetResourceAllocationSettings(VirtualSystemSettingData vmSettings) - { - // An ASSOCIATOR object provides the cross reference from the VirtualSystemSettingData and the - // ResourceAllocationSettingData, but generated wrappers do not expose a ASSOCIATOR OF query as a method. - // Instead, we use the System.Management to code the equivalant of - // string query = string.Format( "ASSOCIATORS OF {{{0}}} WHERE ResultClass = {1}", vmSettings.path, resultclassName); - // - var wmiObjQuery = new RelatedObjectQuery(vmSettings.Path.Path, ResourceAllocationSettingData.CreatedClassName); - - // NB: default scope of ManagementObjectSearcher is '\\.\root\cimv2', which does not contain - // the virtualisation objects. - var wmiObjectSearch = new ManagementObjectSearcher(vmSettings.Scope, wmiObjQuery); - var wmiObjCollection = new ResourceAllocationSettingData.ResourceAllocationSettingDataCollection(wmiObjectSearch.Get()); - - if (wmiObjCollection != null) - { - return wmiObjCollection; - } - - var errMsg = string.Format("No ResourceAllocationSettingData in VirtualSystemSettingData {0}", vmSettings.Path.Path); - var ex = new WmiException(errMsg); - logger.Error(errMsg, ex); - throw ex; - } - - public EthernetPortAllocationSettingData[] GetEthernetConnections(ComputerSystem vm) - { - // ComputerSystem -> VirtualSystemSettingData -> EthernetPortAllocationSettingData - VirtualSystemSettingData vmSettings = GetVmSettings(vm); - - // An ASSOCIATOR object provides the cross reference from the VirtualSystemSettingData and the - // EthernetPortAllocationSettingData, but generated wrappers do not expose a ASSOCIATOR OF query as a method. - // Instead, we use the System.Management to code the equivalant of - // string query = string.Format( "ASSOCIATORS OF {{{0}}} WHERE ResultClass = {1}", vmSettings.path, resultclassName); - // - var wmiObjQuery = new RelatedObjectQuery(vmSettings.Path.Path, EthernetPortAllocationSettingData.CreatedClassName); - - // NB: default scope of ManagementObjectSearcher is '\\.\root\cimv2', which does not contain - // the virtualisation objects. - var wmiObjectSearch = new ManagementObjectSearcher(vmSettings.Scope, wmiObjQuery); - var wmiObjCollection = new EthernetPortAllocationSettingData.EthernetPortAllocationSettingDataCollection(wmiObjectSearch.Get()); - - var result = new List(wmiObjCollection.Count); - foreach (EthernetPortAllocationSettingData item in wmiObjCollection) - { - result.Add(item); - } - return result.ToArray(); - } - - public StorageAllocationSettingData[] GetStorageSettings(ComputerSystem vm) - { - // ComputerSystem -> VirtualSystemSettingData -> EthernetPortAllocationSettingData - VirtualSystemSettingData vmSettings = GetVmSettings(vm); - - var wmiObjQuery = new RelatedObjectQuery(vmSettings.Path.Path, StorageAllocationSettingData.CreatedClassName); - - // NB: default scope of ManagementObjectSearcher is '\\.\root\cimv2', which does not contain - // the virtualisation objects. - var wmiObjectSearch = new ManagementObjectSearcher(vmSettings.Scope, wmiObjQuery); - var wmiObjCollection = new StorageAllocationSettingData.StorageAllocationSettingDataCollection(wmiObjectSearch.Get()); - - var result = new List(wmiObjCollection.Count); - foreach (StorageAllocationSettingData item in wmiObjCollection) - { - result.Add(item); - } - return result.ToArray(); - } - - - public EthernetSwitchPortVlanSettingData GetVlanSettings(EthernetPortAllocationSettingData ethernetConnection) - { - // An ASSOCIATOR object provides the cross reference from the VirtualSystemSettingData and the - // EthernetPortAllocationSettingData, but generated wrappers do not expose a ASSOCIATOR OF query as a method. - // Instead, we use the System.Management to code the equivalant of - // string query = string.Format( "ASSOCIATORS OF {{{0}}} WHERE ResultClass = {1}", vmSettings.path, resultclassName); - // - var wmiObjQuery = new RelatedObjectQuery(ethernetConnection.Path.Path, EthernetSwitchPortVlanSettingData.CreatedClassName); - - // NB: default scope of ManagementObjectSearcher is '\\.\root\cimv2', which does not contain - // the virtualisation objects. - var wmiObjectSearch = new ManagementObjectSearcher(ethernetConnection.Scope, wmiObjQuery); - var wmiObjCollection = new EthernetSwitchPortVlanSettingData.EthernetSwitchPortVlanSettingDataCollection(wmiObjectSearch.Get()); - - if (wmiObjCollection.Count == 0) - { - return null; - } - - // Assert - if (wmiObjCollection.Count > 1) - { - var errMsg = string.Format("Internal error, morn one VLAN settings for a single ethernetConnection"); - var ex = new WmiException(errMsg); - logger.Error(errMsg, ex); - throw ex; - } - - return wmiObjCollection.OfType().First(); - } - - - public SyntheticEthernetPortSettingData[] GetEthernetPortSettings(ComputerSystem vm) - { - // An ASSOCIATOR object provides the cross reference from the ComputerSettings and the - // SyntheticEthernetPortSettingData, via the VirtualSystemSettingData. - // However, generated wrappers do not expose a ASSOCIATOR OF query as a method. - // Instead, we use the System.Management to code the equivalant of - // - // string query = string.Format( "ASSOCIATORS OF {{{0}}} WHERE ResultClass = {1}", vm.path, resultclassName); - // - VirtualSystemSettingData vmSettings = GetVmSettings(vm); - - var wmiObjQuery = new RelatedObjectQuery(vmSettings.Path.Path, SyntheticEthernetPortSettingData.CreatedClassName); - - // NB: default scope of ManagementObjectSearcher is '\\.\root\cimv2', which does not contain - // the virtualisation objects. - var wmiObjectSearch = new ManagementObjectSearcher(vm.Scope, wmiObjQuery); - var wmiObjCollection = new SyntheticEthernetPortSettingData.SyntheticEthernetPortSettingDataCollection(wmiObjectSearch.Get()); - - List results = new List(wmiObjCollection.Count); - foreach (SyntheticEthernetPortSettingData item in wmiObjCollection) - { - results.Add(item); - } - - return results.ToArray(); - } - - public string GetDefaultDataRoot() - { - string defaultRootPath = null; - VirtualSystemManagementServiceSettingData vs_mgmt_data = VirtualSystemManagementServiceSettingData.CreateInstance(); - defaultRootPath = vs_mgmt_data.DefaultVirtualHardDiskPath; - if (defaultRootPath == null) { - defaultRootPath = Path.GetPathRoot(Environment.SystemDirectory) + - "\\Users\\Public\\Documents\\Hyper-V\\Virtual hard disks"; - } - - return defaultRootPath; - } - - public VirtualSystemSettingData GetVmSettings(ComputerSystem vm) - { - // An ASSOCIATOR object provides the cross reference from the ComputerSettings and the - // VirtualSystemSettingData, but generated wrappers do not expose a ASSOCIATOR OF query as a method. - // Instead, we use the System.Management to code the equivalant of - // string query = string.Format( "ASSOCIATORS OF {{{0}}} WHERE ResultClass = {1}", vm.path, resultclassName); - // - var wmiObjQuery = new RelatedObjectQuery(vm.Path.Path, VirtualSystemSettingData.CreatedClassName); - - // NB: default scope of ManagementObjectSearcher is '\\.\root\cimv2', which does not contain - // the virtualisation objects. - var wmiObjectSearch = new ManagementObjectSearcher(vm.Scope, wmiObjQuery); - var wmiObjCollection = new VirtualSystemSettingData.VirtualSystemSettingDataCollection(wmiObjectSearch.Get()); - - // When snapshots are taken into account, there can be multiple settings objects - // take the first one that isn't a snapshot - foreach (VirtualSystemSettingData wmiObj in wmiObjCollection) - { - if (wmiObj.VirtualSystemType == "Microsoft:Hyper-V:System:Realized" || - wmiObj.VirtualSystemType == "Microsoft:Hyper-V:System:Planned") - { - return wmiObj; - } - } - - var errMsg = string.Format("No VirtualSystemSettingData for VM {0}, path {1}", vm.ElementName, vm.Path.Path); - var ex = new WmiException(errMsg); - logger.Error(errMsg, ex); - throw ex; - } - - public KvpExchangeComponentSettingData GetKvpSettings(VirtualSystemSettingData vmSettings) - { - // An ASSOCIATOR object provides the cross reference from the VirtualSystemSettingData and the - // KvpExchangeComponentSettingData, but generated wrappers do not expose a ASSOCIATOR OF query as a method. - // Instead, we use the System.Management to code the equivalant of - // string query = string.Format( "ASSOCIATORS OF {{{0}}} WHERE ResultClass = {1}", vmSettings.path, resultclassName); - // - var wmiObjQuery = new RelatedObjectQuery(vmSettings.Path.Path, KvpExchangeComponentSettingData.CreatedClassName); - - // NB: default scope of ManagementObjectSearcher is '\\.\root\cimv2', which does not contain - // the virtualisation objects. - var wmiObjectSearch = new ManagementObjectSearcher(vmSettings.Scope, wmiObjQuery); - var wmiObjCollection = new KvpExchangeComponentSettingData.KvpExchangeComponentSettingDataCollection(wmiObjectSearch.Get()); - - foreach (KvpExchangeComponentSettingData wmiObj in wmiObjCollection) - { - return wmiObj; - } - - var errMsg = string.Format("No KvpExchangeComponentSettingData in VirtualSystemSettingData {0}", vmSettings.Path.Path); - var ex = new WmiException(errMsg); - logger.Error(errMsg, ex); - throw ex; - } - - public void GetSummaryInfo(Dictionary vmProcessorInfo, List vmsToInspect) - { - // Process info available from WMI, - // See http://msdn.microsoft.com/en-us/library/hh850062(v=vs.85).aspx - uint[] requestedInfo = new uint[] { // TODO: correct? - 0, // Name - 1, // ElementName - 4, // Number of processes - 101 // ProcessorLoad - }; - - System.Management.ManagementBaseObject[] sysSummary; - var vmsvc = GetVirtualisationSystemManagementService(); - System.Management.ManagementPath[] vmPaths = vmsToInspect.ToArray(); - vmsvc.GetSummaryInformation(requestedInfo, vmPaths, out sysSummary); - - foreach (var summary in sysSummary) - { - - var summaryInfo = new SummaryInformation(summary); - - logger.Debug("VM " + summaryInfo.Name + "(elementName " + summaryInfo.ElementName + ") has " + - summaryInfo.NumberOfProcessors + " CPUs, and load of " + summaryInfo.ProcessorLoad); - var vmInfo = new VmStatsEntry - { - cpuUtilization = summaryInfo.ProcessorLoad, - numCPUs = summaryInfo.NumberOfProcessors, - networkReadKBs = 1, - networkWriteKBs = 1, - entityType = "vm" - }; - vmProcessorInfo.Add(summaryInfo.ElementName, vmInfo); - } - } + public Dictionary GetVmSync(String privateIpAddress) + { + List vms = GetVmElementNames(); + Dictionary vmSyncStates = new Dictionary(); + String vmState; + foreach (String vm in vms) + { + vmState = EnabledState.ToCloudStackState(GetComputerSystem(vm).EnabledState); + vmSyncStates.Add(vm, new VmState(vmState, privateIpAddress)); + } + return vmSyncStates; + } + + public List GetVmElementNames() + { + List result = new List(); + ComputerSystem.ComputerSystemCollection vmCollection = ComputerSystem.GetInstances(); + + // Return the first one + foreach (ComputerSystem vm in vmCollection) + { + if (vm.Caption.StartsWith("Hosting Computer System") ) + { + continue; + } + result.Add(vm.ElementName); + } + return result; + } + + public ProcessorSettingData GetProcSettings(VirtualSystemSettingData vmSettings) + { + // An ASSOCIATOR object provides the cross reference from the VirtualSystemSettingData and the + // ProcessorSettingData, but generated wrappers do not expose a ASSOCIATOR OF query as a method. + // Instead, we use the System.Management to code the equivalant of + // string query = string.Format( "ASSOCIATORS OF {{{0}}} WHERE ResultClass = {1}", vmSettings.path, resultclassName); + // + var wmiObjQuery = new RelatedObjectQuery(vmSettings.Path.Path, ProcessorSettingData.CreatedClassName); + + // NB: default scope of ManagementObjectSearcher is '\\.\root\cimv2', which does not contain + // the virtualisation objects. + var wmiObjectSearch = new ManagementObjectSearcher(vmSettings.Scope, wmiObjQuery); + var wmiObjCollection = new ProcessorSettingData.ProcessorSettingDataCollection(wmiObjectSearch.Get()); + + foreach (ProcessorSettingData wmiObj in wmiObjCollection) + { + return wmiObj; + } + + var errMsg = string.Format("No ProcessorSettingData in VirtualSystemSettingData {0}", vmSettings.Path.Path); + var ex = new WmiException(errMsg); + logger.Error(errMsg, ex); + throw ex; + } + + public MemorySettingData GetMemSettings(VirtualSystemSettingData vmSettings) + { + // An ASSOCIATOR object provides the cross reference from the VirtualSystemSettingData and the + // MemorySettingData, but generated wrappers do not expose a ASSOCIATOR OF query as a method. + // Instead, we use the System.Management to code the equivalant of + // string query = string.Format( "ASSOCIATORS OF {{{0}}} WHERE ResultClass = {1}", vmSettings.path, resultclassName); + // + var wmiObjQuery = new RelatedObjectQuery(vmSettings.Path.Path, MemorySettingData.CreatedClassName); + + // NB: default scope of ManagementObjectSearcher is '\\.\root\cimv2', which does not contain + // the virtualisation objects. + var wmiObjectSearch = new ManagementObjectSearcher(vmSettings.Scope, wmiObjQuery); + var wmiObjCollection = new MemorySettingData.MemorySettingDataCollection(wmiObjectSearch.Get()); + + foreach (MemorySettingData wmiObj in wmiObjCollection) + { + return wmiObj; + } + + var errMsg = string.Format("No MemorySettingData in VirtualSystemSettingData {0}", vmSettings.Path.Path); + var ex = new WmiException(errMsg); + logger.Error(errMsg, ex); + throw ex; + } + + + public ResourceAllocationSettingData GetDvdDriveSettings(VirtualSystemSettingData vmSettings) + { + var wmiObjCollection = GetResourceAllocationSettings(vmSettings); + + foreach (ResourceAllocationSettingData wmiObj in wmiObjCollection) + { + // DVD drive is '16', see http://msdn.microsoft.com/en-us/library/hh850200(v=vs.85).aspx + if (wmiObj.ResourceType == 16) + { + return wmiObj; + } + } + + var errMsg = string.Format( + "Cannot find the Dvd drive in VirtualSystemSettingData {0}", + vmSettings.Path.Path); + var ex = new WmiException(errMsg); + logger.Error(errMsg, ex); + throw ex; + } + + public ResourceAllocationSettingData GetIDEControllerSettings(VirtualSystemSettingData vmSettings, string cntrllerAddr) + { + var wmiObjCollection = GetResourceAllocationSettings(vmSettings); + + foreach (ResourceAllocationSettingData wmiObj in wmiObjCollection) + { + if (wmiObj.ResourceSubType == IDE_CONTROLLER && wmiObj.Address == cntrllerAddr) + { + return wmiObj; + } + } + + var errMsg = string.Format( + "Cannot find the Microsoft Emulated IDE Controlle at address {0} in VirtualSystemSettingData {1}", + cntrllerAddr, + vmSettings.Path.Path); + var ex = new WmiException(errMsg); + logger.Error(errMsg, ex); + throw ex; + } + + public ResourceAllocationSettingData GetScsiControllerSettings(VirtualSystemSettingData vmSettings) + { + var wmiObjCollection = GetResourceAllocationSettings(vmSettings); + + foreach (ResourceAllocationSettingData wmiObj in wmiObjCollection) + { + if (wmiObj.ResourceSubType == SCSI_CONTROLLER) + { + return wmiObj; + } + } + + var errMsg = string.Format( + "Cannot find the Microsoft Synthetic SCSI Controller in VirtualSystemSettingData {1}", + vmSettings.Path.Path); + var ex = new WmiException(errMsg); + logger.Error(errMsg, ex); + throw ex; + } + + /// + /// VM resources, typically hardware a described by a generic MSVM_ResourceAllocationSettingData object. The hardware type being + /// described is identified in two ways: in general terms using an enum in the ResourceType field, and in terms of the implementation + /// using text in the ResourceSubType field. + /// See http://msdn.microsoft.com/en-us/library/cc136877%28v=vs.85%29.aspx + /// + /// + /// + public ResourceAllocationSettingData.ResourceAllocationSettingDataCollection GetResourceAllocationSettings(VirtualSystemSettingData vmSettings) + { + // An ASSOCIATOR object provides the cross reference from the VirtualSystemSettingData and the + // ResourceAllocationSettingData, but generated wrappers do not expose a ASSOCIATOR OF query as a method. + // Instead, we use the System.Management to code the equivalant of + // string query = string.Format( "ASSOCIATORS OF {{{0}}} WHERE ResultClass = {1}", vmSettings.path, resultclassName); + // + var wmiObjQuery = new RelatedObjectQuery(vmSettings.Path.Path, ResourceAllocationSettingData.CreatedClassName); + + // NB: default scope of ManagementObjectSearcher is '\\.\root\cimv2', which does not contain + // the virtualisation objects. + var wmiObjectSearch = new ManagementObjectSearcher(vmSettings.Scope, wmiObjQuery); + var wmiObjCollection = new ResourceAllocationSettingData.ResourceAllocationSettingDataCollection(wmiObjectSearch.Get()); + + if (wmiObjCollection != null) + { + return wmiObjCollection; + } + + var errMsg = string.Format("No ResourceAllocationSettingData in VirtualSystemSettingData {0}", vmSettings.Path.Path); + var ex = new WmiException(errMsg); + logger.Error(errMsg, ex); + throw ex; + } + + public EthernetPortAllocationSettingData[] GetEthernetConnections(ComputerSystem vm) + { + // ComputerSystem -> VirtualSystemSettingData -> EthernetPortAllocationSettingData + VirtualSystemSettingData vmSettings = GetVmSettings(vm); + + // An ASSOCIATOR object provides the cross reference from the VirtualSystemSettingData and the + // EthernetPortAllocationSettingData, but generated wrappers do not expose a ASSOCIATOR OF query as a method. + // Instead, we use the System.Management to code the equivalant of + // string query = string.Format( "ASSOCIATORS OF {{{0}}} WHERE ResultClass = {1}", vmSettings.path, resultclassName); + // + var wmiObjQuery = new RelatedObjectQuery(vmSettings.Path.Path, EthernetPortAllocationSettingData.CreatedClassName); + + // NB: default scope of ManagementObjectSearcher is '\\.\root\cimv2', which does not contain + // the virtualisation objects. + var wmiObjectSearch = new ManagementObjectSearcher(vmSettings.Scope, wmiObjQuery); + var wmiObjCollection = new EthernetPortAllocationSettingData.EthernetPortAllocationSettingDataCollection(wmiObjectSearch.Get()); + + var result = new List(wmiObjCollection.Count); + foreach (EthernetPortAllocationSettingData item in wmiObjCollection) + { + result.Add(item); + } + return result.ToArray(); + } + + public StorageAllocationSettingData[] GetStorageSettings(ComputerSystem vm) + { + // ComputerSystem -> VirtualSystemSettingData -> EthernetPortAllocationSettingData + VirtualSystemSettingData vmSettings = GetVmSettings(vm); + + var wmiObjQuery = new RelatedObjectQuery(vmSettings.Path.Path, StorageAllocationSettingData.CreatedClassName); + + // NB: default scope of ManagementObjectSearcher is '\\.\root\cimv2', which does not contain + // the virtualisation objects. + var wmiObjectSearch = new ManagementObjectSearcher(vmSettings.Scope, wmiObjQuery); + var wmiObjCollection = new StorageAllocationSettingData.StorageAllocationSettingDataCollection(wmiObjectSearch.Get()); + + var result = new List(wmiObjCollection.Count); + foreach (StorageAllocationSettingData item in wmiObjCollection) + { + result.Add(item); + } + return result.ToArray(); + } + + + public EthernetSwitchPortVlanSettingData GetVlanSettings(EthernetPortAllocationSettingData ethernetConnection) + { + // An ASSOCIATOR object provides the cross reference from the VirtualSystemSettingData and the + // EthernetPortAllocationSettingData, but generated wrappers do not expose a ASSOCIATOR OF query as a method. + // Instead, we use the System.Management to code the equivalant of + // string query = string.Format( "ASSOCIATORS OF {{{0}}} WHERE ResultClass = {1}", vmSettings.path, resultclassName); + // + var wmiObjQuery = new RelatedObjectQuery(ethernetConnection.Path.Path, EthernetSwitchPortVlanSettingData.CreatedClassName); + + // NB: default scope of ManagementObjectSearcher is '\\.\root\cimv2', which does not contain + // the virtualisation objects. + var wmiObjectSearch = new ManagementObjectSearcher(ethernetConnection.Scope, wmiObjQuery); + var wmiObjCollection = new EthernetSwitchPortVlanSettingData.EthernetSwitchPortVlanSettingDataCollection(wmiObjectSearch.Get()); + + if (wmiObjCollection.Count == 0) + { + return null; + } + + // Assert + if (wmiObjCollection.Count > 1) + { + var errMsg = string.Format("Internal error, morn one VLAN settings for a single ethernetConnection"); + var ex = new WmiException(errMsg); + logger.Error(errMsg, ex); + throw ex; + } + + return wmiObjCollection.OfType().First(); + } + + + public SyntheticEthernetPortSettingData[] GetEthernetPortSettings(ComputerSystem vm) + { + // An ASSOCIATOR object provides the cross reference from the ComputerSettings and the + // SyntheticEthernetPortSettingData, via the VirtualSystemSettingData. + // However, generated wrappers do not expose a ASSOCIATOR OF query as a method. + // Instead, we use the System.Management to code the equivalant of + // + // string query = string.Format( "ASSOCIATORS OF {{{0}}} WHERE ResultClass = {1}", vm.path, resultclassName); + // + VirtualSystemSettingData vmSettings = GetVmSettings(vm); + + var wmiObjQuery = new RelatedObjectQuery(vmSettings.Path.Path, SyntheticEthernetPortSettingData.CreatedClassName); + + // NB: default scope of ManagementObjectSearcher is '\\.\root\cimv2', which does not contain + // the virtualisation objects. + var wmiObjectSearch = new ManagementObjectSearcher(vm.Scope, wmiObjQuery); + var wmiObjCollection = new SyntheticEthernetPortSettingData.SyntheticEthernetPortSettingDataCollection(wmiObjectSearch.Get()); + + List results = new List(wmiObjCollection.Count); + foreach (SyntheticEthernetPortSettingData item in wmiObjCollection) + { + results.Add(item); + } + + return results.ToArray(); + } + + public string GetDefaultDataRoot() + { + string defaultRootPath = null; + VirtualSystemManagementServiceSettingData vs_mgmt_data = VirtualSystemManagementServiceSettingData.CreateInstance(); + defaultRootPath = vs_mgmt_data.DefaultVirtualHardDiskPath; + if (defaultRootPath == null) { + defaultRootPath = Path.GetPathRoot(Environment.SystemDirectory) + + "\\Users\\Public\\Documents\\Hyper-V\\Virtual hard disks"; + } + + return defaultRootPath; + } + + public VirtualSystemSettingData GetVmSettings(ComputerSystem vm) + { + // An ASSOCIATOR object provides the cross reference from the ComputerSettings and the + // VirtualSystemSettingData, but generated wrappers do not expose a ASSOCIATOR OF query as a method. + // Instead, we use the System.Management to code the equivalant of + // string query = string.Format( "ASSOCIATORS OF {{{0}}} WHERE ResultClass = {1}", vm.path, resultclassName); + // + var wmiObjQuery = new RelatedObjectQuery(vm.Path.Path, VirtualSystemSettingData.CreatedClassName); + + // NB: default scope of ManagementObjectSearcher is '\\.\root\cimv2', which does not contain + // the virtualisation objects. + var wmiObjectSearch = new ManagementObjectSearcher(vm.Scope, wmiObjQuery); + var wmiObjCollection = new VirtualSystemSettingData.VirtualSystemSettingDataCollection(wmiObjectSearch.Get()); + + // When snapshots are taken into account, there can be multiple settings objects + // take the first one that isn't a snapshot + foreach (VirtualSystemSettingData wmiObj in wmiObjCollection) + { + if (wmiObj.VirtualSystemType == "Microsoft:Hyper-V:System:Realized" || + wmiObj.VirtualSystemType == "Microsoft:Hyper-V:System:Planned") + { + return wmiObj; + } + } + + var errMsg = string.Format("No VirtualSystemSettingData for VM {0}, path {1}", vm.ElementName, vm.Path.Path); + var ex = new WmiException(errMsg); + logger.Error(errMsg, ex); + throw ex; + } + + public KvpExchangeComponentSettingData GetKvpSettings(VirtualSystemSettingData vmSettings) + { + // An ASSOCIATOR object provides the cross reference from the VirtualSystemSettingData and the + // KvpExchangeComponentSettingData, but generated wrappers do not expose a ASSOCIATOR OF query as a method. + // Instead, we use the System.Management to code the equivalant of + // string query = string.Format( "ASSOCIATORS OF {{{0}}} WHERE ResultClass = {1}", vmSettings.path, resultclassName); + // + var wmiObjQuery = new RelatedObjectQuery(vmSettings.Path.Path, KvpExchangeComponentSettingData.CreatedClassName); + + // NB: default scope of ManagementObjectSearcher is '\\.\root\cimv2', which does not contain + // the virtualisation objects. + var wmiObjectSearch = new ManagementObjectSearcher(vmSettings.Scope, wmiObjQuery); + var wmiObjCollection = new KvpExchangeComponentSettingData.KvpExchangeComponentSettingDataCollection(wmiObjectSearch.Get()); + + foreach (KvpExchangeComponentSettingData wmiObj in wmiObjCollection) + { + return wmiObj; + } + + var errMsg = string.Format("No KvpExchangeComponentSettingData in VirtualSystemSettingData {0}", vmSettings.Path.Path); + var ex = new WmiException(errMsg); + logger.Error(errMsg, ex); + throw ex; + } + + public void GetSummaryInfo(Dictionary vmProcessorInfo, List vmsToInspect) + { + // Process info available from WMI, + // See http://msdn.microsoft.com/en-us/library/hh850062(v=vs.85).aspx + uint[] requestedInfo = new uint[] { // TODO: correct? + 0, // Name + 1, // ElementName + 4, // Number of processes + 101 // ProcessorLoad + }; + + System.Management.ManagementBaseObject[] sysSummary; + var vmsvc = GetVirtualisationSystemManagementService(); + System.Management.ManagementPath[] vmPaths = vmsToInspect.ToArray(); + vmsvc.GetSummaryInformation(requestedInfo, vmPaths, out sysSummary); + + foreach (var summary in sysSummary) + { + + var summaryInfo = new SummaryInformation(summary); + + logger.Debug("VM " + summaryInfo.Name + "(elementName " + summaryInfo.ElementName + ") has " + + summaryInfo.NumberOfProcessors + " CPUs, and load of " + summaryInfo.ProcessorLoad); + var vmInfo = new VmStatsEntry + { + cpuUtilization = summaryInfo.ProcessorLoad, + numCPUs = summaryInfo.NumberOfProcessors, + networkReadKBs = 1, + networkWriteKBs = 1, + entityType = "vm" + }; + vmProcessorInfo.Add(summaryInfo.ElementName, vmInfo); + } + } public string GetVmNote(System.Management.ManagementPath sysPath) { @@ -2733,242 +2733,242 @@ namespace HypervResource return null; } - } - - public class WmiException : Exception - { - public WmiException() - { - } - - public WmiException(string message) - : base(message) - { - } - - public WmiException(string message, Exception inner) - : base(message, inner) - { - } - } - - /// - /// Covers V2 API, see - /// http://msdn.microsoft.com/en-us/library/hh850031%28v=vs.85%29.aspx - /// - public static class ReturnCode - { - public const UInt32 Completed = 0; - public const UInt32 Started = 4096; - public const UInt32 Failed = 32768; - public const UInt32 AccessDenied = 32769; - public const UInt32 NotSupported = 32770; - public const UInt32 Unknown = 32771; - public const UInt32 Timeout = 32772; - public const UInt32 InvalidParameter = 32773; - public const UInt32 SystemInUse = 32774; - public const UInt32 InvalidState = 32775; - public const UInt32 IncorrectDataType = 32776; - public const UInt32 SystemNotAvailable = 32777; - public const UInt32 OutofMemory = 32778; - public static string ToString(UInt32 value) - { - string result = "Unknown return code"; - switch (value) - { - case Completed: result = "Completed"; break; - case Started: result = "Started"; break; - case Failed: result = "Failed"; break; - case AccessDenied: result = "AccessDenied"; break; - case NotSupported: result = "NotSupported"; break; - case Unknown: result = "Unknown"; break; - case Timeout: result = "Timeout"; break; - case InvalidParameter: result = "InvalidParameter"; break; - case SystemInUse: result = "SystemInUse"; break; - case InvalidState: result = "InvalidState"; break; - case IncorrectDataType: result = "IncorrectDataType"; break; - case SystemNotAvailable: result = "SystemNotAvailable"; break; - case OutofMemory: result = "OutofMemory"; break; - } - return result; - } - } - - /// - /// Covers V2 API, see - /// http://msdn.microsoft.com/en-us/library/hh850031%28v=vs.85%29.aspx - /// - public static class JobState - { - public const UInt16 New = 2; - public const UInt16 Starting = 3; - public const UInt16 Running = 4; - public const UInt16 Suspended = 5; - public const UInt16 ShuttingDown = 6; - public const UInt16 Completed = 7; - public const UInt16 Terminated = 8; - public const UInt16 Killed = 9; - public const UInt16 Exception = 10; - public const UInt16 Service = 11; - public static string ToString(UInt16 value) - { - string result = "Unknown JobState code"; - switch (value) - { - case New: result = "New"; break; - case Starting: result = "Starting"; break; - case Running: result = "Running"; break; - case Suspended: result = "Suspended"; break; - case ShuttingDown: result = "ShuttingDown"; break; - case Completed: result = "Completed"; break; - case Terminated: result = "Terminated"; break; - case Killed: result = "Killed"; break; - case Exception: result = "Exception"; break; - case Service: result = "Service"; break; - } - return result; - } - } - - /// - /// V2 API (see http://msdn.microsoft.com/en-us/library/hh850279(v=vs.85).aspx) - /// has removed 'Paused' and 'Suspended' as compared to the - /// V1 API (see http://msdn.microsoft.com/en-us/library/cc723874%28v=vs.85%29.aspx) - /// However, Paused and Suspended appear on the VM state transition table - /// (see http://msdn.microsoft.com/en-us/library/hh850116(v=vs.85).aspx#methods) - /// - public class RequiredState - { - public const UInt16 Enabled = 2; // Turns the VM on. - public const UInt16 Disabled = 3; // Turns the VM off. - public const UInt16 ShutDown = 4; - public const UInt16 Offline = 6; - //public const UInt16 Test = 7; - public const UInt16 Defer = 8; - // public const UInt16 Quiesce = 9; - // public const UInt16 Reboot = 10; // A hard reset of the VM. - public const UInt16 Reset = 11; // For future use. - public const UInt16 Paused = 9; // Pauses the VM. - public const UInt16 Suspended = 32779; // Saves the state of the VM. - - public static string ToString(UInt16 value) - { - string result = "Unknown RequiredState code"; - switch (value) - { - case Enabled: result = "Enabled"; break; - case Disabled: result = "Disabled"; break; - case ShutDown: result = "ShutDown"; break; - case Offline: result = "Offline"; break; - case Defer: result = "Defer"; break; - case Reset: result = "Reset"; break; - } - return result; - } - } - - /// - /// V2 API specifies the states below in its state transition graph at - /// http://msdn.microsoft.com/en-us/library/hh850116(v=vs.85).aspx#methods - /// However, the CIM standard has additional possibilities based on the description - /// of EnabledState. - /// The previous V1 API is described by - /// http://msdn.microsoft.com/en-us/library/cc136822%28v=vs.85%29.aspx - /// - public class EnabledState - { - /// - /// The state of the VM could not be determined. - /// - public const UInt16 Unknown = 0; - /// - /// The VM is running. - /// - public const UInt16 Enabled = 2; - /// - /// The VM is turned off. - /// - public const UInt16 Disabled = 3; - /// - /// The VM is paused. - /// - public const UInt16 Paused = 32768; - /// - /// The VM is in a saved state. - /// - public const UInt16 Suspended = 32769; - /// - /// The VM is starting. This is a transitional state between 3 (Disabled) - /// or 32769 (Suspended) and 2 (Enabled) initiated by a call to the - /// RequestStateChange method with a RequestedState parameter of 2 (Enabled). - /// - public const UInt16 Starting = 32770; - /// - /// Starting with Windows Server 2008 R2 this value is not supported. - /// If the VM is performing a snapshot operation, the element at index 1 - /// of the OperationalStatus property array will contain 32768 (Creating Snapshot), - /// 32769 (Applying Snapshot), or 32770 (Deleting Snapshot). - /// - public const UInt16 Snapshotting = 32771; - /// - /// The VM is saving its state. This is a transitional state between 2 (Enabled) - /// and 32769 (Suspended) initiated by a call to the RequestStateChange method - /// with a RequestedState parameter of 32769 (Suspended). - /// - public const UInt16 Saving = 32773; - /// - /// The VM is turning off. This is a transitional state between 2 (Enabled) - /// and 3 (Disabled) initiated by a call to the RequestStateChange method - /// with a RequestedState parameter of 3 (Disabled) or a guest operating system - /// initiated power off. - /// - public const UInt16 Stopping = 32774; - /// - /// The VM is pausing. This is a transitional state between 2 (Enabled) and 32768 (Paused) initiated by a call to the RequestStateChange method with a RequestedState parameter of 32768 (Paused). - /// - public const UInt16 Pausing = 32776; - /// - /// The VM is resuming from a paused state. This is a transitional state between 32768 (Paused) and 2 (Enabled). - /// - public const UInt16 Resuming = 32777; - - public static string ToString(UInt16 value) - { - string result = "Unknown"; - switch (value) - { - case Enabled: result = "Enabled"; break; - case Disabled: result = "Disabled"; break; - case Paused: result = "Paused"; break; - case Suspended: result = "Suspended"; break; - case Starting: result = "Starting"; break; - case Snapshotting: result = "Snapshotting"; break; // NOT used - case Saving: result = "Saving"; break; - case Stopping: result = "Stopping"; break; - case Pausing: result = "Pausing"; break; - case Resuming: result = "Resuming"; break; - } - return result; - } - - public static string ToCloudStackState(UInt16 value) - { - string result = "Unknown"; - switch (value) - { - case Enabled: result = "Running"; break; - case Disabled: result = "Stopped"; break; - case Paused: result = "Unknown"; break; - case Suspended: result = "Unknown"; break; - case Starting: result = "Starting"; break; - case Snapshotting: result = "Unknown"; break; // NOT used - case Saving: result = "Saving"; break; - case Stopping: result = "Stopping"; break; - case Pausing: result = "Unknown"; break; - case Resuming: result = "Starting"; break; - } - return result; - } + } + + public class WmiException : Exception + { + public WmiException() + { + } + + public WmiException(string message) + : base(message) + { + } + + public WmiException(string message, Exception inner) + : base(message, inner) + { + } + } + + /// + /// Covers V2 API, see + /// http://msdn.microsoft.com/en-us/library/hh850031%28v=vs.85%29.aspx + /// + public static class ReturnCode + { + public const UInt32 Completed = 0; + public const UInt32 Started = 4096; + public const UInt32 Failed = 32768; + public const UInt32 AccessDenied = 32769; + public const UInt32 NotSupported = 32770; + public const UInt32 Unknown = 32771; + public const UInt32 Timeout = 32772; + public const UInt32 InvalidParameter = 32773; + public const UInt32 SystemInUse = 32774; + public const UInt32 InvalidState = 32775; + public const UInt32 IncorrectDataType = 32776; + public const UInt32 SystemNotAvailable = 32777; + public const UInt32 OutofMemory = 32778; + public static string ToString(UInt32 value) + { + string result = "Unknown return code"; + switch (value) + { + case Completed: result = "Completed"; break; + case Started: result = "Started"; break; + case Failed: result = "Failed"; break; + case AccessDenied: result = "AccessDenied"; break; + case NotSupported: result = "NotSupported"; break; + case Unknown: result = "Unknown"; break; + case Timeout: result = "Timeout"; break; + case InvalidParameter: result = "InvalidParameter"; break; + case SystemInUse: result = "SystemInUse"; break; + case InvalidState: result = "InvalidState"; break; + case IncorrectDataType: result = "IncorrectDataType"; break; + case SystemNotAvailable: result = "SystemNotAvailable"; break; + case OutofMemory: result = "OutofMemory"; break; + } + return result; + } + } + + /// + /// Covers V2 API, see + /// http://msdn.microsoft.com/en-us/library/hh850031%28v=vs.85%29.aspx + /// + public static class JobState + { + public const UInt16 New = 2; + public const UInt16 Starting = 3; + public const UInt16 Running = 4; + public const UInt16 Suspended = 5; + public const UInt16 ShuttingDown = 6; + public const UInt16 Completed = 7; + public const UInt16 Terminated = 8; + public const UInt16 Killed = 9; + public const UInt16 Exception = 10; + public const UInt16 Service = 11; + public static string ToString(UInt16 value) + { + string result = "Unknown JobState code"; + switch (value) + { + case New: result = "New"; break; + case Starting: result = "Starting"; break; + case Running: result = "Running"; break; + case Suspended: result = "Suspended"; break; + case ShuttingDown: result = "ShuttingDown"; break; + case Completed: result = "Completed"; break; + case Terminated: result = "Terminated"; break; + case Killed: result = "Killed"; break; + case Exception: result = "Exception"; break; + case Service: result = "Service"; break; + } + return result; + } + } + + /// + /// V2 API (see http://msdn.microsoft.com/en-us/library/hh850279(v=vs.85).aspx) + /// has removed 'Paused' and 'Suspended' as compared to the + /// V1 API (see http://msdn.microsoft.com/en-us/library/cc723874%28v=vs.85%29.aspx) + /// However, Paused and Suspended appear on the VM state transition table + /// (see http://msdn.microsoft.com/en-us/library/hh850116(v=vs.85).aspx#methods) + /// + public class RequiredState + { + public const UInt16 Enabled = 2; // Turns the VM on. + public const UInt16 Disabled = 3; // Turns the VM off. + public const UInt16 ShutDown = 4; + public const UInt16 Offline = 6; + //public const UInt16 Test = 7; + public const UInt16 Defer = 8; + // public const UInt16 Quiesce = 9; + // public const UInt16 Reboot = 10; // A hard reset of the VM. + public const UInt16 Reset = 11; // For future use. + public const UInt16 Paused = 9; // Pauses the VM. + public const UInt16 Suspended = 32779; // Saves the state of the VM. + + public static string ToString(UInt16 value) + { + string result = "Unknown RequiredState code"; + switch (value) + { + case Enabled: result = "Enabled"; break; + case Disabled: result = "Disabled"; break; + case ShutDown: result = "ShutDown"; break; + case Offline: result = "Offline"; break; + case Defer: result = "Defer"; break; + case Reset: result = "Reset"; break; + } + return result; + } + } + + /// + /// V2 API specifies the states below in its state transition graph at + /// http://msdn.microsoft.com/en-us/library/hh850116(v=vs.85).aspx#methods + /// However, the CIM standard has additional possibilities based on the description + /// of EnabledState. + /// The previous V1 API is described by + /// http://msdn.microsoft.com/en-us/library/cc136822%28v=vs.85%29.aspx + /// + public class EnabledState + { + /// + /// The state of the VM could not be determined. + /// + public const UInt16 Unknown = 0; + /// + /// The VM is running. + /// + public const UInt16 Enabled = 2; + /// + /// The VM is turned off. + /// + public const UInt16 Disabled = 3; + /// + /// The VM is paused. + /// + public const UInt16 Paused = 32768; + /// + /// The VM is in a saved state. + /// + public const UInt16 Suspended = 32769; + /// + /// The VM is starting. This is a transitional state between 3 (Disabled) + /// or 32769 (Suspended) and 2 (Enabled) initiated by a call to the + /// RequestStateChange method with a RequestedState parameter of 2 (Enabled). + /// + public const UInt16 Starting = 32770; + /// + /// Starting with Windows Server 2008 R2 this value is not supported. + /// If the VM is performing a snapshot operation, the element at index 1 + /// of the OperationalStatus property array will contain 32768 (Creating Snapshot), + /// 32769 (Applying Snapshot), or 32770 (Deleting Snapshot). + /// + public const UInt16 Snapshotting = 32771; + /// + /// The VM is saving its state. This is a transitional state between 2 (Enabled) + /// and 32769 (Suspended) initiated by a call to the RequestStateChange method + /// with a RequestedState parameter of 32769 (Suspended). + /// + public const UInt16 Saving = 32773; + /// + /// The VM is turning off. This is a transitional state between 2 (Enabled) + /// and 3 (Disabled) initiated by a call to the RequestStateChange method + /// with a RequestedState parameter of 3 (Disabled) or a guest operating system + /// initiated power off. + /// + public const UInt16 Stopping = 32774; + /// + /// The VM is pausing. This is a transitional state between 2 (Enabled) and 32768 (Paused) initiated by a call to the RequestStateChange method with a RequestedState parameter of 32768 (Paused). + /// + public const UInt16 Pausing = 32776; + /// + /// The VM is resuming from a paused state. This is a transitional state between 32768 (Paused) and 2 (Enabled). + /// + public const UInt16 Resuming = 32777; + + public static string ToString(UInt16 value) + { + string result = "Unknown"; + switch (value) + { + case Enabled: result = "Enabled"; break; + case Disabled: result = "Disabled"; break; + case Paused: result = "Paused"; break; + case Suspended: result = "Suspended"; break; + case Starting: result = "Starting"; break; + case Snapshotting: result = "Snapshotting"; break; // NOT used + case Saving: result = "Saving"; break; + case Stopping: result = "Stopping"; break; + case Pausing: result = "Pausing"; break; + case Resuming: result = "Resuming"; break; + } + return result; + } + + public static string ToCloudStackState(UInt16 value) + { + string result = "Unknown"; + switch (value) + { + case Enabled: result = "Running"; break; + case Disabled: result = "Stopped"; break; + case Paused: result = "Unknown"; break; + case Suspended: result = "Unknown"; break; + case Starting: result = "Starting"; break; + case Snapshotting: result = "Unknown"; break; // NOT used + case Saving: result = "Saving"; break; + case Stopping: result = "Stopping"; break; + case Pausing: result = "Unknown"; break; + case Resuming: result = "Starting"; break; + } + return result; + } public static string ToCloudStackPowerState(UInt16 value) { @@ -2988,5 +2988,5 @@ namespace HypervResource } return result; } - } -} + } +}