mirror of
				https://github.com/apache/cloudstack.git
				synced 2025-10-26 08:42:29 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			3008 lines
		
	
	
		
			131 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			3008 lines
		
	
	
		
			131 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
| // 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";
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Defines the migration types.
 | |
|         /// </summary>
 | |
|         public enum MigrationType
 | |
|         {
 | |
|             VirtualSystem = 32768,
 | |
|             Storage = 32769,
 | |
|             Staged = 32770,
 | |
|             VirtualSystemAndStorage = 32771
 | |
|         };
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Defines migration transport types.
 | |
|         /// </summary>
 | |
|         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));
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Returns ping status of the given ip
 | |
|         /// </summary>
 | |
|         public static String PingHost(String ip)
 | |
|         {
 | |
|             return "Success";
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Returns ComputerSystem lacking any NICs and VOLUMEs
 | |
|         /// </summary>
 | |
|         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;
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Returns ComputerSystem lacking any NICs and VOLUMEs
 | |
|         /// </summary>
 | |
|         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;
 | |
|         }
 | |
| 
 | |
|         /// <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 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<SyntheticEthernetPortSettingData>().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
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Create new VM.  By default we start it.
 | |
|         /// </summary>
 | |
|         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}",
 | |
|                         vmName,
 | |
|                         EnabledState.ToString(vmWmiObj.EnabledState));
 | |
|                     logger.Info(infoMsg);
 | |
|                     return vmWmiObj;
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
|                     errMsg = string.Format("Create VM failing, because there exists a VM with name {0}, state {1}",
 | |
|                         vmName,
 | |
|                         EnabledState.ToString(vmWmiObj.EnabledState));
 | |
|                     var ex = new WmiException(errMsg);
 | |
|                     logger.Error(errMsg, ex);
 | |
|                     throw ex;
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             // Create vm carcase
 | |
|             logger.DebugFormat("Going ahead with create VM {0}, {1} vcpus, {2}MB RAM", vmName, vcpus, memSize);
 | |
|             var newVm = CreateVM(vmName, memSize, vcpus);
 | |
| 
 | |
|             // Add a SCSI controller for attaching/detaching data volumes.
 | |
|             AddScsiController(newVm);
 | |
| 
 | |
|             foreach (var diskDrive in diskDrives)
 | |
|             {
 | |
|                 string vhdFile = null;
 | |
|                 string diskName = null;
 | |
|                 string isoPath = null;
 | |
|                 VolumeObjectTO volInfo = VolumeObjectTO.ParseJson(diskDrive.data);
 | |
|                 TemplateObjectTO templateInfo = TemplateObjectTO.ParseJson(diskDrive.data);
 | |
| 
 | |
|                 if (volInfo != null)
 | |
|                 {
 | |
|                     // assert
 | |
|                     errMsg = vmName + ": volume missing primaryDataStore for disk " + diskDrive.ToString();
 | |
|                     if (volInfo.primaryDataStore == null)
 | |
|                     {
 | |
|                         logger.Error(errMsg);
 | |
|                         throw new ArgumentException(errMsg);
 | |
|                     }
 | |
|                     diskName = volInfo.name;
 | |
| 
 | |
|                     // assert
 | |
|                     errMsg = vmName + ": can't deal with DataStore type for disk " + diskDrive.ToString();
 | |
|                     if (volInfo.primaryDataStore == null)
 | |
|                     {
 | |
|                         logger.Error(errMsg);
 | |
|                         throw new ArgumentException(errMsg);
 | |
|                     }
 | |
|                     errMsg = vmName + ": Malformed PrimaryDataStore for disk " + diskDrive.ToString();
 | |
|                     if (String.IsNullOrEmpty(volInfo.primaryDataStore.Path))
 | |
|                     {
 | |
|                         logger.Error(errMsg);
 | |
|                         throw new ArgumentException(errMsg);
 | |
|                     }
 | |
|                     errMsg = vmName + ": Missing folder PrimaryDataStore for disk " + diskDrive.ToString() + ", missing path: " +  volInfo.primaryDataStore.Path;
 | |
|                     if (!Directory.Exists(volInfo.primaryDataStore.Path))
 | |
|                     {
 | |
|                         logger.Error(errMsg);
 | |
|                         throw new ArgumentException(errMsg);
 | |
|                     }
 | |
| 
 | |
|                     vhdFile = volInfo.FullFileName;
 | |
|                     if (!System.IO.File.Exists(vhdFile))
 | |
|                     {
 | |
|                         errMsg = vmName + ": non-existent volume, missing " + vhdFile + " for drive " + diskDrive.ToString();
 | |
|                         logger.Error(errMsg);
 | |
|                         throw new ArgumentException(errMsg);
 | |
|                     }
 | |
|                     logger.Debug("Going to create " + vmName + " with attached voluem " + diskName + " at " + vhdFile);
 | |
|                 }
 | |
|                 else if (templateInfo != null && templateInfo.nfsDataStoreTO != null)
 | |
|                 {
 | |
|                     NFSTO share = templateInfo.nfsDataStoreTO;
 | |
|                     // The share is mapped, now attach the iso
 | |
|                     isoPath = Utils.NormalizePath(Path.Combine(share.UncPath, templateInfo.path));
 | |
|                 }
 | |
| 
 | |
|                 string driveType = diskDrive.type;
 | |
|                 string ideCtrllr = "0";
 | |
|                 string driveResourceType = null;
 | |
|                 switch (driveType) {
 | |
|                     case "ROOT":
 | |
|                         ideCtrllr = "0";
 | |
|                         driveResourceType = HARDDISK_DRIVE;
 | |
|                         break;
 | |
|                     case "ISO":
 | |
|                         ideCtrllr = "1";
 | |
|                         driveResourceType = ISO_DRIVE;
 | |
|                         break;
 | |
|                     case "DATADISK":
 | |
|                         break;
 | |
|                     default:
 | |
|                         // TODO: double check exception type
 | |
|                         errMsg = string.Format("Unknown disk type {0} for disk {1}, vm named {2}",
 | |
|                                 string.IsNullOrEmpty(driveType) ? "NULL" : driveType,
 | |
|                                 string.IsNullOrEmpty(diskName) ? "NULL" : diskName, vmName);
 | |
|                         var ex = new WmiException(errMsg);
 | |
|                         logger.Error(errMsg, ex);
 | |
|                         throw ex;
 | |
|                 }
 | |
| 
 | |
|                 logger.DebugFormat("Create disk type {1} (Named: {0}), on vm {2} {3}", diskName, driveResourceType, vmName,
 | |
|                         string.IsNullOrEmpty(vhdFile) ? " no disk to insert" : ", inserting disk" + vhdFile);
 | |
|                 if (driveType.Equals("DATADISK"))
 | |
|                 {
 | |
|                     AttachDisk(vmName, vhdFile, (string)diskDrive.diskSeq);
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
|                     AddDiskDriveToIdeController(newVm, vhdFile, ideCtrllr, driveResourceType);
 | |
|                     if (isoPath != null)
 | |
|                     {
 | |
|                         AttachIso(vmName, isoPath);
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             int nicCount = 0;
 | |
|             int enableState = 2;
 | |
| 
 | |
|             // Add the Nics to the VM in the deviceId order.
 | |
|             foreach (var nc in nicInfo)
 | |
|             {
 | |
|                 foreach (var nic in nicInfo)
 | |
|                 {
 | |
| 
 | |
|                     int nicid = nic.deviceId;
 | |
|                     Int32 networkRateMbps = nic.networkRateMbps;
 | |
|                     string mac = nic.mac;
 | |
|                     string vlan = null;
 | |
|                     string isolationUri = nic.isolationUri;
 | |
|                     string broadcastUri = nic.broadcastUri;
 | |
|                     string nicIp = nic.ip;
 | |
|                     string nicNetmask = nic.netmask;
 | |
|                     if ( (broadcastUri != null ) || (isolationUri != null && isolationUri.StartsWith("vlan://")))
 | |
|                     {
 | |
|                         if (broadcastUri != null && broadcastUri.StartsWith("storage"))
 | |
|                         {
 | |
|                             vlan = broadcastUri.Substring("storage://".Length);
 | |
|                         }
 | |
|                         else
 | |
|                         {
 | |
|                             vlan = isolationUri.Substring("vlan://".Length);
 | |
|                         }
 | |
|                         int tmp;
 | |
|                         if (vlan.Equals("untagged", StringComparison.CurrentCultureIgnoreCase) ) {
 | |
|                             // recevied vlan is untagged, don't parse for the vlan in the isolation uri
 | |
|                             vlan = null;
 | |
|                         }
 | |
|                         else if (!int.TryParse(vlan, out tmp))
 | |
|                         {
 | |
|                             // TODO: double check exception type
 | |
|                             errMsg = string.Format("Invalid VLAN value {0} for on vm {1} for nic uuid {2}", isolationUri, vmName, nic.uuid);
 | |
|                             var ex = new WmiException(errMsg);
 | |
|                             logger.Error(errMsg, ex);
 | |
|                             throw ex;
 | |
|                         }
 | |
|                     }
 | |
| 
 | |
| 
 | |
|                     if (nicid == nicCount)
 | |
|                     {
 | |
|                         if (nicIp.Equals("0.0.0.0") && nicNetmask.Equals("255.255.255.255"))
 | |
|                         {
 | |
|                             // this is the extra nic added to VR.
 | |
|                             vlan = null;
 | |
|                             enableState = 3;
 | |
|                         }
 | |
| 
 | |
|                         // Create network adapter
 | |
|                         var newAdapter = CreateNICforVm(newVm, mac);
 | |
|                         String switchName ="";
 | |
|                         if (nic.name != null)
 | |
|                         {
 | |
|                             switchName =  nic.name;
 | |
|                         }
 | |
|                         EthernetPortAllocationSettingData portSettings = null;
 | |
|                         // connection to vswitch
 | |
|                         portSettings = AttachNicToPort(newVm, newAdapter, switchName, enableState);
 | |
|                         //reset the flag for other nics
 | |
|                         enableState = 2;
 | |
|                         // set vlan
 | |
|                         if (vlan != null)
 | |
|                         {
 | |
|                             SetPortVlan(vlan, portSettings);
 | |
|                         }
 | |
| 
 | |
|                         if (networkRateMbps > 0)
 | |
|                         {
 | |
|                             SetBandWidthLimit((ulong)networkRateMbps, portSettings);
 | |
|                         }
 | |
| 
 | |
|                         logger.DebugFormat("Created adapter {0} on port {1}, {2}",
 | |
|                             newAdapter.Path, portSettings.Path, (vlan == null ? "No VLAN" : "VLAN " + vlan));
 | |
|                      //   logger.DebugFormat("Created adapter {0} on port {1}, {2}",
 | |
|                     //       newAdapter.Path, portSettings.Path, (vlan == null ? "No VLAN" : "VLAN " + vlan));
 | |
|                     }
 | |
|                 }
 | |
|                 nicCount++;
 | |
|             }
 | |
| 
 | |
| 
 | |
|             // pass the boot args for the VM using KVP component.
 | |
|             // We need to pass the boot args to system vm's to get them configured with cloudstack configuration.
 | |
|             // Add new user data
 | |
|             var vm = GetComputerSystem(vmName);
 | |
|             if (bootArgs != null && !String.IsNullOrEmpty((string)bootArgs))
 | |
|             {
 | |
| 
 | |
|                 String bootargs = bootArgs;
 | |
|                 AddUserData(vm, bootargs);
 | |
|             }
 | |
| 
 | |
|             // call patch systemvm iso only for systemvms
 | |
|             if (vmName.StartsWith("r-") || vmName.StartsWith("s-") || vmName.StartsWith("v-"))
 | |
|             {
 | |
|                 if (systemVmIso != null && systemVmIso.Length != 0)
 | |
|                 {
 | |
|                     patchSystemVmIso(vmName, systemVmIso);
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             logger.DebugFormat("Starting VM {0}", vmName);
 | |
|             SetState(newVm, RequiredState.Enabled);
 | |
|             // Mark the VM as created by cloudstack tag
 | |
|             TagVm(newVm);
 | |
| 
 | |
|             // we need to reboot to get the hv kvp daemon get started vr gets configured.
 | |
|             if (vmName.StartsWith("r-") || vmName.StartsWith("s-") || vmName.StartsWith("v-"))
 | |
|             {
 | |
|                 System.Threading.Thread.Sleep(90000);
 | |
|             }
 | |
|             logger.InfoFormat("Started VM {0}", vmName);
 | |
|             return newVm;
 | |
|         }
 | |
| 
 | |
|         public static Boolean pingResource(String ip)
 | |
|         {
 | |
|             PingOptions pingOptions = null;
 | |
|             PingReply pingReply = null;
 | |
|             IPAddress ipAddress = null;
 | |
|             Ping pingSender = new Ping();
 | |
|             int numberOfPings = 6;
 | |
|             int pingTimeout = 1000;
 | |
|             int byteSize = 32;
 | |
|             byte[] buffer = new byte[byteSize];
 | |
|             ipAddress = IPAddress.Parse(ip);
 | |
|             pingOptions = new PingOptions();
 | |
|             for (int i = 0; i < numberOfPings; i++)
 | |
|             {
 | |
|                 pingReply = pingSender.Send(ipAddress, pingTimeout, buffer, pingOptions);
 | |
|                 if (pingReply.Status == IPStatus.Success)
 | |
|                 {
 | |
|                     System.Threading.Thread.Sleep(30000);
 | |
|                     return true;
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
|                     // wait for the second boot and then return with suces
 | |
|                     System.Threading.Thread.Sleep(30000);
 | |
|                 }
 | |
|             }
 | |
|             return false;
 | |
|         }
 | |
| 
 | |
|         private EthernetPortAllocationSettingData AttachNicToPort(ComputerSystem newVm, SyntheticEthernetPortSettingData newAdapter, String vSwitchName, int enableState)
 | |
|         {
 | |
|             // Get the virtual switch
 | |
|             VirtualEthernetSwitch vSwitch = GetExternalVirtSwitch(vSwitchName);
 | |
|             //check the 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<EthernetPortAllocationSettingData>().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);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         /// </summary>
 | |
|         /// <param name="vm"></param>
 | |
|         /// <param name="cntrllerAddr"></param>
 | |
|         /// <param name="driveResourceType">IDE_HARDDISK_DRIVE or IDE_ISO_DRIVE</param>
 | |
|         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);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Removes a disk image from a drive, but does not remove the drive itself.
 | |
|         /// </summary>
 | |
|         /// <param name="vm"></param>
 | |
|         /// <param name="diskFileName"></param>
 | |
|         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);
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Create Msvm_StorageAllocationSettingData corresponding to the ISO image, and
 | |
|         /// associate this with the VM's DVD drive.
 | |
|         /// </summary>
 | |
|         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<ResourceAllocationSettingData>().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 = "";
 | |
|             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)
 | |
|                 });
 | |
