From 095fb09b7519289ab0d2ae3a880c5477d0cb52cc Mon Sep 17 00:00:00 2001 From: Rajesh Battala Date: Mon, 5 May 2014 12:55:59 +0530 Subject: [PATCH] CLOUDSTACK-6518 [Hyper-V] Efficient way of finding the empty nic in VR/VpcVR to configure VPC entities (cherry picked from commit cf41ccaa5b6475dace0bddbe6681c98cc5149189) Conflicts: plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/HypervResourceController.cs plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/IWmiCallsV2.cs plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/WmiCallsV2.cs --- .../HypervResourceController.cs | 226 +- .../HypervResource/IWmiCallsV2.cs | 8 +- .../HypervResource/WmiCallsV2.cs | 2391 ++++------------- 3 files changed, 581 insertions(+), 2044 deletions(-) diff --git a/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/HypervResourceController.cs b/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/HypervResourceController.cs index 41a3a8aa71e..40ac1593c93 100644 --- a/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/HypervResourceController.cs +++ b/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/HypervResourceController.cs @@ -857,29 +857,11 @@ namespace HypervResource { 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); - } - + logger.Info(CloudStackTypes.PlugNicCommand + Utils.CleanString(cmd.ToString())); object ansContent = new { - result = result, - volumePath = (string)cmd.volumePath, - details = details, + result = true, + details = "Hot Nic plug not supported, change any empty virtual network adapter network settings", contextMap = contextMap }; @@ -1193,28 +1175,21 @@ namespace HypervResource string details = null; bool result = false; - List volumeTos = new List(); - - try + String vmName = cmd.vmName; + String vlan = cmd.vlan; + string macAddress = cmd.macAddress; + uint pos = cmd.index; + bool enable = cmd.enable; + string switchLableName = cmd.switchLableName; + if (macAddress != null) { - 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); + wmiCallsV2.ModifyVmVLan(vmName, vlan, macAddress); result = true; } - catch (Exception sysEx) - { - details = CloudStackTypes.MigrateWithStorageCommand + " failed due to " + sysEx.Message; - logger.Error(details, sysEx); + else if (pos >= 1) + { + wmiCallsV2.ModifyVmVLan(vmName, vlan, pos, enable, switchLableName); + result = true; } object ansContent = new @@ -1259,142 +1234,45 @@ namespace HypervResource { 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() + "." + - 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); - 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())) - { - logger.Info(CloudStackTypes.GetVncPortCommand + Utils.CleanString(cmd.ToString())); - - string details = null; + logger.Info(CloudStackTypes.GetVmConfigCommand + Utils.CleanString(cmd.ToString())); bool result = false; - string address = null; - int port = -9; + String vmName = cmd.vmName; + ComputerSystem vm = wmiCallsV2.GetComputerSystem(vmName); + 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++; + } + + index = 0; + foreach (SyntheticEthernetPortSettingData item in nicSettingsViaVm) + { + nic = new NicDetails(item.Address, nicVlan[index], nicStates[index]); + index++; + nicDetails.Add(nic); + } - 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); - } + + result = true; object ansContent = new { diff --git a/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/IWmiCallsV2.cs b/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/IWmiCallsV2.cs index 0a64f4bc7e8..896a287c6cf 100644 --- a/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/IWmiCallsV2.cs +++ b/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/IWmiCallsV2.cs @@ -71,8 +71,8 @@ namespace HypervResource 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 104ee2d5e0d..1c5a458c795 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}", @@ -379,6 +379,8 @@ namespace HypervResource } int nicCount = 0; + int enableState = 2; + // Add the Nics to the VM in the deviceId order. foreach (var nc in nicInfo) { @@ -417,13 +419,17 @@ namespace HypervResource throw ex; } } - if(nicIp.Equals("0.0.0.0") && nicNetmask.Equals("255.255.255.255") ) { - // this is the extra nic added to VR. - vlan = defaultvlan; - } - + + 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 =""; @@ -431,10 +437,11 @@ namespace HypervResource { switchName = nic.name; } - + EthernetPortAllocationSettingData portSettings = null; // connection to vswitch - var portSettings = AttachNicToPort(newVm, newAdapter, switchName); - + portSettings = AttachNicToPort(newVm, newAdapter, switchName, enableState); + //reset the flag for other nics + enableState = 2; // set vlan if (vlan != null) { @@ -446,38 +453,38 @@ namespace HypervResource 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); @@ -519,7 +526,7 @@ namespace HypervResource return false; } - private EthernetPortAllocationSettingData AttachNicToPort(ComputerSystem newVm, SyntheticEthernetPortSettingData newAdapter, String vSwitchName) + private EthernetPortAllocationSettingData AttachNicToPort(ComputerSystem newVm, SyntheticEthernetPortSettingData newAdapter, String vSwitchName, int enableState) { // Get the virtual switch VirtualEthernetSwitch vSwitch = GetExternalVirtSwitch(vSwitchName); @@ -548,7 +555,7 @@ namespace HypervResource 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); @@ -908,8 +915,19 @@ namespace HypervResource return new ResourceAllocationSettingData((ManagementBaseObject)defaultDiskDriveSettings.LateBoundObject.Clone()); } - // 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-")) + // Modify the systemvm nic's VLAN id + public void ModifyVmVLan(string vmName, String vlanid, String mac) + { + int enableState = 2; + bool enable = true; + ComputerSystem vm = GetComputerSystem(vmName); + SyntheticEthernetPortSettingData[] nicSettingsViaVm = GetEthernetPortSettings(vm); + // Obtain controller for Hyper-V virtualisation subsystem + VirtualSystemManagementService vmMgmtSvc = GetVirtualisationSystemManagementService(); + EthernetPortAllocationSettingData networkAdapter = null; + string normalisedMAC = string.Join("", (mac.Split(new char[] { ':' }))); + int index = 0; + foreach (SyntheticEthernetPortSettingData item in nicSettingsViaVm) { System.Threading.Thread.Sleep(90000); // wait for the second boot and then return with sucesss @@ -918,1588 +936,229 @@ namespace HypervResource { System.Threading.Thread.Sleep(90000); } - else - { - pingResource(publicIpAddress); - }*/ - } - 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; - bool enable = true; - ComputerSystem vm = GetComputerSystem(vmName); - SyntheticEthernetPortSettingData[] nicSettingsViaVm = GetEthernetPortSettings(vm); - // Obtain controller for Hyper-V virtualisation subsystem - VirtualSystemManagementService vmMgmtSvc = GetVirtualisationSystemManagementService(); - EthernetPortAllocationSettingData networkAdapter = null; - 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++; - } - 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; + 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); - } - } + 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; + } } - // 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) + }); + } } - // 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 + // 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); - } - } - } - } - - 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; - } - - // Stop VM - logger.DebugFormat("Stop 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); - } - - /// - /// 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); - VirtualSystemSettingData vmSettings = GetVmSettings(vm); - 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"] = ""; - 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); - VirtualSystemSettingData vmSettings = GetVmSettings(vm); - 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); - - var vmVirtMgmtSvc = GetVirtualisationSystemManagementService(); - var bandwidthSettings = EthernetSwitchPortBandwidthSettingData.GetInstances(vmVirtMgmtSvc.Scope, "InstanceID LIKE \"%Default\""); - - // Assert - if (bandwidthSettings.Count != 1) - { - var errMsg = string.Format("Internal error, could not find default EthernetSwitchPortBandwidthSettingData instance"); - var ex = new WmiException(errMsg); - logger.Error(errMsg, ex); - throw ex; - } - var defaultBandwidthSettings = bandwidthSettings.OfType().First(); - - var newBandwidthSettings = new EthernetSwitchPortBandwidthSettingData((ManagementBaseObject)defaultBandwidthSettings.LateBoundObject.Clone()); - newBandwidthSettings.Limit = limit * 1000000; - - // Insert bandwidth settings to nic - string[] newResources = new string[] { newBandwidthSettings.LateBoundObject.GetText(System.Management.TextFormat.CimDtd20) }; - ManagementPath[] newResourcePaths = AddFeatureSettings(newResources, portPath.Path); - - // assert - if (newResourcePaths.Length != 1) - { - var errMsg = string.Format( - "Failed to properly apply network rate limit {0} for NIC on port {1}", - limit, - portPath.Path); - var ex = new WmiException(errMsg); - logger.Error(errMsg, ex); - throw ex; - } - } - - - /// - /// 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) - { - // Resource settings are changed through the management service - System.Management.ManagementPath jobPath; - System.Management.ManagementPath[] results; - - var ret_val = vmMgmtSvc.ModifyFeatureSettings( - 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 - System.Management.ManagementPath jobPath; - - var ret_val = vmMgmtSvc.ModifySystemSettings( - systemSettings, - 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 system setting {0}", - 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(); - VirtualSystemSettingData vmSettings = GetVmSettings(vm); - - vmSettings.LateBoundObject["Notes"] = new string[] { "Created by CloudStack, do not edit. \n" }; - ModifySystemSetting(vmMgmtSvc, vmSettings.LateBoundObject.GetText(TextFormat.CimDtd20)); - 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. - UInt16 startupAction = 2; // Do nothing. - UInt16 stopAction = 4; // Shutdown. - 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() - { - ComputerSystem vm = GetComputerSystem(vmName); - // Obtain controller for Hyper-V virtualisation subsystem - VirtualSystemManagementService vmMgmtSvc = GetVirtualisationSystemManagementService(); - - 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; + 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); + } + } } }