cloudstack-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From devd...@apache.org
Subject [28/31] A plugin for Hyper-V control is available for CloudStack. The plugin implements basic VM control; however, its architecture allows additional functionality to be easily added. Incorporating the plugin in CloudStack will allow the community to
Date Wed, 02 Oct 2013 09:20:48 GMT
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/1d0a931d/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/WmiCalls.cs
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/WmiCalls.cs b/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/WmiCalls.cs
new file mode 100644
index 0000000..0442be3
--- /dev/null
+++ b/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/WmiCalls.cs
@@ -0,0 +1,1469 @@
+// 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;
+using log4net;
+using System.Globalization;
+using System.Management;
+using Newtonsoft.Json;
+using Newtonsoft.Json.Linq;
+using CloudStack.Plugin.WmiWrappers.ROOT.CIMV2;
+using System.IO;
+
+namespace HypervResource
+{
+    public class WmiCalls
+    {
+        public static void Initialize()
+        {
+            // Trigger assembly load into curren appdomain
+        }
+
+        private static ILog logger = LogManager.GetLogger(typeof(WmiCalls));
+
+        /// <summary>
+        /// Returns ComputerSystem lacking any NICs and VOLUMEs
+        /// </summary>
+        public static 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;
+        }
+
+        /// <summary>
+        /// Create a (synthetic) nic, and attach it to the vm
+        /// </summary>
+        /// <param name="vm"></param>
+        /// <param name="mac"></param>
+        /// <param name="vlan"></param>
+        /// <returns></returns>
+        public static SyntheticEthernetPortSettingData CreateNICforVm(ComputerSystem vm, string mac, string vlan)
+        {
+            logger.DebugFormat("Creating nic for VM {0} (GUID {1})", vm.ElementName, vm.Name);
+
+            // Obtain controller for Hyper-V networking subsystem
+            VirtualSwitchManagementService 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<SyntheticEthernetPortSettingData>().First();
+
+            var newSynthNICSettings = new SyntheticEthernetPortSettingData((ManagementBaseObject)defaultSynthNICSettings.LateBoundObject.Clone());
+
+            // Get the virtual switch
+            VirtualSwitch vSwitch = GetExternalVirtSwitch();
+
+            // Crate switch port for new VM
+            ManagementPath newSwitchPath = CreateSwitchPortForVm(vm, vmNetMgmtSvc, vSwitch);
+
+            // Add required VLAND support
+            if (vlan != null)
+            {
+                SetPortVlan(vlan, vmNetMgmtSvc, newSwitchPath);
+            }
+
+            logger.DebugFormat("Created switch port {0} on switch {1}", newSwitchPath.Path, vSwitch.Path.Path);
+
+            //  Assign configuration to new NIC
+            string normalisedMAC = string.Join("", (mac.Split(new char[] { ':' })));
+            newSynthNICSettings.LateBoundObject["Connection"] = new string[] { newSwitchPath.Path };
+            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_HARDDISK_DRIVE = "Microsoft Synthetic Disk Drive";
+        public const string IDE_ISO_DRIVE  = "Microsoft Synthetic DVD Drive";
+
+        public const string IDE_ISO_DISK = "Microsoft Virtual CD/DVD Disk"; // For IDE_ISO_DRIVE
+        public const string IDE_HARDDISK_DISK = "Microsoft Virtual Hard Disk"; // For IDE_HARDDISK_DRIVE
+
+        /// <summary>
+        /// Create new VM.  By default we start it. 
+        /// </summary>
+        public static ComputerSystem DeployVirtualMachine(dynamic jsonObj)
+        {
+            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;
+
+            // 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
+                {
+                    // TODO: revise exception type
+                    errMsg = string.Format("Create VM failing, because there exists a VM with name {0}, state {1}", 
+                        vmName,
+                        EnabledState.ToString(vmWmiObj.EnabledState));
+                    var ex = new WmiException(errMsg);
+                    logger.Error(errMsg, ex);
+                    throw ex;
+                }
+            }
+
+            // Create vm carcase
+            logger.DebugFormat("Going ahead with create VM {0}, {1} vcpus, {2}MB RAM", vmName, vcpus, memSize);
+            var newVm = WmiCalls.CreateVM(vmName, memSize, vcpus);
+
+            foreach (var diskDrive in diskDrives)
+            {
+                string vhdFile = null;
+                string diskName = null;
+                VolumeObjectTO volInfo = VolumeObjectTO.ParseJson(diskDrive.data);
+                if (volInfo != null)
+                {
+                    // assert
+                    errMsg = vmName + ": volume missing primaryDataStore for disk " + diskDrive.ToString();
+                    if (volInfo.primaryDataStore == null)
+                    {
+                        logger.Error(errMsg);
+                        throw new ArgumentException(errMsg);
+                    }
+                    diskName = volInfo.name;
+
+                    // assert
+                    errMsg = vmName + ": can't deal with DataStore type for disk " + diskDrive.ToString();
+                    if (volInfo.primaryDataStore == null)
+                    {
+                        logger.Error(errMsg);
+                        throw new ArgumentException(errMsg);
+                    }
+                    errMsg = vmName + ": Malformed PrimaryDataStore for disk " + diskDrive.ToString();
+                    if (String.IsNullOrEmpty(volInfo.primaryDataStore.path))
+                    {
+                        logger.Error(errMsg);
+                        throw new ArgumentException(errMsg);
+                    }
+                    errMsg = vmName + ": Missing folder PrimaryDataStore for disk " + diskDrive.ToString() + ", missing path: " +  volInfo.primaryDataStore.path;
+                    if (!Directory.Exists(volInfo.primaryDataStore.path))
+                    {
+                        logger.Error(errMsg);
+                        throw new ArgumentException(errMsg);
+                    }
+
+                    vhdFile = volInfo.FullFileName;
+                    if (!System.IO.File.Exists(vhdFile))
+                    {
+                        errMsg = vmName + ": non-existent volume, missing " + vhdFile + " for drive " + diskDrive.ToString();
+                        logger.Error(errMsg);
+                        throw new ArgumentException(errMsg);
+                    }
+                    logger.Debug("Going to create " + vmName + " with attached voluem " + diskName + " at " + vhdFile);
+                }
+
+                string driveType = diskDrive.type;
+
+                string ideCtrllr = "0";
+                string driveResourceType = null;
+                switch (driveType) {
+                    case "ROOT":
+                        ideCtrllr = "0";
+                        driveResourceType = IDE_HARDDISK_DRIVE;
+                        break;
+                    case "ISO":
+                        ideCtrllr = "1";
+                        driveResourceType = IDE_ISO_DRIVE;
+                        break;
+                    default: 
+                        // TODO: double check exception type
+                        errMsg = string.Format("Unknown disk type {0} for disk {1}, vm named {2}", 
+                                string.IsNullOrEmpty(driveType) ? "NULL" : driveType,
+                                string.IsNullOrEmpty(diskName) ? "NULL" : diskName, vmName);
+                        var ex = new WmiException(errMsg);
+                        logger.Error(errMsg, ex);
+                        throw ex;
+                }
+                logger.DebugFormat("Create disk type {1} (Named: {0}), on vm {2} {3}", diskName, driveResourceType, vmName, 
+                                        string.IsNullOrEmpty(vhdFile) ? " no disk to insert" : ", inserting disk" +vhdFile );
+                AddDiskDriveToVm(newVm, vhdFile, ideCtrllr, driveResourceType);
+            }
+
+            // add nics
+            foreach (var nic in nicInfo)
+            {
+                string mac = nic.mac;
+                string vlan = null;
+                string isolationUri = nic.isolationUri;
+                if (isolationUri != null && isolationUri.StartsWith("vlan://") && !isolationUri.Equals("vlan://untagged"))
+                {
+                    vlan = isolationUri.Substring("vlan://".Length);
+                    int tmp;
+                    if (!int.TryParse(vlan, out tmp))
+                    {
+                        // TODO: double check exception type
+                        errMsg = string.Format("Invalid VLAN value {0} for on vm {1} for nic uuid {2}", isolationUri, vmName, nic.uuid);
+                        var ex = new WmiException(errMsg);
+                        logger.Error(errMsg, ex);
+                        throw ex;
+                    }
+                }
+                CreateNICforVm(newVm, mac, vlan);
+            }
+
+            logger.DebugFormat("Starting VM {0}", vmName);
+            SetState(newVm, RequiredState.Enabled);
+            logger.InfoFormat("Started VM {0}", vmName);
+            return newVm;
+       }
+
+        /// <summary>
+        /// Create a disk and attach it to the vm
+        /// </summary>
+        /// <param name="vm"></param>
+        /// <param name="cntrllerAddr"></param>
+        /// <param name="driveResourceType">IDE_HARDDISK_DRIVE or IDE_ISO_DRIVE</param>
+        public static ManagementPath AddDiskDriveToVm(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 IDE_HARDDISK_DRIVE:
+                    diskResourceSubType = IDE_HARDDISK_DISK;
+                    break;
+                case IDE_ISO_DRIVE: 
+                    diskResourceSubType = IDE_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 = AttachNewDriveToVm(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;
+    }
+
+        private static ManagementPath AttachNewDriveToVm(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["Address"] = "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.Address);
+            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 static void InsertDiskImage(ComputerSystem vm, string vhdfile, 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 = CloneResourceAllocationSetting(defaultDiskQuery);
+
+            // Set disk drive and VHD file on disk for new disk
+            newDiskSettings.LateBoundObject["Parent"] = drivePath.Path;
+            newDiskSettings.LateBoundObject["Connection"] = new string[] { vhdfile };
+            newDiskSettings.CommitObject();
+
+            // Add the new vhd object as a virtual hard disk to the vm.
+            string[] newDiskResource = new string[] { newDiskSettings.LateBoundObject.GetText(System.Management.TextFormat.CimDtd20) };
+            ManagementPath[] newDiskPaths = AddVirtualResource(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,
+                    vhdfile);
+        }
+
+        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<ResourceAllocationSettingData>().First();
+            return new ResourceAllocationSettingData((ManagementBaseObject)defaultDiskDriveSettings.LateBoundObject.Clone());
+        }
+
+        public static void DestroyVm(dynamic jsonObj)
+        {
+            string vmToDestroy = jsonObj.vmName;
+            DestroyVm(vmToDestroy);
+        }
+        
+        /// <summary>
+        /// Remove all VMs and all SwitchPorts with the displayName.  VHD gets deleted elsewhere.
+        /// </summary>
+        /// <param name="displayName"></param>
+        public static 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
+            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.DestroyVirtualSystem(vm.Path, out jobPath);
+
+                if (ret_val == ReturnCode.Started)
+                {
+                    JobCompleted(jobPath);
+                }
+                else if (ret_val != ReturnCode.Completed)
+                {
+                    var errMsg = string.Format(
+                        "Failed Delete VM {0} (GUID {1}) due to {2}",
+                        vm.ElementName,
+                        vm.Name,
+                        ReturnCode.ToString(ret_val));
+                    var ex = new WmiException(errMsg);
+                    logger.Error(errMsg, ex);
+                    throw ex;
+                }
+                vm = GetComputerSystem(displayName);
+            }
+            while (vm != null);
+        }
+
+        public static 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;
+            // TimeSpan is a value type; default ctor is equivalent to 0.
+            var ret_val = vm.RequestStateChange(requiredState, new TimeSpan(), out jobPath);
+
+            // If the Job is done asynchronously
+            if (ret_val == ReturnCode.Started)
+            {
+                JobCompleted(jobPath);
+            }
+            else if (ret_val == 32775)
+            {
+                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
+        public static bool DeleteSwitchPort(string elementName)
+        {
+            var virtSwitchMgmtSvc = GetVirtualSwitchManagementService();
+            // Get NIC path
+            var condition = string.Format("ElementName=\"{0}\"", elementName);
+            var switchPortCollection = SwitchPort.GetInstances(virtSwitchMgmtSvc.Scope, condition);
+            if (switchPortCollection.Count == 0)
+            {
+                return true;
+            }
+
+            foreach (SwitchPort port in switchPortCollection)
+            {
+                // Destroy
+                var ret_val = virtSwitchMgmtSvc.DeleteSwitchPort(port.Path);
+
+                if (ret_val != ReturnCode.Completed)
+                {
+                    return false;
+                }
+            }
+
+            return true;
+        }
+
+        // Add new 
+        private static ManagementPath[] AddVirtualResource(string[] resourceSettings, ComputerSystem vm )
+        {
+            var virtSysMgmtSvc = GetVirtualisationSystemManagementService();
+
+            ManagementPath jobPath;
+            ManagementPath[] resourcePaths;
+            var ret_val = virtSysMgmtSvc.AddVirtualSystemResources(
+                resourceSettings, 
+                vm.Path,
+                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 static ManagementPath CreateSwitchPortForVm(ComputerSystem vm, VirtualSwitchManagementService vmNetMgmtSvc, VirtualSwitch vSwitch)
+        {
+            ManagementPath newSwitchPath = null;
+            var ret_val = vmNetMgmtSvc.CreateSwitchPort(
+                vm.ElementName,
+                Guid.NewGuid().ToString(),
+                "",
+                vSwitch.Path,
+                out newSwitchPath);
+            // Job is always done synchronously
+            if (ret_val != ReturnCode.Completed)
+            {
+                var errMsg = string.Format(
+                    "Failed to create switch for NIC on VM {0} (GUID {1}), error code {2}",
+                    vm.ElementName,
+                    vm.Name,
+                    ret_val);
+                var ex = new WmiException(errMsg);
+                logger.Error(errMsg, ex);
+                throw ex;
+            }
+            return newSwitchPath;
+        }
+
+        // add vlan support by setting AccessVLAN on VLANEndpointSettingData for port
+        private static void SetPortVlan(string vlan, VirtualSwitchManagementService vmNetMgmtSvc, ManagementPath newSwitchPath)
+        {
+            logger.DebugFormat("Setting VLAN to {0}", vlan);
+
+            VLANEndpointSettingData vlanEndpointSettings = GetVlanEndpointSettings(vmNetMgmtSvc, newSwitchPath);
+            vlanEndpointSettings.LateBoundObject["AccessVLAN"] = vlan;
+            vlanEndpointSettings.CommitObject();
+        }
+
+        public static VLANEndpointSettingData GetVlanEndpointSettings(VirtualSwitchManagementService vmNetMgmtSvc, ManagementPath newSwitchPath)
+        {
+            // Get Msvm_VLANEndpoint through associated with new Port
+            var vlanEndpointQuery = new RelatedObjectQuery(newSwitchPath.Path, VLANEndpoint.CreatedClassName);
+            var vlanEndpointSearch = new ManagementObjectSearcher(vmNetMgmtSvc.Scope, vlanEndpointQuery);
+            var vlanEndpointCollection = new VLANEndpoint.VLANEndpointCollection(vlanEndpointSearch.Get());
+
+            // assert
+            if (vlanEndpointCollection.Count != 1)
+            {
+                var errMsg = string.Format("No VLANs for vSwitch on Hyper-V server for switch {0}", newSwitchPath.Path);
+                var ex = new WmiException(errMsg);
+                logger.Error(errMsg, ex);
+                throw ex;
+            }
+
+            VLANEndpoint vlanEndpoint = vlanEndpointCollection.OfType<VLANEndpoint>().First();
+
+            // Get Msvm_VLANEndpointSettingData assocaited with Msvm_VLANEndpoint
+            var vlanEndpointSettingsQuery = new RelatedObjectQuery(vlanEndpoint.Path.Path, VLANEndpointSettingData.CreatedClassName);
+            var vlanEndpointSettingsSearch = new ManagementObjectSearcher(vmNetMgmtSvc.Scope, vlanEndpointSettingsQuery);
+            var vlanEndpointSettingsCollection = new VLANEndpointSettingData.VLANEndpointSettingDataCollection(vlanEndpointSettingsSearch.Get());
+
+            // assert
+            if (vlanEndpointSettingsCollection.Count != 1)
+            {
+                var errMsg = string.Format("Internal error, VLAN for vSwitch not setup propertly Hyper-V");
+                var ex = new WmiException(errMsg);
+                logger.Error(errMsg, ex);
+                throw ex;
+            }
+
+            VLANEndpointSettingData vlanEndpointSettings = vlanEndpointSettingsCollection.OfType<VLANEndpointSettingData>().First();
+            return vlanEndpointSettings;
+        }
+
+        /// <summary>
+        /// External VSwitch has an external NIC, and we assume there is only one external NIC
+        /// </summary>
+        /// <param name="vmSettings"></param>
+        /// <returns></returns>
+        /// <throw>Throws if there is no vswitch</throw>
+        public static VirtualSwitch GetExternalVirtSwitch()
+        {
+            // Work back from the first *bound* external NIC we find.
+            var externNICs = ExternalEthernetPort.GetInstances("IsBound = TRUE");
+
+            if (externNICs.Count == 0 )
+            {
+                var errMsg = "No ExternalEthernetPort available to Hyper-V";
+                var ex = new WmiException(errMsg);
+                logger.Error(errMsg, ex);
+                throw ex;
+            }
+
+            ExternalEthernetPort externNIC = externNICs.OfType<ExternalEthernetPort>().First();
+
+            // 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, SwitchLANEndpoint.CreatedClassName);
+            var endpointSearch = new ManagementObjectSearcher(externNIC.Scope, endpointQuery);
+            var endpointCollection = new SwitchLANEndpoint.SwitchLANEndpointCollection(endpointSearch.Get());
+
+            // assert
+            if (endpointCollection.Count < 1 )
+            {
+                var errMsg = string.Format("No SwitchLANEndpoint for external NIC {0} on Hyper-V server", externNIC.Name);
+                var ex = new WmiException(errMsg);
+                logger.Error(errMsg, ex);
+                throw ex;
+            }
+
+            SwitchLANEndpoint endPoint = endpointCollection.OfType<SwitchLANEndpoint>().First();
+            var switchPortQuery = new RelatedObjectQuery(endPoint.Path.Path, SwitchPort.CreatedClassName);
+            var switchPortSearch = new ManagementObjectSearcher(externNIC.Scope, switchPortQuery);
+            var switchPortCollection = new SwitchPort.SwitchPortCollection(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;
+            }
+
+            SwitchPort switchPort = switchPortCollection.OfType<SwitchPort>().First();
+            var vSwitchQuery = new RelatedObjectQuery(switchPort.Path.Path, VirtualSwitch.CreatedClassName);
+            var vSwitchSearch = new ManagementObjectSearcher(externNIC.Scope, vSwitchQuery);
+            var vSwitchCollection = new VirtualSwitch.VirtualSwitchCollection(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;
+            }
+
+            VirtualSwitch vSwitch = vSwitchCollection.OfType<VirtualSwitch>().First();
+
+            return vSwitch;
+        }
+
+
+        private static void ModifyVmResources(VirtualSystemManagementService vmMgmtSvc, ComputerSystem vm, string[] resourceSettings)
+        {
+            // Resource settings are changed through the management service
+            System.Management.ManagementPath jobPath;
+
+            var ret_val = vmMgmtSvc.ModifyVirtualSystemResources(vm.Path,
+                resourceSettings,
+                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;
+            }
+        }
+
+        private static ComputerSystem CreateDefaultVm(VirtualSystemManagementService vmMgmtSvc, string name)
+        {
+            // Tweak default settings by basing new VM on default global setting object 
+            // with designed display name.
+
+            VirtualSystemGlobalSettingData vs_gs_data = VirtualSystemGlobalSettingData.CreateInstance();
+            vs_gs_data.LateBoundObject["ElementName"] = name;
+
+            System.Management.ManagementPath jobPath;
+            System.Management.ManagementPath defined_sys;
+            var ret_val = vmMgmtSvc.DefineVirtualSystem(
+                new string[0],
+                null,
+                vs_gs_data.LateBoundObject.GetText(System.Management.TextFormat.CimDtd20),
+                out defined_sys,
+                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 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 static VirtualSwitchManagementService GetVirtualSwitchManagementService()
+        {
+            // VirtualSwitchManagementService is a singleton, most anonymous way of lookup is by asking for the set
+            // of local instances, which should be size 1.
+            var virtSwtichSvcCollection = VirtualSwitchManagementService.GetInstances();
+            foreach (VirtualSwitchManagementService item in virtSwtichSvcCollection)
+            {
+                return item;
+            }
+
+            var errMsg = string.Format("No Hyper-V subsystem on server");
+            var ex = new WmiException(errMsg);
+            logger.Error(errMsg, ex);
+            throw ex;
+        }
+
+        public static void CreateDynamicVirtualHardDisk(ulong MaxInternalSize, string Path)
+        {
+            // Resource settings are changed through the management service
+            System.Management.ManagementPath jobPath;
+            var imgMgr = GetImageManagementService();
+            var ret_val = imgMgr.CreateDynamicVirtualHardDisk(MaxInternalSize, 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 CreateDynamicVirtualHardDisk size {0}, path {1} to {2}",
+                    MaxInternalSize,
+                    Path,
+                    ReturnCode.ToString(ret_val));
+                var ex = new WmiException(errMsg);
+                logger.Error(errMsg, ex);
+                throw ex;
+            }
+        }
+
+        public static ImageManagementService GetImageManagementService()
+        {
+            // VirtualSystemManagementService is a singleton, most anonymous way of lookup is by asking for the set
+            // of local instances, which should be size 1.
+
+            var coll = ImageManagementService.GetInstances();
+            foreach (ImageManagementService item in coll)
+            {
+                return item;
+            }
+
+            var errMsg = string.Format("No Hyper-V subsystem on server");
+            var ex = new WmiException(errMsg);
+            logger.Error(errMsg, ex);
+            throw ex;
+        }
+
+
+        public static VirtualSystemManagementService GetVirtualisationSystemManagementService()
+        {
+            // VirtualSystemManagementService is a singleton, most anonymous way of lookup is by asking for the set
+            // of local instances, which should be size 1.
+           
+            var virtSysMgmtSvcCollection = VirtualSystemManagementService.GetInstances();
+            foreach (VirtualSystemManagementService item in virtSysMgmtSvcCollection)
+            {
+                return item;
+            }
+
+            var errMsg = string.Format("No Hyper-V subsystem on server");
+            var ex = new WmiException(errMsg);
+            logger.Error(errMsg, ex);
+            throw ex;
+        }
+
+        /// <summary>
+        /// Similar to http://msdn.microsoft.com/en-us/library/hh850031%28v=vs.85%29.aspx
+        /// </summary>
+        /// <param name="jobPath"></param>
+        /// <returns></returns>
+        private static void JobCompleted(ManagementPath jobPath)
+        {
+            ConcreteJob jobObj = null;
+            for(;;)
+            {
+                jobObj = new ConcreteJob(jobPath);
+                if (jobObj.JobState != JobState.Starting && jobObj.JobState != JobState.Running)
+                {
+                    break;
+                }
+                logger.InfoFormat("In progress... {0}% completed.", jobObj.PercentComplete);
+                System.Threading.Thread.Sleep(1000);
+            }
+
+            if (jobObj.JobState != JobState.Completed)
+            {
+                var errMsg = string.Format(
+                    "Hyper-V Job failed, Error Code:{0}, Description: {1}", 
+                    jobObj.ErrorCode, 
+                    jobObj.ErrorDescription);
+                var ex = new WmiException(errMsg);
+                logger.Error(errMsg, ex);
+                throw ex;
+            }
+
+            logger.DebugFormat("WMI job succeeded: {0}, Elapsed={1}", jobObj.Description, jobObj.ElapsedTime);
+        }
+
+        public static void GetProcessorResources(out uint cores, out uint mhz)
+        {
+            //  Processor processors
+            cores = 0;
+            mhz = 0;
+            Processor.ProcessorCollection procCol = Processor.GetInstances();
+            foreach (Processor procInfo in procCol)
+            {
+                cores += procInfo.NumberOfCores;
+                mhz = procInfo.MaxClockSpeed;
+           }
+        }
+        
+        public static void GetProcessorUsageInfo(out double cpuUtilization)
+        {
+            PerfFormattedData_Counters_ProcessorInformation.PerfFormattedData_Counters_ProcessorInformationCollection coll = 
+                            PerfFormattedData_Counters_ProcessorInformation.GetInstances("Name=\"_Total\"");
+            cpuUtilization = 100;
+            // Use the first one
+            foreach (PerfFormattedData_Counters_ProcessorInformation procInfo in coll)
+            {
+                // Idle during a given internal 
+                // See http://library.wmifun.net/cimv2/win32_perfformatteddata_counters_processorinformation.html
+                cpuUtilization = 100.0 - (double)procInfo.PercentIdleTime;            
+            }
+        }
+
+
+        public static void GetMemoryResources(out ulong physicalRamKBs, out ulong freeMemoryKBs)
+        {
+            OperatingSystem0 os = new OperatingSystem0();
+            physicalRamKBs = os.TotalVisibleMemorySize;
+            freeMemoryKBs = os.FreePhysicalMemory;
+        }
+
+        public static string GetDefaultVirtualDiskFolder()
+        {
+            VirtualSystemManagementServiceSettingData.VirtualSystemManagementServiceSettingDataCollection coll = VirtualSystemManagementServiceSettingData.GetInstances();
+            string defaultVirtualHardDiskPath = null;
+            foreach (VirtualSystemManagementServiceSettingData settings in coll)
+            {
+                return settings.DefaultVirtualHardDiskPath;
+            }
+
+            // assert
+            if (!System.IO.Directory.Exists(defaultVirtualHardDiskPath) ){
+                var errMsg = string.Format(
+                    "Hyper-V DefaultVirtualHardDiskPath is invalid!");
+                logger.Error(errMsg);
+                return null;
+            }
+            
+            return defaultVirtualHardDiskPath;
+        }
+
+        public static ComputerSystem GetComputerSystem(string displayName)
+        {
+            var wmiQuery = String.Format("ElementName=\"{0}\"", displayName);
+            ComputerSystem.ComputerSystemCollection vmCollection = ComputerSystem.GetInstances(wmiQuery);
+
+            // Return the first one
+            foreach (ComputerSystem vm in vmCollection)
+            {
+                return vm;
+            }
+            return null;
+        }
+
+        public static List<string> GetVmElementNames()
+        {
+            List<string> result = new List<string>();
+            ComputerSystem.ComputerSystemCollection vmCollection = ComputerSystem.GetInstances();
+
+            // Return the first one
+            foreach (ComputerSystem vm in vmCollection)
+            {
+                if (vm.Caption.StartsWith("Hosting Computer System") )
+                {
+                    continue;
+                }
+                result.Add(vm.ElementName);
+            }
+            return result;
+        }
+
+        public static ProcessorSettingData GetProcSettings(VirtualSystemSettingData vmSettings)
+        {
+            // An ASSOCIATOR object provides the cross reference from the VirtualSystemSettingData and the 
+            // ProcessorSettingData, but generated wrappers do not expose a ASSOCIATOR OF query as a method.
+            // Instead, we use the System.Management to code the equivalant of 
+            //  string query = string.Format( "ASSOCIATORS OF {{{0}}} WHERE ResultClass = {1}", vmSettings.path, resultclassName);
+            //
+            var wmiObjQuery = new RelatedObjectQuery(vmSettings.Path.Path, ProcessorSettingData.CreatedClassName);
+
+            // NB: default scope of ManagementObjectSearcher is '\\.\root\cimv2', which does not contain
+            // the virtualisation objects.
+            var wmiObjectSearch = new ManagementObjectSearcher(vmSettings.Scope, wmiObjQuery);
+            var wmiObjCollection = new ProcessorSettingData.ProcessorSettingDataCollection(wmiObjectSearch.Get());
+
+            foreach (ProcessorSettingData wmiObj in wmiObjCollection)
+            {
+                return wmiObj;
+            }
+
+            var errMsg = string.Format("No ProcessorSettingData in VirtualSystemSettingData {0}", vmSettings.Path.Path);
+            var ex = new WmiException(errMsg);
+            logger.Error(errMsg, ex);
+            throw ex;
+        }
+
+        public static MemorySettingData GetMemSettings(VirtualSystemSettingData vmSettings)
+        {
+            // An ASSOCIATOR object provides the cross reference from the VirtualSystemSettingData and the 
+            // MemorySettingData, but generated wrappers do not expose a ASSOCIATOR OF query as a method.
+            // Instead, we use the System.Management to code the equivalant of 
+            //  string query = string.Format( "ASSOCIATORS OF {{{0}}} WHERE ResultClass = {1}", vmSettings.path, resultclassName);
+            //
+            var wmiObjQuery = new RelatedObjectQuery(vmSettings.Path.Path, MemorySettingData.CreatedClassName);
+
+            // NB: default scope of ManagementObjectSearcher is '\\.\root\cimv2', which does not contain
+            // the virtualisation objects.
+            var wmiObjectSearch = new ManagementObjectSearcher(vmSettings.Scope, wmiObjQuery);
+            var wmiObjCollection = new MemorySettingData.MemorySettingDataCollection(wmiObjectSearch.Get());
+
+            foreach (MemorySettingData wmiObj in wmiObjCollection)
+            {
+                return wmiObj;
+            }
+
+            var errMsg = string.Format("No MemorySettingData in VirtualSystemSettingData {0}", vmSettings.Path.Path);
+            var ex = new WmiException(errMsg);
+            logger.Error(errMsg, ex);
+            throw ex;
+        }
+
+        public static ResourceAllocationSettingData GetIDEControllerSettings(VirtualSystemSettingData vmSettings, string cntrllerAddr)
+        {
+            var wmiObjCollection = GetResourceAllocationSettings(vmSettings);
+
+            foreach (ResourceAllocationSettingData wmiObj in wmiObjCollection)
+            {
+                if (wmiObj.ResourceSubType == "Microsoft Emulated IDE Controller" && wmiObj.Address == cntrllerAddr)
+                {
+                    return wmiObj;
+                }
+            }
+
+            var errMsg = string.Format(
+                                "Cannot find the Microsoft Emulated IDE Controlle at address {0} in VirtualSystemSettingData {1}", 
+                                cntrllerAddr, 
+                                vmSettings.Path.Path);
+            var ex = new WmiException(errMsg);
+            logger.Error(errMsg, ex);
+            throw ex;
+        }
+
+        /// <summary>
+        /// VM resources, typically hardware a described by a generic MSVM_ResourceAllocationSettingData object.  The hardware type being 
+        /// described is identified in two ways:  in general terms using an enum in the ResourceType field, and in terms of the implementation 
+        /// using text in the ResourceSubType field.
+        /// See http://msdn.microsoft.com/en-us/library/cc136877%28v=vs.85%29.aspx
+        /// </summary>
+        /// <param name="vmSettings"></param>
+        /// <returns></returns>
+        public static ResourceAllocationSettingData.ResourceAllocationSettingDataCollection GetResourceAllocationSettings(VirtualSystemSettingData vmSettings)
+        {
+            // An ASSOCIATOR object provides the cross reference from the VirtualSystemSettingData and the 
+            // ResourceAllocationSettingData, but generated wrappers do not expose a ASSOCIATOR OF query as a method.
+            // Instead, we use the System.Management to code the equivalant of 
+            //  string query = string.Format( "ASSOCIATORS OF {{{0}}} WHERE ResultClass = {1}", vmSettings.path, resultclassName);
+            //
+            var wmiObjQuery = new RelatedObjectQuery(vmSettings.Path.Path, ResourceAllocationSettingData.CreatedClassName);
+
+            // NB: default scope of ManagementObjectSearcher is '\\.\root\cimv2', which does not contain
+            // the virtualisation objects.
+            var wmiObjectSearch = new ManagementObjectSearcher(vmSettings.Scope, wmiObjQuery);
+            var wmiObjCollection = new ResourceAllocationSettingData.ResourceAllocationSettingDataCollection(wmiObjectSearch.Get());
+
+            if (wmiObjCollection != null)
+            {
+                return wmiObjCollection;
+            }
+
+            var errMsg = string.Format("No ResourceAllocationSettingData in VirtualSystemSettingData {0}", vmSettings.Path.Path);
+            var ex = new WmiException(errMsg);
+            logger.Error(errMsg, ex);
+            throw ex;
+        }
+
+        public static SwitchPort[] GetSwitchPorts(ComputerSystem vm)
+        {
+            var virtSwitchMgmtSvc = GetVirtualSwitchManagementService();
+            // Get NIC path
+            var condition = string.Format("ElementName=\"{0}\"", vm.ElementName);
+            var switchPortCollection = SwitchPort.GetInstances(virtSwitchMgmtSvc.Scope, condition);
+
+            List<SwitchPort> result = new List<SwitchPort>(switchPortCollection.Count);
+            foreach (SwitchPort item in switchPortCollection)
+            {
+                result.Add(item);
+            }
+            return result.ToArray();
+        }
+
+
+        /// <summary>
+        /// Deprecated
+        /// </summary>
+        /// <param name="nic"></param>
+        /// <returns></returns>
+        public static SwitchPort GetSwitchPort(SyntheticEthernetPort nic)
+        {
+            // An ASSOCIATOR object provides the cross reference between WMI objects, 
+            // 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}", wmiObject.path, resultclassName);
+            //
+            var wmiObjQuery = new RelatedObjectQuery(nic.Path.Path, VmLANEndpoint.CreatedClassName);
+
+            // NB: default scope of ManagementObjectSearcher is '\\.\root\cimv2', which does not contain
+            // the virtualisation objects.
+            var wmiObjectSearch = new ManagementObjectSearcher(nic.Scope, wmiObjQuery);
+            var wmiObjCollection = new VmLANEndpoint.VmLANEndpointCollection(wmiObjectSearch.Get());
+
+            // assert
+            if (wmiObjCollection.Count < 1)
+            {
+                var errMsg = string.Format("No VmLANEndpoint for external NIC {0} on Hyper-V server", nic.Name);
+                var ex = new WmiException(errMsg);
+                logger.Error(errMsg, ex);
+                throw ex;
+            }
+
+            VmLANEndpoint vmEndPoint = wmiObjCollection.OfType<VmLANEndpoint>().First();
+            var switchPortQuery = new RelatedObjectQuery(vmEndPoint.Path.Path, SwitchPort.CreatedClassName);
+            var switchPortSearch = new ManagementObjectSearcher(nic.Scope, switchPortQuery);
+            var switchPortCollection = new SwitchPort.SwitchPortCollection(switchPortSearch.Get());
+
+            // assert
+            if (switchPortCollection.Count < 1)
+            {
+                var errMsg = string.Format("No SwitchPort for external NIC {0} on Hyper-V server", nic.Name);
+                var ex = new WmiException(errMsg);
+                logger.Error(errMsg, ex);
+                throw ex;
+            }
+
+            SwitchPort switchPort = wmiObjCollection.OfType<SwitchPort>().First();
+
+            return switchPort;
+        }
+
+        public static SyntheticEthernetPortSettingData[] GetEthernetPorts(ComputerSystem vm)
+        {
+            // An ASSOCIATOR object provides the cross reference from the ComputerSettings and the 
+            // SyntheticEthernetPortSettingData, via the VirtualSystemSettingData.
+            // However, generated wrappers do not expose a ASSOCIATOR OF query as a method.
+            // Instead, we use the System.Management to code the equivalant of 
+            //
+            // string query = string.Format( "ASSOCIATORS OF {{{0}}} WHERE ResultClass = {1}", vm.path, resultclassName);
+            //
+            VirtualSystemSettingData vmSettings = GetVmSettings(vm);
+
+            var wmiObjQuery = new RelatedObjectQuery(vmSettings.Path.Path, SyntheticEthernetPortSettingData.CreatedClassName);
+
+            // NB: default scope of ManagementObjectSearcher is '\\.\root\cimv2', which does not contain
+            // the virtualisation objects.
+            var wmiObjectSearch = new ManagementObjectSearcher(vm.Scope, wmiObjQuery);
+            var wmiObjCollection = new SyntheticEthernetPortSettingData.SyntheticEthernetPortSettingDataCollection(wmiObjectSearch.Get());
+
+            List<SyntheticEthernetPortSettingData> results = new List<SyntheticEthernetPortSettingData>(wmiObjCollection.Count);
+            foreach (SyntheticEthernetPortSettingData item in wmiObjCollection)
+            {
+                results.Add(item);
+            }
+
+            return results.ToArray();
+        }
+
+        public static VirtualSystemSettingData GetVmSettings(ComputerSystem vm)
+        {
+            // An ASSOCIATOR object provides the cross reference from the ComputerSettings and the 
+            // VirtualSystemSettingData, but generated wrappers do not expose a ASSOCIATOR OF query as a method.
+            // Instead, we use the System.Management to code the equivalant of 
+            //  string query = string.Format( "ASSOCIATORS OF {{{0}}} WHERE ResultClass = {1}", vm.path, resultclassName);
+            //
+            var wmiObjQuery = new RelatedObjectQuery(vm.Path.Path, VirtualSystemSettingData.CreatedClassName);
+
+            // NB: default scope of ManagementObjectSearcher is '\\.\root\cimv2', which does not contain
+            // the virtualisation objects.
+            var wmiObjectSearch = new ManagementObjectSearcher(vm.Scope, wmiObjQuery);
+            var wmiObjCollection = new VirtualSystemSettingData.VirtualSystemSettingDataCollection(wmiObjectSearch.Get());
+
+            // When snapshots are taken into account, there can be multiple settings objects
+            // take the first one that isn't a snapshot
+            foreach (VirtualSystemSettingData wmiObj in wmiObjCollection)
+            {
+                if (wmiObj.SettingType == 3)
+                {
+                    return wmiObj;
+                }
+            }
+
+            var errMsg = string.Format("No VirtualSystemSettingData for VM {0}, path {1}", vm.ElementName, vm.Path.Path);
+            var ex = new WmiException(errMsg);
+            logger.Error(errMsg, ex);
+            throw ex;
+        }
+    }
+
+    public class WmiException : Exception
+    {
+        public WmiException()
+        {
+        }
+
+        public WmiException(string message)
+            : base(message)
+        {
+        }
+
+        public WmiException(string message, Exception inner)
+            : base(message, inner)
+        {
+        }
+    }
+
+    /// <summary>
+    /// http://msdn.microsoft.com/en-us/library/hh850031%28v=vs.85%29.aspx
+    /// </summary>
+    public static class ReturnCode
+    {
+        public const UInt32 Completed = 0;
+        public const UInt32 Started = 4096;
+        public const UInt32 Failed = 32768;
+        public const UInt32 AccessDenied = 32769;
+        public const UInt32 NotSupported = 32770;
+        public const UInt32 Unknown = 32771;
+        public const UInt32 Timeout = 32772;
+        public const UInt32 InvalidParameter = 32773;
+        public const UInt32 SystemInUse = 32774;
+        public const UInt32 InvalidState = 32775;
+        public const UInt32 IncorrectDataType = 32776;
+        public const UInt32 SystemNotAvailable = 32777;
+        public const UInt32 OutofMemory = 32778;
+        public static string ToString(UInt32 value)
+        {
+            string result = "Unknown return code";
+            switch (value)
+            {
+                case Completed: result = "Completed"; break;
+                case Started: result = "Started"; break;
+                case Failed: result = "Failed"; break;
+                case AccessDenied: result = "AccessDenied"; break;
+                case NotSupported: result = "NotSupported"; break;
+                case Unknown: result = "Unknown"; break;
+                case Timeout: result = "Timeout"; break;
+                case InvalidParameter: result = "InvalidParameter"; break;
+                case SystemInUse: result = "SystemInUse"; break;
+                case InvalidState: result = "InvalidState"; break;
+                case IncorrectDataType: result = "IncorrectDataType"; break;
+                case SystemNotAvailable: result = "SystemNotAvailable"; break;
+                case OutofMemory: result = "OutofMemory"; break;
+            }
+            return result;
+        }
+    }
+
+    /// <summary>
+    /// http://msdn.microsoft.com/en-us/library/hh850031%28v=vs.85%29.aspx
+    /// </summary>
+    public static class JobState
+    {
+        public const UInt16 New = 2;
+        public const UInt16 Starting = 3;
+        public const UInt16 Running = 4;
+        public const UInt16 Suspended = 5;
+        public const UInt16 ShuttingDown = 6;
+        public const UInt16 Completed = 7;
+        public const UInt16 Terminated = 8;
+        public const UInt16 Killed = 9;
+        public const UInt16 Exception = 10;
+        public const UInt16 Service = 11;
+        public static string ToString(UInt16 value)
+        {
+            string result = "Unknown JobState code";
+            switch (value)
+            {
+                case New: result = "New"; break;
+                case Starting: result = "Starting"; break;
+                case Running: result = "Running"; break;
+                case Suspended: result = "Suspended"; break;
+                case ShuttingDown: result = "ShuttingDown"; break;
+                case Completed: result = "Completed"; break;
+                case Terminated: result = "Terminated"; break;
+                case Killed: result = "Killed"; break;
+                case Exception: result = "Exception"; break;
+                case Service: result = "Service"; break;
+            }
+            return result;
+        }
+    }
+
+    /// <summary>
+    /// http://msdn.microsoft.com/en-us/library/cc723874%28v=vs.85%29.aspx
+    /// </summary>
+    public class RequiredState
+    {
+        public const UInt16 Enabled = 2;        // Turns the VM on.
+        public const UInt16 Disabled = 3;       // Turns the VM off.
+        public const UInt16 Reboot = 10;        // A hard reset of the VM.
+        public const UInt16 Reset = 11;         // For future use.
+        public const UInt16 Paused = 32768;     // Pauses the VM.
+        public const UInt16 Suspended = 32769;  // Saves the state of the VM.
+        public static string ToString(UInt16 value)
+        {
+            string result = "Unknown RequiredState code";
+            switch (value)
+            {
+                case Enabled: result = "Enabled"; break;
+                case Disabled: result = "Disabled"; break;
+                case Reboot: result = "Reboot"; break;
+                case Reset: result = "Reset"; break;
+                case Paused: result = "Paused"; break;
+                case Suspended: result = "Suspended"; break;
+            }
+            return result;
+        }
+    }
+
+    /// <summary>
+    /// http://msdn.microsoft.com/en-us/library/cc136822%28v=vs.85%29.aspx
+    /// </summary>
+        public class EnabledState
+    {
+            /// <summary>
+            /// The state of the VM could not be determined.
+            /// </summary>
+        public const UInt16 Unknown = 0;
+            /// <summary>
+            /// The VM is running.
+            /// </summary>
+        public const UInt16 Enabled = 2;
+            /// <summary>
+            /// The VM is turned off.
+            /// </summary>
+        public const UInt16 Disabled = 3;
+            /// <summary>
+            /// The VM is paused.
+            /// </summary>
+        public const UInt16 Paused = 32768;
+            /// <summary>
+            /// The VM is in a saved state.
+            /// </summary>
+        public const UInt16 Suspended = 32769;
+            /// <summary>
+            /// The VM is starting. This is a transitional state between 3 (Disabled)
+            /// or 32769 (Suspended) and 2 (Enabled) initiated by a call to the 
+            /// RequestStateChange method with a RequestedState parameter of 2 (Enabled).
+            /// </summary>
+        public const UInt16 Starting = 32770;
+            /// <summary>
+            /// Starting with Windows Server 2008 R2 this value is not supported. 
+            /// If the VM is performing a snapshot operation, the element at index 1 
+            /// of the OperationalStatus property array will contain 32768 (Creating Snapshot), 
+            /// 32769 (Applying Snapshot), or 32770 (Deleting Snapshot).
+            /// </summary>
+        public const UInt16 Snapshotting = 32771;
+            /// <summary>
+            /// The VM is saving its state. This is a transitional state between 2 (Enabled)
+            /// and 32769 (Suspended) initiated by a call to the RequestStateChange method 
+            /// with a RequestedState parameter of 32769 (Suspended).
+            /// </summary>
+        public const UInt16 Saving = 32773;
+            /// <summary>
+            /// The VM is turning off. This is a transitional state between 2 (Enabled) 
+            /// and 3 (Disabled) initiated by a call to the RequestStateChange method 
+            /// with a RequestedState parameter of 3 (Disabled) or a guest operating system 
+            /// initiated power off.
+            /// </summary>
+        public const UInt16 Stopping = 32774;
+            /// <summary>
+            /// The VM is pausing. This is a transitional state between 2 (Enabled) and 32768 (Paused) initiated by a call to the RequestStateChange method with a RequestedState parameter of 32768 (Paused).
+            /// </summary>
+        public const UInt16 Pausing = 32776;
+            /// <summary>
+            /// The VM is resuming from a paused state. This is a transitional state between 32768 (Paused) and 2 (Enabled).
+            /// </summary>
+        public const UInt16 Resuming = 32777;
+
+        public static string ToString(UInt16 value)
+        {
+            string result = "Unknown";
+            switch (value)
+            {
+                case Enabled: result = "Enabled"; break;
+                case Disabled: result = "Disabled"; break;
+                case Paused: result = "Paused"; break;
+                case Suspended: result = "Suspended"; break;
+                case Starting: result = "Starting"; break;
+                case Snapshotting: result = "Snapshotting"; break; // NOT used
+                case Saving: result = "Saving"; break;
+                case Stopping: result = "Stopping"; break;
+                case Pausing: result = "Pausing"; break;
+                case Resuming: result = "Resuming"; break;
+            }
+            return result;
+        }
+
+        public static string ToCloudStackState(UInt16 value)
+        {
+            string result = "Unknown";
+            switch (value)
+            {
+                case Enabled: result = "Running"; break;
+                case Disabled: result = "Stopped"; break;
+                case Paused: result = "Unknown"; break;
+                case Suspended: result = "Unknown"; break;
+                case Starting: result = "Starting"; break;
+                case Snapshotting: result = "Unknown"; break; // NOT used
+                case Saving: result = "Saving"; break;
+                case Stopping: result = "Stopping"; break;
+                case Pausing: result = "Unknown"; break;
+                case Resuming: result = "Starting"; break; 
+            }
+            return result;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/1d0a931d/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/packages.config
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/packages.config b/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/packages.config
new file mode 100644
index 0000000..b0f2ace
--- /dev/null
+++ b/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/packages.config
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+  <package id="AWSSDK" version="1.5.23.0" targetFramework="net45" />
+  <package id="DotNetZip" version="1.9.1.8" targetFramework="net45" />
+  <package id="log4net" version="2.0.0" targetFramework="net45" />
+  <package id="Newtonsoft.Json" version="4.5.11" targetFramework="net45" />
+</packages>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/1d0a931d/plugins/hypervisors/hyperv/DotNet/ServerResource/ServerResource.Tests/App.config
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/hyperv/DotNet/ServerResource/ServerResource.Tests/App.config b/plugins/hypervisors/hyperv/DotNet/ServerResource/ServerResource.Tests/App.config
new file mode 100644
index 0000000..1bf17d4
--- /dev/null
+++ b/plugins/hypervisors/hyperv/DotNet/ServerResource/ServerResource.Tests/App.config
@@ -0,0 +1,128 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!-- 
+    Note: Add entries to the App.config file for configuration settings
+    that apply only to the Test project.
+-->
+<configuration>
+  <configSections>
+    <sectionGroup name="applicationSettings" type="System.Configuration.ApplicationSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
+      <section name="CloudStack.Plugin.AgentShell.AgentSettings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
+    </sectionGroup>
+    <sectionGroup name="userSettings" type="System.Configuration.UserSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
+      <section name="CloudStack.Plugin.AgentShell.AgentSettings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" allowExeDefinition="MachineToLocalUser" requirePermission="false" />
+    </sectionGroup>
+  </configSections>
+
+  <appSettings>
+    </appSettings>
+    <connectionStrings>
+    </connectionStrings>
+
+  <applicationSettings>
+    <CloudStack.Plugin.AgentShell.AgentSettings>
+      <setting name="cpus" serializeAs="String">
+        <value>8</value>
+      </setting>
+      <setting name="private_ip_address" serializeAs="String">
+        <value>10.1.1.1</value>
+      </setting>
+      <setting name="type" serializeAs="String">
+        <value>Routing</value>
+      </setting>
+      <setting name="local_storage_uuid" serializeAs="String">
+        <value>5fe2bad3-d785-394e-9949-89786b8a63d2</value>
+      </setting>
+      <setting name="capabilities" serializeAs="String">
+        <value>hvm</value>
+      </setting>
+      <setting name="Settingcpuspeed" serializeAs="String">
+        <value>2130</value>
+      </setting>
+      <setting name="port" serializeAs="String">
+        <value>8250</value>
+      </setting>
+      <setting name="memory" serializeAs="String">
+        <value>34359738368</value>
+      </setting>
+      <setting name="host" serializeAs="String">
+        <value>camldonall01.citrite.net</value>
+      </setting>
+      <setting name="pod" serializeAs="String">
+        <value>1</value>
+      </setting>
+      <setting name="gateway_ip_address" serializeAs="String">
+        <value>10.70.176.1</value>
+      </setting>
+      <setting name="cluster" serializeAs="String">
+        <value>2</value>
+      </setting>
+      <setting name="zone" serializeAs="String">
+        <value>1</value>
+      </setting>
+      <setting name="local_storage_path" serializeAs="String">
+        <value>E:\Disks\Disks</value>
+      </setting>
+      <setting name="workers" serializeAs="String">
+        <value>5</value>
+      </setting>
+      <setting name="private_ip_netmask" serializeAs="String">
+        <value>255.255.240.0</value>
+      </setting>
+      <setting name="RootDeviceReservedSpaceBytes" serializeAs="String">
+        <value>4294967296</value>
+      </setting>
+      <setting name="hyperv_plugin_root" serializeAs="String">
+        <value>..\..\..\..\..\</value>
+      </setting>
+      <setting name="RootDeviceName" serializeAs="String">
+        <value>e:\</value>
+      </setting>
+      <setting name="dom0MinMemory" serializeAs="String">
+        <value>2048</value>
+      </setting>
+      <setting name="private_mac_address" serializeAs="String">
+        <value>101F742C6B88</value>
+      </setting>
+    </CloudStack.Plugin.AgentShell.AgentSettings>
+  </applicationSettings>
+  <userSettings>
+    <CloudStack.Plugin.AgentShell.AgentSettings>
+      <setting name="local_secondary_storage_path" serializeAs="String">
+        <value>c:\Secondary</value>
+      </setting>
+      <setting name="local_storage_path" serializeAs="String">
+        <value>E:\Disks\Disks</value>
+      </setting>
+      <setting name="testLocalStoreUUID" serializeAs="String">
+        <value>5fe2bad3-d785-394e-9949-89786b8a63d2</value>
+      </setting>
+      <setting name="testLocalStorePath" serializeAs="String">
+        <value>.\var\test\storagepool</value>
+      </setting>
+      <setting name="testS3Bucket" serializeAs="String">
+        <value>cshv3eu</value>
+      </setting>
+      <setting name="testS3Endpoint" serializeAs="String">
+        <value>s3.amazonaws.com</value>
+      </setting>
+      <setting name="testS3AccessKey" serializeAs="String">
+        <value>testS3AccessKey</value>
+      </setting>
+      <setting name="testS3SecretKey" serializeAs="String">
+        <value>testS3SecretKey</value>
+      </setting>
+      <setting name="testS3TemplateName" serializeAs="String">
+        <value>206-2-73592258-559a-3b38-8f66-b667aab143eb</value>
+      </setting>
+      <setting name="testCifsTemplateName" serializeAs="String">
+        <value>206-2-73592258-559a-3b38-8f66-b667aab143eb</value>
+      </setting>
+      <setting name="testCifsUrl" serializeAs="String">
+        <value>cifs://10.1.1.1/secondary?user\u003dadministrator\u0026password\u003d1pass%40word1</value>
+      </setting>
+      <setting name="testCifsPath" serializeAs="String">
+        <value>template/tmpl/2/201/6dda6631-4daa-3150-a49a-d5a4b0a4c4b6.vhd</value>
+      </setting>
+    </CloudStack.Plugin.AgentShell.AgentSettings>
+  </userSettings>
+</configuration>


Mime
View raw message