| 
 | |
|             EthernetSwitchPortVlanSettingData vlanSettings = GetVlanSettings(ethernetConnections[index]);
 | |
| 
 | |
|             if (vlanid.Equals("untagged", StringComparison.CurrentCultureIgnoreCase))
 | |
|             {
 | |
|                 // recevied vlan is untagged, don't parse for the vlan in the isolation uri
 | |
|                 vlanid = null;
 | |
|             }
 | |
| 
 | |
|             if (vlanSettings == null)
 | |
|             {
 | |
|                 // when modifying  nic to not connected don't create vlan
 | |
|                 if (enable)
 | |
|                 {
 | |
|                     if (vlanid != null)
 | |
|                     {
 | |
|                         SetPortVlan(vlanid, networkAdapter);
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 if (enable)
 | |
|                 {
 | |
|                     if (vlanid != null)
 | |
|                     {
 | |
|                         //Assign vlan configuration to nic
 | |
|                         vlanSettings.LateBoundObject["AccessVlanId"] = vlanid;
 | |
|                         vlanSettings.LateBoundObject["OperationMode"] = 1;
 | |
|                         ModifyFeatureVmResources(vmMgmtSvc, vm, new String[] {
 | |
|                             vlanSettings.LateBoundObject.GetText(TextFormat.CimDtd20)});
 | |
|                     }
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
|                     var virtSysMgmtSvc = GetVirtualisationSystemManagementService();
 | |
| 
 | |
|                     // This method will remove the vlan settings present on the Nic
 | |
|                     ManagementPath jobPath;
 | |
|                     var ret_val = virtSysMgmtSvc.RemoveFeatureSettings(new ManagementPath[] { vlanSettings.Path },
 | |
|                         out jobPath);
 | |
| 
 | |
|                     // If the Job is done asynchronously
 | |
|                     if (ret_val == ReturnCode.Started)
 | |
|                     {
 | |
|                         JobCompleted(jobPath);
 | |
|                     }
 | |
|                     else if (ret_val != ReturnCode.Completed)
 | |
|                     {
 | |
|                         var errMsg = string.Format(
 | |
|                             "Failed to remove vlan resource {0} from VM {1} (GUID {2}) due to {3}",
 | |
|                             vlanSettings.Path,
 | |
|                             vm.ElementName,
 | |
|                             vm.Name,
 | |
|                             ReturnCode.ToString(ret_val));
 | |
|                         var ex = new WmiException(errMsg);
 | |
|                         logger.Error(errMsg, ex);
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         // This is disabling the VLAN settings on the specified nic. It works Awesome.
 | |
|         public void DisableNicVlan(String mac, String vmName)
 | |
|         {
 | |
|             ComputerSystem vm = GetComputerSystem(vmName);
 | |
|             SyntheticEthernetPortSettingData[] nicSettingsViaVm = GetEthernetPortSettings(vm);
 | |
|             // Obtain controller for Hyper-V virtualisation subsystem
 | |
|             VirtualSystemManagementService vmMgmtSvc = GetVirtualisationSystemManagementService();
 | |
|             string normalisedMAC = string.Join("", (mac.Split(new char[] { ':' })));
 | |
|             int index = 0;
 | |
|             foreach (SyntheticEthernetPortSettingData item in nicSettingsViaVm)
 | |
|             {
 | |
|                 if (normalisedMAC.ToLower().Equals(item.Address.ToLower()))
 | |
|                 {
 | |
|                     break;
 | |
|                 }
 | |
|                 index++;
 | |
|             }
 | |
| 
 | |
|             //TODO: make sure the index won't 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 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)
 | |
|                 });
 | |
|             }
 | |
| 
 | |
|             // check when nic is disabled, removing vlan is required or not.
 | |
|             EthernetPortAllocationSettingData[] vmEthernetConnections = GetEthernetConnections(vm);
 | |
|             EthernetSwitchPortVlanSettingData vlanSettings = GetVlanSettings(vmEthernetConnections[pos]);
 | |
| 
 | |
|             if (vlanid.Equals("untagged", StringComparison.CurrentCultureIgnoreCase))
 | |
|             {
 | |
|                 // recevied vlan is untagged, don't parse for the vlan in the isolation uri
 | |
|                 vlanid = null;
 | |
|             }
 | |
| 
 | |
|             if (vlanSettings == null)
 | |
|             {
 | |
|                 // when modifying  nic to not connected don't 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);
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Remove all VMs and all SwitchPorts with the displayName.  VHD gets deleted elsewhere.
 | |
|         /// </summary>
 | |
|         /// <param name="displayName"></param>
 | |
|         public void DestroyVm(string displayName)
 | |
|         {
 | |
|             logger.DebugFormat("Got request to destroy vm {0}", displayName);
 | |
| 
 | |
|             var vm = GetComputerSystem(displayName);
 | |
|             if ( vm  == null )
 | |
|             {
 | |
|                 logger.DebugFormat("VM {0} already destroyed (or never existed)", displayName);
 | |
|                 return;
 | |
|             }
 | |
| 
 | |
|             //try to shutdown vm first
 | |
|             ShutdownVm(vm);
 | |
| 
 | |
|             if(GetComputerSystem(vm.ElementName).EnabledState != EnabledState.Disabled)
 | |
|             {
 | |
|                 logger.Info("Could not shutdown system cleanly, will forcefully delete the system");
 | |
|             }
 | |
| 
 | |
|             // Remove VM
 | |
|             logger.DebugFormat("Remove VM {0} (GUID {1})", vm.ElementName, vm.Name);
 | |
|             SetState(vm, RequiredState.Disabled);
 | |
| 
 | |
|             // Delete SwitchPort
 | |
|             logger.DebugFormat("Remove associated switch ports for VM {0} (GUID {1})", vm.ElementName, vm.Name);
 | |
|             DeleteSwitchPort(vm.ElementName);
 | |
| 
 | |
|             // Delete VM
 | |
|             var virtSysMgmtSvc = GetVirtualisationSystemManagementService();
 | |
|             ManagementPath jobPath;
 | |
| 
 | |
|             do
 | |
|             {
 | |
|                 logger.DebugFormat("Delete VM {0} (GUID {1})", vm.ElementName, vm.Name);
 | |
|                 var ret_val = virtSysMgmtSvc.DestroySystem(vm.Path, out jobPath);
 | |
| 
 | |
|                 if (ret_val == ReturnCode.Started)
 | |
|                 {
 | |
|                     JobCompleted(jobPath);
 | |
|                 }
 | |
|                 else if (ret_val != ReturnCode.Completed)
 | |
|                 {
 | |
|                     var errMsg = string.Format(
 | |
|                         "Failed Delete VM {0} (GUID {1}) due to {2}",
 | |
|                         vm.ElementName,
 | |
|                         vm.Name,
 | |
|                         ReturnCode.ToString(ret_val));
 | |
|                     var ex = new WmiException(errMsg);
 | |
|                     logger.Error(errMsg, ex);
 | |
|                     throw ex;
 | |
|                 }
 | |
|                 vm = GetComputerSystem(displayName);
 | |
|             }
 | |
|             while (vm != null);
 | |
|         }
 | |
| 
 | |
|         public void ShutdownVm(ComputerSystem vm)
 | |
|         {
 | |
|             ShutdownComponent sc = GetShutdownComponent(vm);
 | |
|             if (sc != null)
 | |
|             {
 | |
|                 var ret_val = sc.InitiateShutdown(true, "need to shutdown");
 | |
|                 if (ret_val != ReturnCode.Completed)
 | |
|                 {
 | |
|                     logger.Info("Shutting down of system failed, may be shutdown integration services are missing");
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
|                     // shutdown job is not returned so checking for shutdown completion by checking the current state of system.
 | |
|                     // poll every one second and timeout after 10 minutes
 | |
|                     for (int period = 0 ; period < 600 && (GetComputerSystem(vm.ElementName).EnabledState != EnabledState.Disabled); period++)
 | |
|                     {
 | |
|                         System.Threading.Thread.Sleep(1000);
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 logger.Info("Shutting down of system failed; may be shutdown integration services are missing");
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Migrates a vm to the given destination host
 | |
|         /// </summary>
 | |
|         /// <param name="desplayName"></param>
 | |
|         /// <param name="destination host"></param>
 | |
|         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;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Migrates the volume of a vm to a given destination storage
 | |
|         /// </summary>
 | |
|         /// <param name="displayName"></param>
 | |
|         /// <param name="volume"></param>
 | |
|         /// <param name="destination storage pool"></param>
 | |
|         public void MigrateVolume(string vmName, string volume, string destination)
 | |
|         {
 | |
|             ComputerSystem vm = GetComputerSystem(vmName);
 | |
|             VirtualSystemMigrationSettingData migrationSettingData = VirtualSystemMigrationSettingData.CreateInstance();
 | |
|             VirtualSystemMigrationService service = GetVirtualisationSystemMigrationService();
 | |
|             StorageAllocationSettingData[] sasd = GetStorageSettings(vm);
 | |
| 
 | |
|             string[] rasds = null;
 | |
|             if (sasd != null)
 | |
|             {
 | |
|                 rasds = new string[1];
 | |
|                 foreach (StorageAllocationSettingData item in sasd)
 | |
|                 {
 | |
|                     string vhdFileName = Path.GetFileNameWithoutExtension(item.HostResource[0]);
 | |
|                     if (!String.IsNullOrEmpty(vhdFileName) && vhdFileName.Equals(volume))
 | |
|                     {
 | |
|                         string newVhdPath = Path.Combine(destination, Path.GetFileName(item.HostResource[0]));
 | |
|                         item.LateBoundObject["HostResource"] = new string[] { newVhdPath };
 | |
|                         item.LateBoundObject["PoolId"] = "";
 | |
|                         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;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Migrates the volume of a vm to a given destination storage
 | |
|         /// </summary>
 | |
|         /// <param name="displayName"></param>
 | |
|         /// <param name="destination host"></param>
 | |
|         /// <param name="volumeToPool"> volume to me migrated to which pool</param>
 | |
|         public void MigrateVmWithVolume(string vmName, string destination, Dictionary<string, string> volumeToPool)
 | |
|         {
 | |
|             ComputerSystem vm = GetComputerSystem(vmName);
 | |
|             VirtualSystemMigrationSettingData migrationSettingData = VirtualSystemMigrationSettingData.CreateInstance();
 | |
|             VirtualSystemMigrationService service = GetVirtualisationSystemMigrationService();
 | |
|             StorageAllocationSettingData[] sasd = GetStorageSettings(vm);
 | |
| 
 | |
|             string[] rasds = null;
 | |
|             if (sasd != null)
 | |
|             {
 | |
|                 rasds = new string[sasd.Length];
 | |
|                 uint index = 0;
 | |
|                 foreach (StorageAllocationSettingData item in sasd)
 | |
|                 {
 | |
|                     string vhdFileName = Path.GetFileNameWithoutExtension(item.HostResource[0]);
 | |
|                     if (!String.IsNullOrEmpty(vhdFileName) && volumeToPool.ContainsKey(vhdFileName))
 | |
|                     {
 | |
|                         string newVhdPath = Path.Combine(volumeToPool[vhdFileName], Path.GetFileName(item.HostResource[0]));
 | |
|                         item.LateBoundObject["HostResource"] = new string[] { newVhdPath };
 | |
|                         item.LateBoundObject["PoolId"] = "";
 | |
|                     }
 | |
| 
 | |
|                     rasds[index++] = item.LateBoundObject.GetText(System.Management.TextFormat.CimDtd20);
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             IPAddress addr = IPAddress.Parse(destination);
 | |
|             IPHostEntry entry = Dns.GetHostEntry(addr);
 | |
|             string[] destinationHost = new string[] { destination };
 | |
| 
 | |
|             migrationSettingData.LateBoundObject["MigrationType"] = MigrationType.VirtualSystemAndStorage;
 | |
|             migrationSettingData.LateBoundObject["TransportType"] = TransportType.TCP;
 | |
|             migrationSettingData.LateBoundObject["DestinationIPAddressList"] = destinationHost;
 | |
|             string migrationSettings = migrationSettingData.LateBoundObject.GetText(System.Management.TextFormat.CimDtd20);
 | |
| 
 | |
|             ManagementPath jobPath;
 | |
|             var ret_val = service.MigrateVirtualSystemToHost(vm.Path, entry.HostName, migrationSettings, rasds, null, out jobPath);
 | |
|             if (ret_val == ReturnCode.Started)
 | |
|             {
 | |
|                 MigrationJobCompleted(jobPath);
 | |
|             }
 | |
|             else if (ret_val != ReturnCode.Completed)
 | |
|             {
 | |
|                 var errMsg = string.Format(
 | |
|                     "Failed migrating VM {0} and its volumes to destination {1} (GUID {2}) due to {3}",
 | |
|                     vm.ElementName,
 | |
|                     destination,
 | |
|                     vm.Name,
 | |
|                     ReturnCode.ToString(ret_val));
 | |
|                 var ex = new WmiException(errMsg);
 | |
|                 logger.Error(errMsg, ex);
 | |
|                 throw ex;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// 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
 | |
|         /// </summary>
 | |
|         /// <param name="wmiQuery"></param>
 | |
|         /// <returns></returns>
 | |
|         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<StorageAllocationSettingData>().First();
 | |
|             return new StorageAllocationSettingData((ManagementBaseObject)defaultDiskDriveSettings.LateBoundObject.Clone());
 | |
|         }
 | |
| 
 | |
|         /// < summary>
 | |
|         /// Removes a storage resource from a computer system.
 | |
|         /// </summary>
 | |
|         /// <param name="storageSettings">Path that uniquely identifies the resource.</param>
 | |
|         /// <param name="vm">VM to which the disk image will be attached.</param>
 | |
|         // 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.
 | |
|         /// </summary>
 | |
|         /// <param name="storageSettings">Path that uniquely identifies the resource.</param>
 | |
|         /// <param name="vm">VM to which the disk image will be attached.</param>
 | |
|         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
 | |
|         /// <summary>
 | |
|         /// Delete switch port by removing settings from the switch
 | |
|         /// </summary>
 | |
|         /// <param name="elementName"></param>
 | |
|         /// <returns></returns>
 | |
|         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;
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Adds storage images to coputer system (disk image, iso image).
 | |
|         /// </summary>
 | |
|         /// <param name="storageSettings">Msvm_StorageAllocationSettings with HostResource configured with image
 | |
|         /// file and Parent set to a controller associated with the ComputerSystem</param>
 | |
|         /// <param name="vm">VM to which the disk image will be attached.</param>
 | |
|         // 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<EthernetSwitchPortVlanSettingData>().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<EthernetSwitchPortBandwidthSettingData>().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;
 | |
|             }
 | |
|         }
 | |
| 
 | |
| 
 | |
|         /// <summary>
 | |
|         /// External VSwitch has an external NIC, and we assume there is only one external NIC and one external vswitch.
 | |
|         /// </summary>
 | |
|         /// <param name="vmSettings"></param>
 | |
|         /// <returns></returns>
 | |
|         /// <throw>Throws if there is no vswitch</throw>
 | |
|         /// <remarks>
 | |
|         /// 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
 | |
|         /// </remarks>
 | |
|         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<ExternalEthernetPort>()) {
 | |
|             // 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<LANEndpoint>().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<LANEndpoint>().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<EthernetSwitchPort>().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<VirtualEthernetSwitch>().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()
 | |
|         {
 | |
|             // VirtualSwitchManagementService is a singleton, most anonymous way of lookup is by asking for the set
 | |
|             // of local instances, which should be size 1.
 | |
|             var virtSwtichSvcCollection = VirtualEthernetSwitchManagementService.GetInstances();
 | |
|             foreach (VirtualEthernetSwitchManagementService item in virtSwtichSvcCollection)
 | |
|             {
 | |
|                 return item;
 | |
|             }
 | |
| 
 | |
|             var errMsg = string.Format("No Hyper-V subsystem on server");
 | |
|             var ex = new WmiException(errMsg);
 | |
|             logger.Error(errMsg, ex);
 | |
|             throw ex;
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Always produces a VHDX.
 | |
|         /// </summary>
 | |
|         /// <param name="MaxInternalSize"></param>
 | |
|         /// <param name="Path"></param>
 | |
|         public void CreateDynamicVirtualHardDisk(ulong MaxInternalSize, string Path)
 | |
|         {
 | |
|             // Produce description of the virtual disk in the format of a Msvm_VirtualHardDiskSettings object
 | |
| 
 | |
|             // Example at http://www.getcodesamples.com/src/FC025DDC/76689747, but
 | |
|             // Is there a template we can use to fill in the settings?
 | |
|             var newVirtHDSettings = VirtualHardDiskSettingData.CreateInstance();
 | |
|             newVirtHDSettings.LateBoundObject["Type"] = 3; // Dynamic
 | |
|             newVirtHDSettings.LateBoundObject["Format"] = 3; // VHDX
 | |
|             newVirtHDSettings.LateBoundObject["Path"] = Path;
 | |
|             newVirtHDSettings.LateBoundObject["MaxInternalSize"] = MaxInternalSize;
 | |
|             newVirtHDSettings.LateBoundObject["BlockSize"] = 0; // Use defaults
 | |
|             newVirtHDSettings.LateBoundObject["LogicalSectorSize"] = 0; // Use defaults
 | |
|             newVirtHDSettings.LateBoundObject["PhysicalSectorSize"] = 0; // Use defaults
 | |
| 
 | |
|             // Optional: newVirtHDSettings.CommitObject();
 | |
| 
 | |
|             // Add the new vhd object as a virtual hard disk to the vm.
 | |
|             string newVirtHDSettingsString = newVirtHDSettings.LateBoundObject.GetText(System.Management.TextFormat.CimDtd20);
 | |
| 
 | |
|             // Resource settings are changed through the management service
 | |
|             System.Management.ManagementPath jobPath;
 | |
|             var imgMgr = GetImageManagementService();
 | |
|             var ret_val = imgMgr.CreateVirtualHardDisk(newVirtHDSettingsString, out jobPath);
 | |
| 
 | |
|             // If the Job is done asynchronously
 | |
|             if (ret_val == ReturnCode.Started)
 | |
|             {
 | |
|                 StorageJobCompleted(jobPath);
 | |
|             }
 | |
|             else if (ret_val != ReturnCode.Completed)
 | |
|             {
 | |
|                 var errMsg = string.Format(
 | |
|                     "Failed to CreateVirtualHardDisk size {0}, path {1} due to {2}",
 | |
|                     MaxInternalSize,
 | |
|                     Path,
 | |
|                     ReturnCode.ToString(ret_val));
 | |
|                 var ex = new WmiException(errMsg);
 | |
|                 logger.Error(errMsg, ex);
 | |
|                 throw ex;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         public ImageManagementService GetImageManagementService()
 | |
|         {
 | |
|             // VirtualSystemManagementService is a singleton, most anonymous way of lookup is by asking for the set
 | |
|             // of local instances, which should be size 1.
 | |
| 
 | |
|             var coll = ImageManagementService.GetInstances();
 | |
|             foreach (ImageManagementService item in coll)
 | |
|             {
 | |
|                 return item;
 | |
|             }
 | |
| 
 | |
|             var errMsg = string.Format("No Hyper-V subsystem on server");
 | |
|             var ex = new WmiException(errMsg);
 | |
|             logger.Error(errMsg, ex);
 | |
|             throw ex;
 | |
|         }
 | |
| 
 | |
| 
 | |
|         public VirtualSystemManagementService GetVirtualisationSystemManagementService()
 | |
|         {
 | |
|             // VirtualSystemManagementService is a singleton, most anonymous way of lookup is by asking for the set
 | |
|             // of local instances, which should be size 1.
 | |
| 
 | |
|             var virtSysMgmtSvcCollection = VirtualSystemManagementService.GetInstances();
 | |
|             foreach (VirtualSystemManagementService item in virtSysMgmtSvcCollection)
 | |
|             {
 | |
|                 return item;
 | |
|             }
 | |
| 
 | |
|             var errMsg = string.Format("No Hyper-V subsystem on server");
 | |
|             var ex = new WmiException(errMsg);
 | |
|             logger.Error(errMsg, ex);
 | |
|             throw ex;
 | |
|         }
 | |
| 
 | |
|         public VirtualSystemMigrationService GetVirtualisationSystemMigrationService()
 | |
|         {
 | |
| 
 | |
|             var virtSysMigSvcCollection = VirtualSystemMigrationService.GetInstances();
 | |
|             foreach (VirtualSystemMigrationService item in virtSysMigSvcCollection)
 | |
|             {
 | |
|                 return item;
 | |
|             }
 | |
| 
 | |
|             var errMsg = string.Format("No Hyper-V migration service subsystem on server");
 | |
|             var ex = new WmiException(errMsg);
 | |
|             logger.Error(errMsg, ex);
 | |
|             throw ex;
 | |
|         }
 | |
| 
 | |
|         /// <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);
 | |
|         }
 | |
| 
 | |
|         private static void MigrationJobCompleted(ManagementPath jobPath)
 | |
|         {
 | |
|             MigrationJob jobObj = null;
 | |
|             for (;;)
 | |
|             {
 | |
|                 jobObj = new MigrationJob(jobPath);
 | |
|                 if (jobObj.JobState != JobState.Starting && jobObj.JobState != JobState.Running)
 | |
|                 {
 | |
|                     break;
 | |
|                 }
 | |
|                 logger.InfoFormat("In progress... {0}% completed.", jobObj.PercentComplete);
 | |
|                 System.Threading.Thread.Sleep(1000);
 | |
|             }
 | |
| 
 | |
|             if (jobObj.JobState != JobState.Completed)
 | |
|             {
 | |
|                 var errMsg = string.Format(
 | |
|                     "Hyper-V Job failed, Error Code:{0}, Description: {1}",
 | |
|                     jobObj.ErrorCode,
 | |
|                     jobObj.ErrorDescription);
 | |
|                 var ex = new WmiException(errMsg);
 | |
|                 logger.Error(errMsg, ex);
 | |
|                 throw ex;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         private static void StorageJobCompleted(ManagementPath jobPath)
 | |
|         {
 | |
|             StorageJob jobObj = null;
 | |
|             for (; ; )
 | |
|             {
 | |
|                 jobObj = new StorageJob(jobPath);
 | |
|                 if (jobObj.JobState != JobState.Starting && jobObj.JobState != JobState.Running)
 | |
|                 {
 | |
|                     break;
 | |
|                 }
 | |
|                 logger.InfoFormat("In progress... {0}% completed.", jobObj.PercentComplete);
 | |
|                 System.Threading.Thread.Sleep(1000);
 | |
|             }
 | |
| 
 | |
|             if (jobObj.JobState != JobState.Completed)
 | |
|             {
 | |
|                 var errMsg = string.Format(
 | |
|                     "Hyper-V Job failed, Error Code:{0}, Description: {1}",
 | |
|                     jobObj.ErrorCode,
 | |
|                     jobObj.ErrorDescription);
 | |
|                 var ex = new WmiException(errMsg);
 | |
|                 logger.Error(errMsg, ex);
 | |
|                 throw ex;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         public void GetProcessorResources(out uint sockets, out uint cores, out uint mhz)
 | |
|         {
 | |
|             //  Processor processors
 | |
|             cores = 0;
 | |
|             mhz = 0;
 | |
|             sockets = 0;
 | |
|             Processor.ProcessorCollection procCol = Processor.GetInstances();
 | |
|             foreach (Processor procInfo in procCol)
 | |
|             {
 | |
|                 cores += procInfo.NumberOfCores;
 | |
|                 mhz = procInfo.MaxClockSpeed;
 | |
|                 sockets++;
 | |
|            }
 | |
|         }
 | |
| 
 | |
|         public void GetProcessorUsageInfo(out double cpuUtilization)
 | |
|         {
 | |
|             PerfFormattedData_Counters_ProcessorInformation.PerfFormattedData_Counters_ProcessorInformationCollection coll =
 | |
|                             PerfFormattedData_Counters_ProcessorInformation.GetInstances("Name=\"_Total\"");
 | |
|             cpuUtilization = 100;
 | |
|             // Use the first one
 | |
|             foreach (PerfFormattedData_Counters_ProcessorInformation procInfo in coll)
 | |
|             {
 | |
|                 // Idle during a given internal
 | |
|                 // See http://library.wmifun.net/cimv2/win32_perfformatteddata_counters_processorinformation.html
 | |
|                 cpuUtilization = 100.0 - (double)procInfo.PercentIdleTime;
 | |
|             }
 | |
|         }
 | |
| 
 | |
| 
 | |
|         public void GetMemoryResources(out ulong physicalRamKBs, out ulong freeMemoryKBs)
 | |
|         {
 | |
|             OperatingSystem0 os = new OperatingSystem0();
 | |
|             physicalRamKBs = os.TotalVisibleMemorySize;
 | |
|             freeMemoryKBs = os.FreePhysicalMemory;
 | |
|         }
 | |
| 
 | |
|         public string GetDefaultVirtualDiskFolder()
 | |
|         {
 | |
|             VirtualSystemManagementServiceSettingData.VirtualSystemManagementServiceSettingDataCollection coll = VirtualSystemManagementServiceSettingData.GetInstances();
 | |
|             string defaultVirtualHardDiskPath = null;
 | |
|             foreach (VirtualSystemManagementServiceSettingData settings in coll)
 | |
|             {
 | |
|                 defaultVirtualHardDiskPath = settings.DefaultVirtualHardDiskPath;
 | |
|             }
 | |
| 
 | |
|             // assert
 | |
|             if (!System.IO.Directory.Exists(defaultVirtualHardDiskPath) ){
 | |
|                 var errMsg = string.Format(
 | |
|                     "Hyper-V DefaultVirtualHardDiskPath is invalid!");
 | |
|                 logger.Error(errMsg);
 | |
|                 return null;
 | |
|             }
 | |
| 
 | |
|             return defaultVirtualHardDiskPath;
 | |
|         }
 | |
| 
 | |
|         public ComputerSystem GetComputerSystem(string displayName)
 | |
|         {
 | |
|             var wmiQuery = String.Format("ElementName=\"{0}\"", displayName);
 | |
|             ComputerSystem.ComputerSystemCollection vmCollection = ComputerSystem.GetInstances(wmiQuery);
 | |
| 
 | |
|             // Return the first one
 | |
|             foreach (ComputerSystem vm in vmCollection)
 | |
|             {
 | |
|                 return vm;
 | |
|             }
 | |
|             return null;
 | |
|         }
 | |
| 
 | |
|         public ComputerSystem.ComputerSystemCollection GetComputerSystemCollection()
 | |
|         {
 | |
|             var wmiQuery = String.Format("ProcessId >= 0");
 | |
|             return ComputerSystem.GetInstances(wmiQuery);
 | |
|         }
 | |
| 
 | |
|         public ShutdownComponent GetShutdownComponent(ComputerSystem vm)
 | |
|         {
 | |
|             var wmiQuery = String.Format("SystemName=\"{0}\"", vm.Name);
 | |
|             ShutdownComponent.ShutdownComponentCollection vmCollection = ShutdownComponent.GetInstances(wmiQuery);
 | |
| 
 | |
|             // Return the first one
 | |
|             foreach (ShutdownComponent sc in vmCollection)
 | |
|             {
 | |
|                 return sc;
 | |
|             }
 | |
|             return null;
 | |
|         }
 | |
| 
 | |
|         public Dictionary<String, VmState> GetVmSync(String privateIpAddress)
 | |
|         {
 | |
|             List<String> vms = GetVmElementNames();
 | |
|             Dictionary<String, VmState> vmSyncStates = new Dictionary<string, VmState>();
 | |
|             String vmState;
 | |
|             foreach (String vm in vms)
 | |
|             {
 | |
|                  vmState = EnabledState.ToCloudStackState(GetComputerSystem(vm).EnabledState);
 | |
|                  vmSyncStates.Add(vm, new VmState(vmState, privateIpAddress));
 | |
|             }
 | |
|             return vmSyncStates;
 | |
|         }
 | |
| 
 | |
|         public 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 ProcessorSettingData GetProcSettings(VirtualSystemSettingData vmSettings)
 | |
|         {
 | |
|             // An ASSOCIATOR object provides the cross reference from the VirtualSystemSettingData and the
 | |
|             // ProcessorSettingData, but generated wrappers do not expose a ASSOCIATOR OF query as a method.
 | |
|             // Instead, we use the System.Management to code the equivalant of
 | |
|             //  string query = string.Format( "ASSOCIATORS OF {{{0}}} WHERE ResultClass = {1}", vmSettings.path, resultclassName);
 | |
|             //
 | |
|             var wmiObjQuery = new RelatedObjectQuery(vmSettings.Path.Path, ProcessorSettingData.CreatedClassName);
 | |
| 
 | |
|             // NB: default scope of ManagementObjectSearcher is '\\.\root\cimv2', which does not contain
 | |
|             // the virtualisation objects.
 | |
|             var wmiObjectSearch = new ManagementObjectSearcher(vmSettings.Scope, wmiObjQuery);
 | |
|             var wmiObjCollection = new ProcessorSettingData.ProcessorSettingDataCollection(wmiObjectSearch.Get());
 | |
| 
 | |
|             foreach (ProcessorSettingData wmiObj in wmiObjCollection)
 | |
|             {
 | |
|                 return wmiObj;
 | |
|             }
 | |
| 
 | |
|             var errMsg = string.Format("No ProcessorSettingData in VirtualSystemSettingData {0}", vmSettings.Path.Path);
 | |
|             var ex = new WmiException(errMsg);
 | |
|             logger.Error(errMsg, ex);
 | |
|             throw ex;
 | |
|         }
 | |
| 
 | |
|         public MemorySettingData GetMemSettings(VirtualSystemSettingData vmSettings)
 | |
|         {
 | |
|             // An ASSOCIATOR object provides the cross reference from the VirtualSystemSettingData and the
 | |
|             // MemorySettingData, but generated wrappers do not expose a ASSOCIATOR OF query as a method.
 | |
|             // Instead, we use the System.Management to code the equivalant of
 | |
|             //  string query = string.Format( "ASSOCIATORS OF {{{0}}} WHERE ResultClass = {1}", vmSettings.path, resultclassName);
 | |
|             //
 | |
|             var wmiObjQuery = new RelatedObjectQuery(vmSettings.Path.Path, MemorySettingData.CreatedClassName);
 | |
| 
 | |
|             // NB: default scope of ManagementObjectSearcher is '\\.\root\cimv2', which does not contain
 | |
|             // the virtualisation objects.
 | |
|             var wmiObjectSearch = new ManagementObjectSearcher(vmSettings.Scope, wmiObjQuery);
 | |
|             var wmiObjCollection = new MemorySettingData.MemorySettingDataCollection(wmiObjectSearch.Get());
 | |
| 
 | |
|             foreach (MemorySettingData wmiObj in wmiObjCollection)
 | |
|             {
 | |
|                 return wmiObj;
 | |
|             }
 | |
| 
 | |
|             var errMsg = string.Format("No MemorySettingData in VirtualSystemSettingData {0}", vmSettings.Path.Path);
 | |
|             var ex = new WmiException(errMsg);
 | |
|             logger.Error(errMsg, ex);
 | |
|             throw ex;
 | |
|         }
 | |
| 
 | |
| 
 | |
|         public ResourceAllocationSettingData GetDvdDriveSettings(VirtualSystemSettingData vmSettings)
 | |
|         {
 | |
|             var wmiObjCollection = GetResourceAllocationSettings(vmSettings);
 | |
| 
 | |
|             foreach (ResourceAllocationSettingData wmiObj in wmiObjCollection)
 | |
|             {
 | |
|                 // DVD drive is '16', see http://msdn.microsoft.com/en-us/library/hh850200(v=vs.85).aspx
 | |
|                 if (wmiObj.ResourceType == 16)
 | |
|                 {
 | |
|                     return wmiObj;
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             var errMsg = string.Format(
 | |
|                                 "Cannot find the Dvd drive in VirtualSystemSettingData {0}",
 | |
|                                 vmSettings.Path.Path);
 | |
|             var ex = new WmiException(errMsg);
 | |
|             logger.Error(errMsg, ex);
 | |
|             throw ex;
 | |
|         }
 | |
| 
 | |
|         public ResourceAllocationSettingData GetIDEControllerSettings(VirtualSystemSettingData vmSettings, string cntrllerAddr)
 | |
|         {
 | |
|             var wmiObjCollection = GetResourceAllocationSettings(vmSettings);
 | |
| 
 | |
|             foreach (ResourceAllocationSettingData wmiObj in wmiObjCollection)
 | |
|             {
 | |
|                 if (wmiObj.ResourceSubType == IDE_CONTROLLER && wmiObj.Address == cntrllerAddr)
 | |
|                 {
 | |
|                     return wmiObj;
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             var errMsg = string.Format(
 | |
|                                 "Cannot find the Microsoft Emulated IDE Controlle at address {0} in VirtualSystemSettingData {1}",
 | |
|                                 cntrllerAddr,
 | |
|                                 vmSettings.Path.Path);
 | |
|             var ex = new WmiException(errMsg);
 | |
|             logger.Error(errMsg, ex);
 | |
|             throw ex;
 | |
|         }
 | |
| 
 | |
|         public ResourceAllocationSettingData GetScsiControllerSettings(VirtualSystemSettingData vmSettings)
 | |
|         {
 | |
|             var wmiObjCollection = GetResourceAllocationSettings(vmSettings);
 | |
| 
 | |
|             foreach (ResourceAllocationSettingData wmiObj in wmiObjCollection)
 | |
|             {
 | |
|                 if (wmiObj.ResourceSubType == SCSI_CONTROLLER)
 | |
|                 {
 | |
|                     return wmiObj;
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             var errMsg = string.Format(
 | |
|                                 "Cannot find the Microsoft Synthetic SCSI Controller in VirtualSystemSettingData {1}",
 | |
|                                 vmSettings.Path.Path);
 | |
|             var ex = new WmiException(errMsg);
 | |
|             logger.Error(errMsg, ex);
 | |
|             throw ex;
 | |
|         }
 | |
| 
 | |
|         /// <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 ResourceAllocationSettingData.ResourceAllocationSettingDataCollection GetResourceAllocationSettings(VirtualSystemSettingData vmSettings)
 | |
|         {
 | |
|             // An ASSOCIATOR object provides the cross reference from the VirtualSystemSettingData and the
 | |
|             // ResourceAllocationSettingData, but generated wrappers do not expose a ASSOCIATOR OF query as a method.
 | |
|             // Instead, we use the System.Management to code the equivalant of
 | |
|             //  string query = string.Format( "ASSOCIATORS OF {{{0}}} WHERE ResultClass = {1}", vmSettings.path, resultclassName);
 | |
|             //
 | |
|             var wmiObjQuery = new RelatedObjectQuery(vmSettings.Path.Path, ResourceAllocationSettingData.CreatedClassName);
 | |
| 
 | |
|             // NB: default scope of ManagementObjectSearcher is '\\.\root\cimv2', which does not contain
 | |
|             // the virtualisation objects.
 | |
|             var wmiObjectSearch = new ManagementObjectSearcher(vmSettings.Scope, wmiObjQuery);
 | |
|             var wmiObjCollection = new ResourceAllocationSettingData.ResourceAllocationSettingDataCollection(wmiObjectSearch.Get());
 | |
| 
 | |
|             if (wmiObjCollection != null)
 | |
|             {
 | |
|                 return wmiObjCollection;
 | |
|             }
 | |
| 
 | |
|             var errMsg = string.Format("No ResourceAllocationSettingData in VirtualSystemSettingData {0}", vmSettings.Path.Path);
 | |
|             var ex = new WmiException(errMsg);
 | |
|             logger.Error(errMsg, ex);
 | |
|             throw ex;
 | |
|         }
 | |
| 
 | |
|         public EthernetPortAllocationSettingData[] GetEthernetConnections(ComputerSystem vm)
 | |
|         {
 | |
|             // ComputerSystem -> VirtualSystemSettingData -> EthernetPortAllocationSettingData
 | |
|             VirtualSystemSettingData vmSettings = GetVmSettings(vm);
 | |
| 
 | |
|             // An ASSOCIATOR object provides the cross reference from the VirtualSystemSettingData and the
 | |
|             // EthernetPortAllocationSettingData, but generated wrappers do not expose a ASSOCIATOR OF query as a method.
 | |
|             // Instead, we use the System.Management to code the equivalant of
 | |
|             //  string query = string.Format( "ASSOCIATORS OF {{{0}}} WHERE ResultClass = {1}", vmSettings.path, resultclassName);
 | |
|             //
 | |
|             var wmiObjQuery = new RelatedObjectQuery(vmSettings.Path.Path, EthernetPortAllocationSettingData.CreatedClassName);
 | |
| 
 | |
|             // NB: default scope of ManagementObjectSearcher is '\\.\root\cimv2', which does not contain
 | |
|             // the virtualisation objects.
 | |
|             var wmiObjectSearch = new ManagementObjectSearcher(vmSettings.Scope, wmiObjQuery);
 | |
|             var wmiObjCollection = new EthernetPortAllocationSettingData.EthernetPortAllocationSettingDataCollection(wmiObjectSearch.Get());
 | |
| 
 | |
|             var result = new List<EthernetPortAllocationSettingData>(wmiObjCollection.Count);
 | |
|             foreach (EthernetPortAllocationSettingData item in wmiObjCollection)
 | |
|             {
 | |
|                 result.Add(item);
 | |
|             }
 | |
|             return result.ToArray();
 | |
|         }
 | |
| 
 | |
|         public StorageAllocationSettingData[] GetStorageSettings(ComputerSystem vm)
 | |
|         {
 | |
|             // ComputerSystem -> VirtualSystemSettingData -> EthernetPortAllocationSettingData
 | |
|             VirtualSystemSettingData vmSettings = GetVmSettings(vm);
 | |
| 
 | |
|             var wmiObjQuery = new RelatedObjectQuery(vmSettings.Path.Path, StorageAllocationSettingData.CreatedClassName);
 | |
| 
 | |
|             // NB: default scope of ManagementObjectSearcher is '\\.\root\cimv2', which does not contain
 | |
|             // the virtualisation objects.
 | |
|             var wmiObjectSearch = new ManagementObjectSearcher(vmSettings.Scope, wmiObjQuery);
 | |
|             var wmiObjCollection = new StorageAllocationSettingData.StorageAllocationSettingDataCollection(wmiObjectSearch.Get());
 | |
| 
 | |
|             var result = new List<StorageAllocationSettingData>(wmiObjCollection.Count);
 | |
|             foreach (StorageAllocationSettingData item in wmiObjCollection)
 | |
|             {
 | |
|                 result.Add(item);
 | |
|             }
 | |
|             return result.ToArray();
 | |
|         }
 | |
| 
 | |
| 
 | |
|         public EthernetSwitchPortVlanSettingData GetVlanSettings(EthernetPortAllocationSettingData ethernetConnection)
 | |
|         {
 | |
|             // An ASSOCIATOR object provides the cross reference from the VirtualSystemSettingData and the
 | |
|             // EthernetPortAllocationSettingData, but generated wrappers do not expose a ASSOCIATOR OF query as a method.
 | |
|             // Instead, we use the System.Management to code the equivalant of
 | |
|             //  string query = string.Format( "ASSOCIATORS OF {{{0}}} WHERE ResultClass = {1}", vmSettings.path, resultclassName);
 | |
|             //
 | |
|             var wmiObjQuery = new RelatedObjectQuery(ethernetConnection.Path.Path, EthernetSwitchPortVlanSettingData.CreatedClassName);
 | |
| 
 | |
|             // NB: default scope of ManagementObjectSearcher is '\\.\root\cimv2', which does not contain
 | |
|             // the virtualisation objects.
 | |
|             var wmiObjectSearch = new ManagementObjectSearcher(ethernetConnection.Scope, wmiObjQuery);
 | |
|             var wmiObjCollection = new EthernetSwitchPortVlanSettingData.EthernetSwitchPortVlanSettingDataCollection(wmiObjectSearch.Get());
 | |
| 
 | |
|             if (wmiObjCollection.Count == 0)
 | |
|             {
 | |
|                 return null;
 | |
|             }
 | |
| 
 | |
|             // Assert
 | |
|             if (wmiObjCollection.Count > 1)
 | |
|             {
 | |
|                 var errMsg = string.Format("Internal error, morn one VLAN settings for a single ethernetConnection");
 | |
|                 var ex = new WmiException(errMsg);
 | |
|                 logger.Error(errMsg, ex);
 | |
|                 throw ex;
 | |
|             }
 | |
| 
 | |
|             return wmiObjCollection.OfType<EthernetSwitchPortVlanSettingData>().First();
 | |
|         }
 | |
| 
 | |
| 
 | |
|         public SyntheticEthernetPortSettingData[] GetEthernetPortSettings(ComputerSystem vm)
 | |
|         {
 | |
|             // An ASSOCIATOR object provides the cross reference from the ComputerSettings and the
 | |
|             // SyntheticEthernetPortSettingData, via the VirtualSystemSettingData.
 | |
|             // However, generated wrappers do not expose a ASSOCIATOR OF query as a method.
 | |
|             // Instead, we use the System.Management to code the equivalant of
 | |
|             //
 | |
|             // string query = string.Format( "ASSOCIATORS OF {{{0}}} WHERE ResultClass = {1}", vm.path, resultclassName);
 | |
|             //
 | |
|             VirtualSystemSettingData vmSettings = GetVmSettings(vm);
 | |
| 
 | |
|             var wmiObjQuery = new RelatedObjectQuery(vmSettings.Path.Path, SyntheticEthernetPortSettingData.CreatedClassName);
 | |
| 
 | |
|             // NB: default scope of ManagementObjectSearcher is '\\.\root\cimv2', which does not contain
 | |
|             // the virtualisation objects.
 | |
|             var wmiObjectSearch = new ManagementObjectSearcher(vm.Scope, wmiObjQuery);
 | |
|             var wmiObjCollection = new SyntheticEthernetPortSettingData.SyntheticEthernetPortSettingDataCollection(wmiObjectSearch.Get());
 | |
| 
 | |
|             List<SyntheticEthernetPortSettingData> results = new List<SyntheticEthernetPortSettingData>(wmiObjCollection.Count);
 | |
|             foreach (SyntheticEthernetPortSettingData item in wmiObjCollection)
 | |
|             {
 | |
|                 results.Add(item);
 | |
|             }
 | |
| 
 | |
|             return results.ToArray();
 | |
|         }
 | |
| 
 | |
|         public string GetDefaultDataRoot()
 | |
|         {
 | |
|             string defaultRootPath = null;
 | |
|             VirtualSystemManagementServiceSettingData vs_mgmt_data = VirtualSystemManagementServiceSettingData.CreateInstance();
 | |
|             defaultRootPath = vs_mgmt_data.DefaultVirtualHardDiskPath;
 | |
|             if (defaultRootPath == null) {
 | |
|                 defaultRootPath = Path.GetPathRoot(Environment.SystemDirectory)  +
 | |
|                     "\\Users\\Public\\Documents\\Hyper-V\\Virtual hard disks";
 | |
|             }
 | |
| 
 | |
|             return defaultRootPath;
 | |
|         }
 | |
| 
 | |
|         public VirtualSystemSettingData GetVmSettings(ComputerSystem vm)
 | |
|         {
 | |
|             // An ASSOCIATOR object provides the cross reference from the ComputerSettings and the
 | |
|             // VirtualSystemSettingData, but generated wrappers do not expose a ASSOCIATOR OF query as a method.
 | |
|             // Instead, we use the System.Management to code the equivalant of
 | |
|             //  string query = string.Format( "ASSOCIATORS OF {{{0}}} WHERE ResultClass = {1}", vm.path, resultclassName);
 | |
|             //
 | |
|             var wmiObjQuery = new RelatedObjectQuery(vm.Path.Path, VirtualSystemSettingData.CreatedClassName);
 | |
| 
 | |
|             // NB: default scope of ManagementObjectSearcher is '\\.\root\cimv2', which does not contain
 | |
|             // the virtualisation objects.
 | |
|             var wmiObjectSearch = new ManagementObjectSearcher(vm.Scope, wmiObjQuery);
 | |
|             var wmiObjCollection = new VirtualSystemSettingData.VirtualSystemSettingDataCollection(wmiObjectSearch.Get());
 | |
| 
 | |
|             // When snapshots are taken into account, there can be multiple settings objects
 | |
|             // take the first one that isn't a snapshot
 | |
|             foreach (VirtualSystemSettingData wmiObj in wmiObjCollection)
 | |
|             {
 | |
|                 if (wmiObj.VirtualSystemType == "Microsoft:Hyper-V:System:Realized" ||
 | |
|                     wmiObj.VirtualSystemType == "Microsoft:Hyper-V:System:Planned")
 | |
|                 {
 | |
|                     return wmiObj;
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             var errMsg = string.Format("No VirtualSystemSettingData for VM {0}, path {1}", vm.ElementName, vm.Path.Path);
 | |
|             var ex = new WmiException(errMsg);
 | |
|             logger.Error(errMsg, ex);
 | |
|             throw ex;
 | |
|         }
 | |
| 
 | |
|         public KvpExchangeComponentSettingData GetKvpSettings(VirtualSystemSettingData vmSettings)
 | |
|         {
 | |
|             // An ASSOCIATOR object provides the cross reference from the VirtualSystemSettingData and the
 | |
|             // KvpExchangeComponentSettingData, but generated wrappers do not expose a ASSOCIATOR OF query as a method.
 | |
|             // Instead, we use the System.Management to code the equivalant of
 | |
|             //  string query = string.Format( "ASSOCIATORS OF {{{0}}} WHERE ResultClass = {1}", vmSettings.path, resultclassName);
 | |
|             //
 | |
|             var wmiObjQuery = new RelatedObjectQuery(vmSettings.Path.Path, KvpExchangeComponentSettingData.CreatedClassName);
 | |
| 
 | |
|             // NB: default scope of ManagementObjectSearcher is '\\.\root\cimv2', which does not contain
 | |
|             // the virtualisation objects.
 | |
|             var wmiObjectSearch = new ManagementObjectSearcher(vmSettings.Scope, wmiObjQuery);
 | |
|             var wmiObjCollection = new KvpExchangeComponentSettingData.KvpExchangeComponentSettingDataCollection(wmiObjectSearch.Get());
 | |
| 
 | |
|             foreach (KvpExchangeComponentSettingData wmiObj in wmiObjCollection)
 | |
|             {
 | |
|                 return wmiObj;
 | |
|             }
 | |
| 
 | |
|             var errMsg = string.Format("No KvpExchangeComponentSettingData in VirtualSystemSettingData {0}", vmSettings.Path.Path);
 | |
|             var ex = new WmiException(errMsg);
 | |
|             logger.Error(errMsg, ex);
 | |
|             throw ex;
 | |
|         }
 | |
| 
 | |
|         public void GetSummaryInfo(Dictionary<string, VmStatsEntry> vmProcessorInfo, List<System.Management.ManagementPath> vmsToInspect)
 | |
|         {
 | |
|             if (vmsToInspect == null || vmsToInspect.Count == 0)
 | |
|             {
 | |
|                 return;
 | |
|             }
 | |
|             // Process info available from WMI,
 | |
|             // See http://msdn.microsoft.com/en-us/library/hh850062(v=vs.85).aspx
 | |
|             uint[] requestedInfo = new uint[] {  // TODO: correct?
 | |
|                     0, // Name
 | |
|                     1, // ElementName
 | |
|                     4, // Number of processes
 | |
|                     101 // ProcessorLoad
 | |
|                 };
 | |
| 
 | |
|             System.Management.ManagementBaseObject[] sysSummary;
 | |
|             var vmsvc = GetVirtualisationSystemManagementService();
 | |
|             System.Management.ManagementPath[] vmPaths = vmsToInspect.ToArray();
 | |
|             vmsvc.GetSummaryInformation(requestedInfo, vmPaths, out sysSummary);
 | |
| 
 | |
|             foreach (var summary in sysSummary)
 | |
|             {
 | |
| 
 | |
|                 var summaryInfo = new SummaryInformation(summary);
 | |
| 
 | |
|                 logger.Debug("VM " + summaryInfo.Name + "(elementName " + summaryInfo.ElementName + ") has " +
 | |
|                                 summaryInfo.NumberOfProcessors + " CPUs, and load of " + summaryInfo.ProcessorLoad);
 | |
|                 var vmInfo = new VmStatsEntry
 | |
|                 {
 | |
|                     cpuUtilization = summaryInfo.ProcessorLoad,
 | |
|                     numCPUs = summaryInfo.NumberOfProcessors,
 | |
|                     networkReadKBs = 1,
 | |
|                     networkWriteKBs = 1,
 | |
|                     entityType = "vm"
 | |
|                 };
 | |
|                 vmProcessorInfo.Add(summaryInfo.ElementName, vmInfo);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         public string GetVmNote(System.Management.ManagementPath sysPath)
 | |
|         {
 | |
|             uint[] requestedInfo = new uint[] { 3 };
 | |
|             System.Management.ManagementPath[] vmPaths = new System.Management.ManagementPath[] { sysPath };
 | |
|             var vmsvc = GetVirtualisationSystemManagementService();
 | |
|             System.Management.ManagementBaseObject[] sysSummary;
 | |
|             vmsvc.GetSummaryInformation(requestedInfo, vmPaths, out sysSummary);
 | |
|             foreach (var summary in sysSummary)
 | |
|             {
 | |
|                 var summaryInfo = new SummaryInformation(summary);
 | |
|                 return summaryInfo.Notes;
 | |
|             }
 | |
| 
 | |
|             return null;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     public class WmiException : Exception
 | |
|     {
 | |
|         public WmiException()
 | |
|         {
 | |
|         }
 | |
| 
 | |
|         public WmiException(string message)
 | |
|             : base(message)
 | |
|         {
 | |
|         }
 | |
| 
 | |
|         public WmiException(string message, Exception inner)
 | |
|             : base(message, inner)
 | |
|         {
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /// <summary>
 | |
|     /// Covers V2 API, see
 | |
|     /// 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>
 | |
|     /// Covers V2 API, see
 | |
|     /// 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>
 | |
|     /// V2 API (see http://msdn.microsoft.com/en-us/library/hh850279(v=vs.85).aspx)
 | |
|     /// has removed 'Paused' and 'Suspended' as compared to the
 | |
|     /// V1 API (see http://msdn.microsoft.com/en-us/library/cc723874%28v=vs.85%29.aspx)
 | |
|     /// However, Paused and Suspended appear on the VM state transition table
 | |
|     /// (see http://msdn.microsoft.com/en-us/library/hh850116(v=vs.85).aspx#methods)
 | |
|     /// </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 ShutDown = 4;
 | |
|         public const UInt16 Offline = 6;
 | |
|         //public const UInt16 Test = 7;
 | |
|         public const UInt16 Defer = 8;
 | |
|         // public const UInt16 Quiesce = 9;
 | |
|         // public const UInt16 Reboot = 10;        // A hard reset of the VM.
 | |
|         public const UInt16 Reset = 11;         // For future use.
 | |
|         public const UInt16 Paused = 9;     // Pauses the VM.
 | |
|         public const UInt16 Suspended = 32779;  // Saves the state of the VM.
 | |
| 
 | |
|         public static string ToString(UInt16 value)
 | |
|         {
 | |
|             string result = "Unknown RequiredState code";
 | |
|             switch (value)
 | |
|             {
 | |
|                 case Enabled: result = "Enabled"; break;
 | |
|                 case Disabled: result = "Disabled"; break;
 | |
|                 case ShutDown: result = "ShutDown"; break;
 | |
|                 case Offline: result = "Offline"; break;
 | |
|                 case Defer: result = "Defer"; break;
 | |
|                 case Reset: result = "Reset"; break;
 | |
|             }
 | |
|             return result;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /// <summary>
 | |
|     /// V2 API specifies the states below in its  state transition graph at
 | |
|     /// http://msdn.microsoft.com/en-us/library/hh850116(v=vs.85).aspx#methods
 | |
|     /// However, the CIM standard has additional possibilities based on the description
 | |
|     /// of EnabledState.
 | |
|     /// The previous V1 API is described by
 | |
|     /// http://msdn.microsoft.com/en-us/library/cc136822%28v=vs.85%29.aspx
 | |
|     /// </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;
 | |
|         }
 | |
| 
 | |
|         public static string ToCloudStackPowerState(UInt16 value)
 | |
|         {
 | |
|             string result = "PowerUnknown";
 | |
|             switch (value)
 | |
|             {
 | |
|                 case Enabled: result = "PowerOn"; break;
 | |
|                 case Disabled: result = "PowerOff"; break;
 | |
|                 case Paused: result = "PowerUnknown"; break;
 | |
|                 case Suspended: result = "PowerUnknown"; break;
 | |
|                 case Starting: result = "PowerOn"; break;
 | |
|                 case Snapshotting: result = "PowerUnknown"; break; // NOT used
 | |
|                 case Saving: result = "PowerOn"; break;
 | |
|                 case Stopping: result = "PowerOff"; break;
 | |
|                 case Pausing: result = "PowerUnknown"; break;
 | |
|                 case Resuming: result = "PowerOn"; break;
 | |
|             }
 | |
|             return result;
 | |
|         }
 | |
|     }
 | |
| }
 |