websitepanel/WebsitePanel/Sources/WebsitePanel.Providers.Virtualization.HyperV/HyperV.cs

2503 lines
101 KiB
C#
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Copyright (c) 2012, Outercurve Foundation.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// - Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// - Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// - Neither the name of the Outercurve Foundation nor the names of its
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
using System;
using System.Collections.Generic;
using System.Text;
using WebsitePanel.Providers.Utils;
using System.Management;
using System.Xml;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using WebsitePanel.Server.Utils;
using Vds = Microsoft.Storage.Vds;
using System.Configuration;
namespace WebsitePanel.Providers.Virtualization
{
public class HyperV : HostingServiceProviderBase, IVirtualizationServer
{
#region Constants
private const string CONFIG_USE_DISKPART_TO_CLEAR_READONLY_FLAG = "WebsitePanel.HyperV.UseDiskPartClearReadOnlyFlag";
private const string WMI_VIRTUALIZATION_NAMESPACE = @"root\virtualization";
private const string WMI_CIMV2_NAMESPACE = @"root\cimv2";
private const int SWITCH_PORTS_NUMBER = 1024;
private const string LIBRARY_INDEX_FILE_NAME = "index.xml";
private const string EXTERNAL_NETWORK_ADAPTER_NAME = "External Network Adapter";
private const string PRIVATE_NETWORK_ADAPTER_NAME = "Private Network Adapter";
private const string MANAGEMENT_NETWORK_ADAPTER_NAME = "Management Network Adapter";
private const string KVP_RAM_SUMMARY_KEY = "VM-RAM-Summary";
private const string KVP_HDD_SUMMARY_KEY = "VM-HDD-Summary";
private const Int64 Size1G = 0x40000000;
private const Int64 Size1M = 0x100000;
#endregion
#region Provider Settings
protected string ServerNameSettings
{
get { return ProviderSettings["ServerName"]; }
}
public int AutomaticStartActionSettings
{
get { return ProviderSettings.GetInt("StartAction"); }
}
public int AutomaticStartupDelaySettings
{
get { return ProviderSettings.GetInt("StartupDelay"); }
}
public int AutomaticStopActionSettings
{
get { return ProviderSettings.GetInt("StopAction"); }
}
public int AutomaticRecoveryActionSettings
{
get { return 1 /* restart */; }
}
public int CpuReserveSettings
{
get { return ProviderSettings.GetInt("CpuReserve"); }
}
public int CpuLimitSettings
{
get { return ProviderSettings.GetInt("CpuLimit"); }
}
public int CpuWeightSettings
{
get { return ProviderSettings.GetInt("CpuWeight"); }
}
#endregion
#region Fields
private Wmi _wmi = null;
private Wmi wmi
{
get
{
if (_wmi == null)
_wmi = new Wmi(ServerNameSettings, WMI_VIRTUALIZATION_NAMESPACE);
return _wmi;
}
}
#endregion
#region Constructors
public HyperV()
{
}
#endregion
#region Virtual Machines
public VirtualMachine GetVirtualMachine(string vmId)
{
ManagementObject objVm = wmi.GetWmiObject("msvm_ComputerSystem", "Name = '{0}'", vmId);
if (objVm == null)
return null;
VirtualMachine vm = CreateVirtualMachineFromWmiObject(objVm);
// load summary information
ManagementBaseObject objSummary = GetVirtualMachineSummaryInformation(vmId,
SummaryInformationRequest.Heartbeat,
SummaryInformationRequest.MemoryUsage,
SummaryInformationRequest.ProcessorLoad,
SummaryInformationRequest.CreationTime);
vm.Heartbeat = (OperationalStatus)Convert.ToInt32(objSummary["Heartbeat"]);
vm.CpuUsage = Convert.ToInt32(objSummary["ProcessorLoad"]);
vm.RamUsage = 0; // Convert.ToInt32(objSummary["MemoryUsage"]);
vm.CreatedDate = wmi.ToDateTime((string)objSummary["CreationTime"]);
// try reading RAM and HDD from WebsitePanel.VmConfig service using KVP
List<KvpExchangeDataItem> vmKvps = GetKVPItems(vmId);
foreach (KvpExchangeDataItem vmKvp in vmKvps)
{
// RAM
if (vmKvp.Name == KVP_RAM_SUMMARY_KEY)
{
string[] ram = vmKvp.Data.Split(':');
int freeRam = Int32.Parse(ram[0]);
int availRam = Int32.Parse(ram[1]);
vm.RamUsage = availRam - freeRam;
}
// HDD
if (vmKvp.Name == KVP_HDD_SUMMARY_KEY)
{
string[] disksArray = vmKvp.Data.Split(';');
vm.HddLogicalDisks = new LogicalDisk[disksArray.Length];
for(int i = 0; i < disksArray.Length; i++)
{
string[] disk = disksArray[i].Split(':');
vm.HddLogicalDisks[i] = new LogicalDisk();
vm.HddLogicalDisks[i].DriveLetter = disk[0];
vm.HddLogicalDisks[i].FreeSpace = Int32.Parse(disk[1]);
vm.HddLogicalDisks[i].Size = Int32.Parse(disk[2]);
}
}
}
return vm;
}
public VirtualMachine GetVirtualMachineEx(string vmId)
{
ManagementObject objVm = wmi.GetWmiObject("msvm_ComputerSystem", "Name = '{0}'", vmId);
if (objVm == null)
return null;
// general settings
VirtualMachine vm = CreateVirtualMachineFromWmiObject(objVm);
// CPU
ManagementObject objCpu = wmi.GetWmiObject("Msvm_ProcessorSettingData", "InstanceID Like 'Microsoft:{0}%'", vmId);
vm.CpuCores = Convert.ToInt32(objCpu["VirtualQuantity"]);
// RAM
ManagementObject objRam = wmi.GetWmiObject("Msvm_MemorySettingData", "InstanceID Like 'Microsoft:{0}%'", vmId);
vm.RamSize = Convert.ToInt32(objRam["VirtualQuantity"]);
// other settings
ManagementObject objSettings = GetVirtualMachineSettingsObject(vmId);
// BIOS (num lock)
vm.NumLockEnabled = Convert.ToBoolean(objSettings["BIOSNumLock"]);
// BIOS (boot order)
// BootOrder = 0 - Boot from floppy, 1 - Boot from CD, 2 - Boot from disk, 3 - PXE Boot
UInt16[] bootOrder = (UInt16[])objSettings["BootOrder"];
vm.BootFromCD = (bootOrder[0] == 1);
// DVD drive
ManagementObject objDvd = wmi.GetWmiObject(
"Msvm_ResourceAllocationSettingData", "ResourceSubType = 'Microsoft Synthetic DVD Drive'"
+ " and InstanceID Like 'Microsoft:{0}%'", vmId);
vm.DvdDriveInstalled = (objDvd != null);
// HDD
ManagementObject objVhd = wmi.GetWmiObject(
"Msvm_ResourceAllocationSettingData", "ResourceSubType = 'Microsoft Virtual Hard Disk'"
+ " and InstanceID like 'Microsoft:{0}%'", vmId);
if(objVhd != null)
{
vm.VirtualHardDrivePath = ((string[])objVhd["Connection"])[0];
// get VHD size
VirtualHardDiskInfo vhdInfo = GetVirtualHardDiskInfo(vm.VirtualHardDrivePath);
if (vhdInfo != null)
vm.HddSize = Convert.ToInt32(vhdInfo.MaxInternalSize / Size1G);
}
// network adapters
List<VirtualMachineNetworkAdapter> nics = new List<VirtualMachineNetworkAdapter>();
ManagementObject objVM = GetVirtualMachineObject(vmId);
// synthetic adapters
foreach (ManagementObject objNic in wmi.GetWmiObjects("Msvm_SyntheticEthernetPortSettingData", "InstanceID like 'Microsoft:{0}%'", vmId))
nics.Add(new VirtualMachineNetworkAdapter() { Name = (string)objNic["ElementName"], MacAddress = (string)objNic["Address"] });
// legacy adapters
foreach (ManagementObject objNic in wmi.GetWmiObjects("Msvm_EmulatedEthernetPortSettingData", "InstanceID like 'Microsoft:{0}%'", vmId))
nics.Add(new VirtualMachineNetworkAdapter() { Name = (string)objNic["ElementName"], MacAddress = (string)objNic["Address"] });
vm.Adapters = nics.ToArray();
return vm;
}
public List<VirtualMachine> GetVirtualMachines()
{
List<VirtualMachine> vms = new List<VirtualMachine>();
ManagementObjectCollection objVms = wmi.ExecuteWmiQuery("select * from msvm_ComputerSystem where Name <> ElementName");
foreach (ManagementObject objVm in objVms)
vms.Add(CreateVirtualMachineFromWmiObject(objVm));
return vms;
}
public byte[] GetVirtualMachineThumbnailImage(string vmId, ThumbnailSize size)
{
ManagementBaseObject objSummary = GetVirtualMachineSummaryInformation(vmId, (SummaryInformationRequest)size);
wmi.Dump(objSummary);
return GetTumbnailFromSummaryInformation(objSummary, size);
}
private byte[] GetTumbnailFromSummaryInformation(ManagementBaseObject objSummary, ThumbnailSize size)
{
int width = 80;
int height = 60;
if (size == ThumbnailSize.Medium160x120)
{
width = 160;
height = 120;
}
else if (size == ThumbnailSize.Large320x240)
{
width = 320;
height = 240;
}
byte[] imgData = (byte[])objSummary["ThumbnailImage"];
// create new bitmap
Bitmap bmp = new Bitmap(width, height);
if (imgData != null)
{
// lock bitmap
Rectangle rect = new Rectangle(0, 0, width, height);
BitmapData bmpData = bmp.LockBits(rect, ImageLockMode.WriteOnly, PixelFormat.Format16bppRgb565);
// get address of the first line
IntPtr ptr = bmpData.Scan0;
// coby thumbnail bytes into bitmap
System.Runtime.InteropServices.Marshal.Copy(imgData, 0, ptr, imgData.Length);
// unlock image
bmp.UnlockBits(bmpData);
}
else
{
// fill grey rectangle
Graphics g = Graphics.FromImage(bmp);
SolidBrush brush = new SolidBrush(Color.LightGray);
g.FillRectangle(brush, 0, 0, width, height);
}
MemoryStream stream = new MemoryStream();
bmp.Save(stream, ImageFormat.Png);
stream.Flush();
byte[] buffer = stream.ToArray();
bmp.Dispose();
stream.Dispose();
return buffer;
}
public VirtualMachine CreateVirtualMachine(VirtualMachine vm)
{
// evaluate paths
vm.RootFolderPath = FileUtils.EvaluateSystemVariables(vm.RootFolderPath);
vm.OperatingSystemTemplatePath = FileUtils.EvaluateSystemVariables(vm.OperatingSystemTemplatePath);
vm.VirtualHardDrivePath = FileUtils.EvaluateSystemVariables(vm.VirtualHardDrivePath);
string vmID = null;
// request management service
ManagementObject objVmsvc = GetVirtualSystemManagementService();
// display name
ManagementObject objGlobalSettings = wmi.GetWmiClass("msvm_VirtualSystemGlobalSettingData").CreateInstance();
objGlobalSettings["ElementName"] = vm.Name;
// VM folders
objGlobalSettings["ExternalDataRoot"] = vm.RootFolderPath;
objGlobalSettings["SnapshotDataRoot"] = vm.RootFolderPath;
wmi.Dump(objGlobalSettings);
// startup/shutdown actions
if (AutomaticStartActionSettings != 100)
{
objGlobalSettings["AutomaticStartupAction"] = AutomaticStartActionSettings;
objGlobalSettings["AutomaticStartupActionDelay"] = String.Format("000000000000{0:d2}.000000:000", AutomaticStartupDelaySettings);
}
if (AutomaticStopActionSettings != 100)
objGlobalSettings["AutomaticShutdownAction"] = AutomaticStopActionSettings;
if (AutomaticRecoveryActionSettings != 100)
objGlobalSettings["AutomaticRecoveryAction"] = AutomaticRecoveryActionSettings;
// create machine
ManagementBaseObject inParams = objVmsvc.GetMethodParameters("DefineVirtualSystem");
inParams["SystemSettingData"] = objGlobalSettings.GetText(TextFormat.CimDtd20);
inParams["ResourceSettingData"] = new string[]{};
// invoke method
ManagementBaseObject outParams = objVmsvc.InvokeMethod("DefineVirtualSystem", inParams, null);
ManagementObject objVM = wmi.GetWmiObjectByPath((string)outParams["DefinedSystem"]);
// job
JobResult job = CreateJobResultFromWmiMethodResults(outParams); ;
// read VM id
vmID = (string)objVM["Name"];
// update general settings
UpdateVirtualMachineGeneralSettings(vmID, objVM,
vm.CpuCores,
vm.RamSize,
vm.BootFromCD,
vm.NumLockEnabled);
// hard disks
// load IDE 0 controller
ManagementObject objIDE0 = wmi.GetWmiObject(
"Msvm_ResourceAllocationSettingData", "ResourceSubType = 'Microsoft Emulated IDE Controller'"
+ " and InstanceID Like 'Microsoft:{0}%' and Address = 0", vmID);
// load default hard disk drive
ManagementObject objDefaultHdd = wmi.GetWmiObject(
"Msvm_ResourceAllocationSettingData", "ResourceSubType = 'Microsoft Synthetic Disk Drive'"
+ " and InstanceID like '%Default'");
ManagementObject objHdd = (ManagementObject)objDefaultHdd.Clone();
objHdd["Parent"] = objIDE0.Path;
objHdd["Address"] = 0;
// add HDD to VM resources
ManagementObject objAddedHDD = AddVirtualMachineResources(objVM, objHdd);
// attach VHD
string fullVhdPath = vm.VirtualHardDrivePath;
ManagementObject objDefaultVHD = wmi.GetWmiObject(
"Msvm_ResourceAllocationSettingData", "ResourceSubType = 'Microsoft Virtual Hard Disk'"
+ " and InstanceID like '%Default'");
ManagementObject objVhd = (ManagementObject)objDefaultVHD.Clone();
objVhd["Parent"] = objAddedHDD.Path.Path;
objVhd["Connection"] = new string[] { fullVhdPath };
// add VHD to the system
AddVirtualMachineResources(objVM, objVhd);
// DVD drive
if (vm.DvdDriveInstalled)
{
AddVirtualMachineDvdDrive(vmID, objVM);
}
// add external adapter
if (vm.ExternalNetworkEnabled && !String.IsNullOrEmpty(vm.ExternalSwitchId))
AddNetworkAdapter(objVM, vm.ExternalSwitchId, vm.Name, vm.ExternalNicMacAddress, EXTERNAL_NETWORK_ADAPTER_NAME, vm.LegacyNetworkAdapter);
// add private adapter
if (vm.PrivateNetworkEnabled && !String.IsNullOrEmpty(vm.PrivateSwitchId))
AddNetworkAdapter(objVM, vm.PrivateSwitchId, vm.Name, vm.PrivateNicMacAddress, PRIVATE_NETWORK_ADAPTER_NAME, vm.LegacyNetworkAdapter);
// add management adapter
if (vm.ManagementNetworkEnabled && !String.IsNullOrEmpty(vm.ManagementSwitchId))
AddNetworkAdapter(objVM, vm.ManagementSwitchId, vm.Name, vm.ManagementNicMacAddress, MANAGEMENT_NETWORK_ADAPTER_NAME, vm.LegacyNetworkAdapter);
vm.VirtualMachineId = vmID;
return vm;
}
public VirtualMachine UpdateVirtualMachine(VirtualMachine vm)
{
string vmId = vm.VirtualMachineId;
// get VM object
ManagementObject objVM = GetVirtualMachineObject(vmId);
// update general settings
UpdateVirtualMachineGeneralSettings(vmId, objVM,
vm.CpuCores,
vm.RamSize,
vm.BootFromCD,
vm.NumLockEnabled);
// check DVD drive
ManagementObject objDvdDrive = wmi.GetWmiObject(
"Msvm_ResourceAllocationSettingData", "ResourceSubType = 'Microsoft Synthetic DVD Drive'"
+ " and InstanceID like 'Microsoft:{0}%' and Address = 0", vmId);
if (vm.DvdDriveInstalled && objDvdDrive == null)
AddVirtualMachineDvdDrive(vmId, objVM);
else if (!vm.DvdDriveInstalled && objDvdDrive != null)
RemoveVirtualMachineResources(objVM, objDvdDrive);
// External NIC
if (!vm.ExternalNetworkEnabled
&& !String.IsNullOrEmpty(vm.ExternalNicMacAddress))
{
// delete adapter
DeleteNetworkAdapter(objVM, vm.ExternalNicMacAddress);
// reset MAC
vm.ExternalNicMacAddress = null;
}
else if(vm.ExternalNetworkEnabled
&& !String.IsNullOrEmpty(vm.ExternalNicMacAddress))
{
// add external adapter
AddNetworkAdapter(objVM, vm.ExternalSwitchId, vm.Name, vm.ExternalNicMacAddress, EXTERNAL_NETWORK_ADAPTER_NAME, vm.LegacyNetworkAdapter);
}
// Private NIC
if (!vm.PrivateNetworkEnabled
&& !String.IsNullOrEmpty(vm.PrivateNicMacAddress))
{
// delete adapter
DeleteNetworkAdapter(objVM, vm.PrivateNicMacAddress);
// reset MAC
vm.PrivateNicMacAddress = null;
}
else if (vm.PrivateNetworkEnabled
&& !String.IsNullOrEmpty(vm.PrivateNicMacAddress))
{
// add private adapter
AddNetworkAdapter(objVM, vm.PrivateSwitchId, vm.Name, vm.PrivateNicMacAddress, PRIVATE_NETWORK_ADAPTER_NAME, vm.LegacyNetworkAdapter);
}
return vm;
}
private void UpdateVirtualMachineGeneralSettings(string vmId, ManagementObject objVM, int cpuCores, int ramMB, bool bootFromCD, bool numLockEnabled)
{
// request management service
ManagementObject objVmsvc = GetVirtualSystemManagementService();
// VM resources
List<string> vmConfig = new List<string>();
// get system settings
ManagementObject objSettings = GetVirtualMachineSettingsObject(vmId);
// BIOS (num lock)
objSettings["BIOSNumLock"] = numLockEnabled;
// BIOS (boot order)
// BootOrder = 0 - Boot from floppy, 1 - Boot from CD, 2 - Boot from disk, 3 - PXE Boot
objSettings["BootOrder"] = bootFromCD ? new int[] { 1, 2, 3, 0 } : new int[] { 2, 1, 3, 0 };
// modify machine settings
ManagementBaseObject inParams = objVmsvc.GetMethodParameters("ModifyVirtualSystem");
inParams["ComputerSystem"] = objVM;
inParams["SystemSettingData"] = objSettings.GetText(TextFormat.CimDtd20);
ManagementBaseObject outParams = objVmsvc.InvokeMethod("ModifyVirtualSystem", inParams, null);
JobResult job = CreateJobResultFromWmiMethodResults(outParams);
// setup CPU
ManagementObject objCpu = wmi.GetWmiObject("Msvm_ProcessorSettingData", "InstanceID Like 'Microsoft:{0}%'", vmId);
objCpu["VirtualQuantity"] = cpuCores;
objCpu["Limit"] = Convert.ToInt64(CpuLimitSettings * 1000);
objCpu["Reservation"] = Convert.ToInt64(CpuReserveSettings * 1000);
objCpu["Weight"] = CpuWeightSettings;
vmConfig.Add(objCpu.GetText(TextFormat.CimDtd20));
// setup RAM
ManagementObject objRam = wmi.GetWmiObject("Msvm_MemorySettingData", "InstanceID Like 'Microsoft:{0}%'", vmId);
objRam["VirtualQuantity"] = ramMB.ToString();
objRam["Reservation"] = ramMB.ToString();
objRam["Limit"] = ramMB.ToString();
vmConfig.Add(objRam.GetText(TextFormat.CimDtd20));
// modify machine resources
inParams = objVmsvc.GetMethodParameters("ModifyVirtualSystemResources");
inParams["ComputerSystem"] = objVM;
inParams["ResourceSettingData"] = vmConfig.ToArray();
outParams = objVmsvc.InvokeMethod("ModifyVirtualSystemResources", inParams, null);
job = CreateJobResultFromWmiMethodResults(outParams);
}
private void AddVirtualMachineDvdDrive(string vmId, ManagementObject objVM)
{
// load IDE 1 controller
ManagementObject objIDE1 = wmi.GetWmiObject(
"Msvm_ResourceAllocationSettingData", "ResourceSubType = 'Microsoft Emulated IDE Controller'"
+ " and InstanceID Like 'Microsoft:{0}%' and Address = 1", vmId);
// load default hard disk drive
ManagementObject objDefaultDvd = wmi.GetWmiObject(
"Msvm_ResourceAllocationSettingData", "ResourceSubType = 'Microsoft Synthetic DVD Drive'"
+ " and InstanceID like '%Default'");
ManagementObject objDvd = (ManagementObject)objDefaultDvd.Clone();
objDvd["Parent"] = objIDE1.Path;
objDvd["Address"] = 0;
// add DVD drive to VM resources
AddVirtualMachineResources(objVM, objDvd);
}
private void AddNetworkAdapter(ManagementObject objVm, string switchId, string portName, string macAddress, string adapterName, bool legacyAdapter)
{
string nicClassName = GetNetworkAdapterClassName(legacyAdapter);
string vmId = (string)objVm["Name"];
// check if already exists
ManagementObject objNic = wmi.GetWmiObject(
nicClassName, "InstanceID like 'Microsoft:{0}%' and Address = '{1}'", vmId, macAddress);
if (objNic != null)
return; // exists - exit
portName = String.Format("{0} - {1}",
portName, (adapterName == EXTERNAL_NETWORK_ADAPTER_NAME) ? "External" : "Private");
// Network service
ManagementObject objNetworkSvc = GetVirtualSwitchManagementService();
// default NIC
ManagementObject objDefaultNic = wmi.GetWmiObject(nicClassName, "InstanceID like '%Default'");
// find switch
ManagementObject objSwitch = wmi.GetWmiObject("msvm_VirtualSwitch", "Name = '{0}'", switchId);
// create switch port
ManagementBaseObject inParams = objNetworkSvc.GetMethodParameters("CreateSwitchPort");
inParams["VirtualSwitch"] = objSwitch;
inParams["Name"] = portName;
inParams["FriendlyName"] = portName;
inParams["ScopeOfResidence"] = "";
// invoke method
ManagementBaseObject outParams = objNetworkSvc.InvokeMethod("CreateSwitchPort", inParams, null);
// process output parameters
ReturnCode code = (ReturnCode)Convert.ToInt32(outParams["ReturnValue"]);
if (code == ReturnCode.OK)
{
// created port
ManagementObject objPort = wmi.GetWmiObjectByPath((string)outParams["CreatedSwitchPort"]);
// create NIC
ManagementObject objExtNic = (ManagementObject)objDefaultNic.Clone();
objExtNic["Connection"] = new string[] { objPort.Path.Path };
if (!String.IsNullOrEmpty(macAddress))
{
objExtNic["StaticMacAddress"] = true;
objExtNic["Address"] = macAddress;
}
else
{
objExtNic["StaticMacAddress"] = false;
}
objExtNic["ElementName"] = adapterName;
if(!legacyAdapter)
objExtNic["VirtualSystemIdentifiers"] = new string[] { Guid.NewGuid().ToString("B") };
// add NIC
ManagementObject objCreatedExtNic = AddVirtualMachineResources(objVm, objExtNic);
}
}
private string GetNetworkAdapterClassName(bool legacy)
{
return legacy ? "Msvm_EmulatedEthernetPortSettingData" : "Msvm_SyntheticEthernetPortSettingData";
}
private ManagementObject AddVirtualMachineResources(ManagementObject objVm, ManagementObject resource)
{
if (resource == null)
return resource;
// request management service
ManagementObject objVmsvc = GetVirtualSystemManagementService();
// add resources
string txtResource = resource.GetText(TextFormat.CimDtd20);
ManagementBaseObject inParams = objVmsvc.GetMethodParameters("AddVirtualSystemResources");
inParams["TargetSystem"] = objVm;
inParams["ResourceSettingData"] = new string[] { txtResource };
ManagementBaseObject outParams = objVmsvc.InvokeMethod("AddVirtualSystemResources", inParams, null);
JobResult result = CreateJobResultFromWmiMethodResults(outParams);
if (result.ReturnValue == ReturnCode.OK)
{
string[] wmiPaths = (string[])outParams["NewResources"];
return wmi.GetWmiObjectByPath(wmiPaths[0]);
}
else if (result.ReturnValue == ReturnCode.JobStarted)
{
if (JobCompleted(result.Job))
{
string[] wmiPaths = (string[])outParams["NewResources"];
return wmi.GetWmiObjectByPath(wmiPaths[0]);
}
else
{
throw new Exception("Cannot add virtual machine resources");
}
}
else
{
throw new Exception("Cannot add virtual machine resources: " + txtResource);
}
}
private JobResult RemoveVirtualMachineResources(ManagementObject objVm, ManagementObject resource)
{
if (resource == null)
return null;
// request management service
ManagementObject objVmsvc = GetVirtualSystemManagementService();
// remove resources
ManagementBaseObject inParams = objVmsvc.GetMethodParameters("RemoveVirtualSystemResources");
inParams["TargetSystem"] = objVm;
inParams["ResourceSettingData"] = new string[] { resource.Path.Path };
ManagementBaseObject outParams = objVmsvc.InvokeMethod("RemoveVirtualSystemResources", inParams, null);
JobResult result = CreateJobResultFromWmiMethodResults(outParams);
if (result.ReturnValue == ReturnCode.OK)
{
return result;
}
else if (result.ReturnValue == ReturnCode.JobStarted)
{
if (!JobCompleted(result.Job))
{
throw new Exception("Cannot remove virtual machine resources");
}
}
else
{
throw new Exception("Cannot remove virtual machine resources: " + resource.Path.Path);
}
return result;
}
public JobResult ChangeVirtualMachineState(string vmId, VirtualMachineRequestedState newState)
{
// target computer
ManagementObject objVm = GetVirtualMachineObject(vmId);
// get method
ManagementBaseObject inParams = objVm.GetMethodParameters("RequestStateChange");
inParams["RequestedState"] = (Int32)newState;
// invoke method
ManagementBaseObject outParams = objVm.InvokeMethod("RequestStateChange", inParams, null);
return CreateJobResultFromWmiMethodResults(outParams);
}
public ReturnCode ShutDownVirtualMachine(string vmId, bool force, string reason)
{
// load virtual machine object
ManagementObject objVm = GetVirtualMachineObject(vmId);
ManagementObject objShutdown = wmi.GetRelatedWmiObject(objVm, "msvm_ShutdownComponent");
// execute InitiateShutdown method
ManagementBaseObject inParams = objShutdown.GetMethodParameters("InitiateShutdown");
inParams["Force"] = force;
inParams["Reason"] = reason;
// invoke method
ManagementBaseObject outParams = objShutdown.InvokeMethod("InitiateShutdown", inParams, null);
return (ReturnCode)Convert.ToInt32(outParams["ReturnValue"]);
}
public List<ConcreteJob> GetVirtualMachineJobs(string vmId)
{
List<ConcreteJob> jobs = new List<ConcreteJob>();
ManagementBaseObject objSummary = GetVirtualMachineSummaryInformation(
vmId, SummaryInformationRequest.AsynchronousTasks);
ManagementBaseObject[] objJobs = (ManagementBaseObject[])objSummary["AsynchronousTasks"];
if (objJobs != null)
{
foreach (ManagementBaseObject objJob in objJobs)
jobs.Add(CreateJobFromWmiObject(objJob));
}
return jobs;
}
public JobResult RenameVirtualMachine(string vmId, string name)
{
// load virtual machine
ManagementObject objVm = GetVirtualMachineObject(vmId);
// load machine settings
ManagementObject objVmSettings = GetVirtualMachineSettingsObject(vmId);
// rename machine
objVmSettings["ElementName"] = name;
// save
ManagementObject objVmsvc = GetVirtualSystemManagementService();
ManagementBaseObject inParams = objVmsvc.GetMethodParameters("ModifyVirtualSystem");
inParams["ComputerSystem"] = objVm.Path.Path;
inParams["SystemSettingData"] = objVmSettings.GetText(TextFormat.CimDtd20);
ManagementBaseObject outParams = objVmsvc.InvokeMethod("ModifyVirtualSystem", inParams, null);
return CreateJobResultFromWmiMethodResults(outParams);
}
public JobResult DeleteVirtualMachine(string vmId)
{
// load virtual machine object
ManagementObject objVm = GetVirtualMachineObject(vmId);
// check state
VirtualMachine vm = GetVirtualMachine(vmId);
// The virtual computer system must be in the powered off or saved state prior to calling this method.
if (vm.State == VirtualMachineState.Saved
|| vm.State == VirtualMachineState.Off)
{
// delete network adapters and ports
DeleteNetworkAdapters(objVm);
// destroy machine
ManagementObject objVmsvc = GetVirtualSystemManagementService();
// get method
ManagementBaseObject inParams = objVmsvc.GetMethodParameters("DestroyVirtualSystem");
inParams["ComputerSystem"] = objVm;
// invoke method
ManagementBaseObject outParams = objVmsvc.InvokeMethod("DestroyVirtualSystem", inParams, null);
return CreateJobResultFromWmiMethodResults(outParams);
}
else
{
throw new Exception("The virtual computer system must be in the powered off or saved state prior to calling Destroy method.");
}
}
private void DeleteNetworkAdapters(ManagementObject objVM)
{
string vmId = (string)objVM["Name"];
// delete synthetic adapters
foreach (ManagementObject objNic in wmi.GetWmiObjects("Msvm_SyntheticEthernetPortSettingData", "InstanceID like 'Microsoft:{0}%'", vmId))
DeleteNetworkAdapter(objVM, objNic);
// delete legacy adapters
foreach (ManagementObject objNic in wmi.GetWmiObjects("Msvm_EmulatedEthernetPortSettingData", "InstanceID like 'Microsoft:{0}%'", vmId))
DeleteNetworkAdapter(objVM, objNic);
}
private void DeleteNetworkAdapter(ManagementObject objVM, string macAddress)
{
// locate network adapter
ManagementObject objNic = wmi.GetWmiObject("CIM_ResourceAllocationSettingData", "Address = '{0}'", macAddress);
// delete adapter
DeleteNetworkAdapter(objVM, objNic);
}
private void DeleteNetworkAdapter(ManagementObject objVM, ManagementObject objNic)
{
if (objNic == null)
return;
// delete corresponding switch port
string[] conn = (string[])objNic["Connection"];
if (conn != null && conn.Length > 0)
DeleteSwitchPort(conn[0]);
// delete adapter
RemoveVirtualMachineResources(objVM, objNic);
}
private void DeleteSwitchPort(string portPath)
{
// Network service
ManagementObject objNetworkSvc = GetVirtualSwitchManagementService();
// create switch port
ManagementBaseObject inParams = objNetworkSvc.GetMethodParameters("DeleteSwitchPort");
inParams["SwitchPort"] = portPath;
// invoke method
objNetworkSvc.InvokeMethod("DeleteSwitchPort", inParams, null);
}
public JobResult ExportVirtualMachine(string vmId, string exportPath)
{
// load virtual machine object
ManagementObject objVm = GetVirtualMachineObject(vmId);
// check state
VirtualMachine vm = GetVirtualMachine(vmId);
// The virtual computer system must be in the powered off or saved state prior to calling this method.
if (vm.State == VirtualMachineState.Off)
{
// export machine
ManagementObject objVmsvc = GetVirtualSystemManagementService();
// get method
ManagementBaseObject inParams = objVmsvc.GetMethodParameters("ExportVirtualSystem");
inParams["ComputerSystem"] = objVm;
inParams["CopyVmState"] = true;
inParams["ExportDirectory"] = FileUtils.EvaluateSystemVariables(exportPath);
// invoke method
ManagementBaseObject outParams = objVmsvc.InvokeMethod("ExportVirtualSystem", inParams, null);
return CreateJobResultFromWmiMethodResults(outParams);
}
else
{
throw new Exception("The virtual computer system must be in the powered off or saved state prior to calling Export method.");
}
}
#endregion
#region Snapshots
public List<VirtualMachineSnapshot> GetVirtualMachineSnapshots(string vmId)
{
// get all VM setting objects
ManagementObject objVmSettings = GetVirtualMachineSettingsObject(vmId);
VirtualMachineSnapshot runningSnapshot = CreateSnapshotFromWmiObject(objVmSettings);
// load snapshots
ManagementBaseObject objSummary = GetVirtualMachineSummaryInformation(vmId, SummaryInformationRequest.Snapshots);
ManagementBaseObject[] objSnapshots = (ManagementBaseObject[])objSummary["Snapshots"];
List<VirtualMachineSnapshot> snapshots = new List<VirtualMachineSnapshot>();
if (objSnapshots != null)
{
foreach (ManagementBaseObject objSnapshot in objSnapshots)
{
VirtualMachineSnapshot snapshot = CreateSnapshotFromWmiObject(objSnapshot);
snapshot.IsCurrent = (runningSnapshot.ParentId == snapshot.Id);
snapshots.Add(snapshot);
}
}
return snapshots;
}
public VirtualMachineSnapshot GetSnapshot(string snapshotId)
{
// load snapshot
ManagementObject objSnapshot = GetSnapshotObject(snapshotId);
return CreateSnapshotFromWmiObject(objSnapshot);
}
public JobResult CreateSnapshot(string vmId)
{
// get VM management service
ManagementObject objVmsvc = GetVirtualSystemManagementService();
// load virtual machine
ManagementObject objVm = GetVirtualMachineObject(vmId);
// get method params
ManagementBaseObject inParams = objVmsvc.GetMethodParameters("CreateVirtualSystemSnapshot");
inParams["SourceSystem"] = objVm;
// invoke method
ManagementBaseObject outParams = objVmsvc.InvokeMethod("CreateVirtualSystemSnapshot", inParams, null);
return CreateJobResultFromWmiMethodResults(outParams);
}
public JobResult RenameSnapshot(string vmId, string snapshotId, string name)
{
// load virtual machine
ManagementObject objVm = GetVirtualMachineObject(vmId);
// load snapshot
ManagementObject objSnapshot = GetSnapshotObject(snapshotId);
// rename snapshot
objSnapshot["ElementName"] = name;
// save
ManagementObject objVmsvc = GetVirtualSystemManagementService();
ManagementBaseObject inParams = objVmsvc.GetMethodParameters("ModifyVirtualSystem");
inParams["ComputerSystem"] = objVm.Path.Path;
inParams["SystemSettingData"] = objSnapshot.GetText(TextFormat.CimDtd20);
ManagementBaseObject outParams = objVmsvc.InvokeMethod("ModifyVirtualSystem", inParams, null);
return CreateJobResultFromWmiMethodResults(outParams);
}
public JobResult ApplySnapshot(string vmId, string snapshotId)
{
// get VM management service
ManagementObject objVmsvc = GetVirtualSystemManagementService();
// load virtual machine
ManagementObject objVm = GetVirtualMachineObject(vmId);
// load snapshot
ManagementObject objSnapshot = GetSnapshotObject(snapshotId);
ManagementObjectCollection objRelated = objVm.GetRelated("Msvm_SettingsDefineState");
// get method params
ManagementBaseObject inParams = objVmsvc.GetMethodParameters("ApplyVirtualSystemSnapshot");
inParams["ComputerSystem"] = objVm.Path.Path;
inParams["SnapshotSettingData"] = objSnapshot.Path.Path;
// invoke method
ManagementBaseObject outParams = objVmsvc.InvokeMethod("ApplyVirtualSystemSnapshot", inParams, null);
return CreateJobResultFromWmiMethodResults(outParams);
}
public JobResult DeleteSnapshot(string snapshotId)
{
// get VM management service
ManagementObject objVmsvc = GetVirtualSystemManagementService();
// load snapshot object
ManagementObject objSnapshot = GetSnapshotObject(snapshotId);
// get method params
ManagementBaseObject inParams = objVmsvc.GetMethodParameters("RemoveVirtualSystemSnapshot");
inParams["SnapshotSettingData"] = objSnapshot.Path.Path;
// invoke method
ManagementBaseObject outParams = objVmsvc.InvokeMethod("RemoveVirtualSystemSnapshot", inParams, null);
return CreateJobResultFromWmiMethodResults(outParams);
}
public JobResult DeleteSnapshotSubtree(string snapshotId)
{
// get VM management service
ManagementObject objVmsvc = GetVirtualSystemManagementService();
// load snapshot object
ManagementObject objSnapshot = GetSnapshotObject(snapshotId);
// get method params
ManagementBaseObject inParams = objVmsvc.GetMethodParameters("RemoveVirtualSystemSnapshotTree");
inParams["SnapshotSettingData"] = objSnapshot.Path.Path;
// invoke method
ManagementBaseObject outParams = objVmsvc.InvokeMethod("RemoveVirtualSystemSnapshotTree", inParams, null);
return CreateJobResultFromWmiMethodResults(outParams);
}
public byte[] GetSnapshotThumbnailImage(string snapshotId, ThumbnailSize size)
{
ManagementBaseObject objSummary = GetSnapshotSummaryInformation(snapshotId, (SummaryInformationRequest)size);
return GetTumbnailFromSummaryInformation(objSummary, size);
}
#endregion
#region DVD operations
public string GetInsertedDVD(string vmId)
{
// find CD/DVD disk
ManagementObject objDvd = wmi.GetWmiObject(
"Msvm_ResourceAllocationSettingData", "ResourceSubType = 'Microsoft Virtual CD/DVD Disk'"
+ " and InstanceID Like 'Microsoft:{0}%'", vmId);
if(objDvd == null)
return null;
string[] path = (string[])objDvd["Connection"];
if (path != null && path.Length > 0)
return path[0];
return null;
}
public JobResult InsertDVD(string vmId, string isoPath)
{
isoPath = FileUtils.EvaluateSystemVariables(isoPath);
// find DVD drive
ManagementObject objDvdDrive = wmi.GetWmiObject(
"Msvm_ResourceAllocationSettingData", "ResourceSubType = 'Microsoft Synthetic DVD Drive'"
+ " and InstanceID Like 'Microsoft:{0}%'", vmId);
// create CD/DVD disk
ManagementObject objDefaultDVD = wmi.GetWmiObject(
"Msvm_ResourceAllocationSettingData", "ResourceSubType = 'Microsoft Virtual CD/DVD Disk'"
+ " and InstanceID like '%Default'");
ManagementObject objDvd = (ManagementObject)objDefaultDVD.Clone();
objDvd["Parent"] = objDvdDrive.Path;
objDvd["Connection"] = new string[] { isoPath };
// get VM service
ManagementObject objVmsvc = GetVirtualSystemManagementService();
// get method
ManagementBaseObject inParams = objVmsvc.GetMethodParameters("AddVirtualSystemResources");
inParams["TargetSystem"] = GetVirtualMachineObject(vmId);
inParams["ResourceSettingData"] = new string[] { objDvd.GetText(TextFormat.CimDtd20) };
// execute method
ManagementBaseObject outParams = objVmsvc.InvokeMethod("AddVirtualSystemResources", inParams, null);
return CreateJobResultFromWmiMethodResults(outParams);
}
public JobResult EjectDVD(string vmId)
{
// find CD/DVD disk
ManagementObject objDvd = wmi.GetWmiObject(
"Msvm_ResourceAllocationSettingData", "ResourceSubType = 'Microsoft Virtual CD/DVD Disk'"
+ " and InstanceID Like 'Microsoft:{0}%'", vmId);
// get VM service
ManagementObject objVmsvc = GetVirtualSystemManagementService();
// get method
ManagementBaseObject inParams = objVmsvc.GetMethodParameters("RemoveVirtualSystemResources");
inParams["TargetSystem"] = GetVirtualMachineObject(vmId);
inParams["ResourceSettingData"] = new object[] { objDvd.Path.Path };
// execute method
ManagementBaseObject outParams = objVmsvc.InvokeMethod("RemoveVirtualSystemResources", inParams, null);
return CreateJobResultFromWmiMethodResults(outParams);
}
#endregion
#region Virtual Switches
public List<VirtualSwitch> GetSwitches()
{
List<VirtualSwitch> switches = new List<VirtualSwitch>();
// load wmi objects
ManagementObjectCollection objSwitches = wmi.GetWmiObjects("msvm_VirtualSwitch");
foreach (ManagementObject objSwitch in objSwitches)
switches.Add(CreateSwitchFromWmiObject(objSwitch));
return switches;
}
public List<VirtualSwitch> GetExternalSwitches(string computerName)
{
Wmi cwmi = new Wmi(computerName, WMI_VIRTUALIZATION_NAMESPACE);
Dictionary<string, string> switches = new Dictionary<string, string>();
List<VirtualSwitch> list = new List<VirtualSwitch>();
// load external adapters
Dictionary<string, string> adapters = new Dictionary<string, string>();
ManagementObjectCollection objAdapters = cwmi.GetWmiObjects("Msvm_ExternalEthernetPort");
foreach (ManagementObject objAdapter in objAdapters)
adapters.Add((string)objAdapter["DeviceID"], "1");
// get active connections
ManagementObjectCollection objConnections = cwmi.GetWmiObjects("Msvm_ActiveConnection");
foreach (ManagementObject objConnection in objConnections)
{
// check LAN andpoint
ManagementObject objLanEndpoint = new ManagementObject(new ManagementPath((string)objConnection["Dependent"]));
string endpointName = (string)objLanEndpoint["Name"];
if (!endpointName.StartsWith("/DEVICE/"))
continue;
endpointName = endpointName.Substring(8);
if (adapters.ContainsKey(endpointName))
{
// get switch port
ManagementObject objPort = new ManagementObject(new ManagementPath((string)objConnection["Antecedent"]));
string switchId = (string)objPort["SystemName"];
if (switches.ContainsKey(switchId))
continue;
// add info about switch
ManagementObject objSwitch = cwmi.GetRelatedWmiObject(objPort, "Msvm_VirtualSwitch");
switches.Add(switchId, (string)objSwitch["ElementName"]);
}
}
foreach (string switchId in switches.Keys)
{
VirtualSwitch sw = new VirtualSwitch();
sw.SwitchId = switchId;
sw.Name = switches[switchId];
list.Add(sw);
}
return list;
}
public bool SwitchExists(string switchId)
{
ManagementObject objSwitch = wmi.GetWmiObject("msvm_VirtualSwitch", "Name = '{0}'", switchId);
return (objSwitch != null);
}
public VirtualSwitch CreateSwitch(string name)
{
// generate ID for new virtual switch
string id = Guid.NewGuid().ToString();
// get switch management object
ManagementObject objNetworkSvc = GetVirtualSwitchManagementService();
ManagementBaseObject inParams = objNetworkSvc.GetMethodParameters("CreateSwitch");
inParams["Name"] = id;
inParams["FriendlyName"] = name;
inParams["NumLearnableAddresses"] = SWITCH_PORTS_NUMBER;
// invoke method
ManagementBaseObject outParams = objNetworkSvc.InvokeMethod("CreateSwitch", inParams, null);
// process output parameters
ManagementObject objSwitch = wmi.GetWmiObjectByPath((string)outParams["CreatedVirtualSwitch"]);
return CreateSwitchFromWmiObject(objSwitch);
}
public ReturnCode DeleteSwitch(string switchId)
{
// find requested switch
ManagementObject objSwitch = wmi.GetWmiObject("msvm_VirtualSwitch", "Name = '{0}'", switchId);
if (objSwitch == null)
throw new Exception("Virtual switch with the specified ID was not found.");
// get switch management object
ManagementObject objNetworkSvc = GetVirtualSwitchManagementService();
// get method params
ManagementBaseObject inParams = objNetworkSvc.GetMethodParameters("DeleteSwitch");
inParams["VirtualSwitch"] = objSwitch.Path.Path;
ManagementBaseObject outParams = (ManagementBaseObject)objNetworkSvc.InvokeMethod("DeleteSwitch", inParams, null);
return (ReturnCode)Convert.ToInt32(outParams["ReturnValue"]);
}
#endregion
#region Library
public LibraryItem[] GetLibraryItems(string path)
{
path = Path.Combine(FileUtils.EvaluateSystemVariables(path), LIBRARY_INDEX_FILE_NAME);
// convert to UNC if it is a remote computer
path = ConvertToUNC(path);
if (!File.Exists(path))
{
Log.WriteWarning("The folder does not contain 'index.xml' file: {0}", path);
return null;
}
// create list
List<LibraryItem> items = new List<LibraryItem>();
// load xml
XmlDocument xml = new XmlDocument();
xml.Load(path);
XmlNodeList nodeItems = xml.SelectNodes("/items/item");
if(nodeItems.Count == 0)
Log.WriteWarning("index.xml found, but contains 0 items: {0}", path);
foreach (XmlNode nodeItem in nodeItems)
{
LibraryItem item = new LibraryItem();
item.Path = nodeItem.Attributes["path"].Value;
// optional attributes
if (nodeItem.Attributes["diskSize"] != null)
item.DiskSize = Int32.Parse(nodeItem.Attributes["diskSize"].Value);
if (nodeItem.Attributes["legacyNetworkAdapter"] != null)
item.LegacyNetworkAdapter = Boolean.Parse(nodeItem.Attributes["legacyNetworkAdapter"].Value);
item.ProcessVolume = 0; // process (extend and sysprep) 1st volume by default
if (nodeItem.Attributes["processVolume"] != null)
item.ProcessVolume = Int32.Parse(nodeItem.Attributes["processVolume"].Value);
if (nodeItem.Attributes["remoteDesktop"] != null)
item.RemoteDesktop = Boolean.Parse(nodeItem.Attributes["remoteDesktop"].Value);
// inner nodes
item.Name = nodeItem.SelectSingleNode("name").InnerText;
item.Description = nodeItem.SelectSingleNode("description").InnerText;
// sysprep files
XmlNodeList nodesSyspep = nodeItem.SelectNodes("provisioning/sysprep");
List<string> sysprepFiles = new List<string>();
foreach (XmlNode nodeSyspep in nodesSyspep)
{
if (nodeSyspep.Attributes["file"] != null)
sysprepFiles.Add(nodeSyspep.Attributes["file"].Value);
}
item.SysprepFiles = sysprepFiles.ToArray();
// vmconfig
XmlNode nodeVmConfig = nodeItem.SelectSingleNode("provisioning/vmconfig");
if (nodeVmConfig != null)
{
if (nodeVmConfig.Attributes["computerName"] != null)
item.ProvisionComputerName = Boolean.Parse(nodeVmConfig.Attributes["computerName"].Value);
if (nodeVmConfig.Attributes["administratorPassword"] != null)
item.ProvisionAdministratorPassword = Boolean.Parse(nodeVmConfig.Attributes["administratorPassword"].Value);
if (nodeVmConfig.Attributes["networkAdapters"] != null)
item.ProvisionNetworkAdapters = Boolean.Parse(nodeVmConfig.Attributes["networkAdapters"].Value);
}
items.Add(item);
}
return items.ToArray();
}
private string ConvertToUNC(string path)
{
if (String.IsNullOrEmpty(ServerNameSettings)
|| path.StartsWith(@"\\"))
return path;
return String.Format(@"\\{0}\{1}", ServerNameSettings, path.Replace(":", "$"));
}
#endregion
#region KVP
public List<KvpExchangeDataItem> GetKVPItems(string vmId)
{
return GetKVPItems(vmId, "GuestExchangeItems");
}
public List<KvpExchangeDataItem> GetStandardKVPItems(string vmId)
{
return GetKVPItems(vmId, "GuestIntrinsicExchangeItems");
}
private List<KvpExchangeDataItem> GetKVPItems(string vmId, string exchangeItemsName)
{
List<KvpExchangeDataItem> pairs = new List<KvpExchangeDataItem>();
// load VM
ManagementObject objVm = GetVirtualMachineObject(vmId);
ManagementObject objKvpExchange = null;
try
{
objKvpExchange = wmi.GetRelatedWmiObject(objVm, "msvm_KvpExchangeComponent");
}
catch
{
// TODO
// add logging...
return pairs;
}
// return XML pairs
string[] xmlPairs = (string[])objKvpExchange[exchangeItemsName];
if (xmlPairs == null)
return pairs;
// join all pairs
StringBuilder sb = new StringBuilder();
sb.Append("<result>");
foreach (string xmlPair in xmlPairs)
sb.Append(xmlPair);
sb.Append("</result>");
// parse pairs
XmlDocument doc = new XmlDocument();
doc.LoadXml(sb.ToString());
foreach (XmlNode nodeName in doc.SelectNodes("/result/INSTANCE/PROPERTY[@NAME='Name']/VALUE"))
{
string name = nodeName.InnerText;
string data = nodeName.ParentNode.ParentNode.SelectSingleNode("PROPERTY[@NAME='Data']/VALUE").InnerText;
pairs.Add(new KvpExchangeDataItem(name, data));
}
return pairs;
}
public JobResult AddKVPItems(string vmId, KvpExchangeDataItem[] items)
{
// get KVP management object
ManagementObject objVmsvc = GetVirtualSystemManagementService();
// create KVP items array
string[] wmiItems = new string[items.Length];
for (int i = 0; i < items.Length; i++)
{
ManagementClass clsKvp = wmi.GetWmiClass("Msvm_KvpExchangeDataItem");
ManagementObject objKvp = clsKvp.CreateInstance();
objKvp["Name"] = items[i].Name;
objKvp["Data"] = items[i].Data;
objKvp["Source"] = 0;
// convert to WMI format
wmiItems[i] = objKvp.GetText(TextFormat.CimDtd20);
}
ManagementBaseObject inParams = objVmsvc.GetMethodParameters("AddKvpItems");
inParams["TargetSystem"] = GetVirtualMachineObject(vmId);
inParams["DataItems"] = wmiItems;
// invoke method
ManagementBaseObject outParams = objVmsvc.InvokeMethod("AddKvpItems", inParams, null);
return CreateJobResultFromWmiMethodResults(outParams);
}
public JobResult RemoveKVPItems(string vmId, string[] itemNames)
{
// get KVP management object
ManagementObject objVmsvc = GetVirtualSystemManagementService();
// delete items one by one
for (int i = 0; i < itemNames.Length; i++)
{
ManagementClass clsKvp = wmi.GetWmiClass("Msvm_KvpExchangeDataItem");
ManagementObject objKvp = clsKvp.CreateInstance();
objKvp["Name"] = itemNames[i];
objKvp["Data"] = "";
objKvp["Source"] = 0;
// convert to WMI format
string wmiItem = objKvp.GetText(TextFormat.CimDtd20);
// call method
ManagementBaseObject inParams = objVmsvc.GetMethodParameters("RemoveKvpItems");
inParams["TargetSystem"] = GetVirtualMachineObject(vmId);
inParams["DataItems"] = new string[] { wmiItem };
// invoke method
objVmsvc.InvokeMethod("RemoveKvpItems", inParams, null);
}
return null;
}
public JobResult ModifyKVPItems(string vmId, KvpExchangeDataItem[] items)
{
// get KVP management object
ManagementObject objVmsvc = GetVirtualSystemManagementService();
// create KVP items array
string[] wmiItems = new string[items.Length];
for (int i = 0; i < items.Length; i++)
{
ManagementClass clsKvp = wmi.GetWmiClass("Msvm_KvpExchangeDataItem");
ManagementObject objKvp = clsKvp.CreateInstance();
objKvp["Name"] = items[i].Name;
objKvp["Data"] = items[i].Data;
objKvp["Source"] = 0;
// convert to WMI format
wmiItems[i] = objKvp.GetText(TextFormat.CimDtd20);
}
ManagementBaseObject inParams = objVmsvc.GetMethodParameters("ModifyKvpItems");
inParams["TargetSystem"] = GetVirtualMachineObject(vmId);
inParams["DataItems"] = wmiItems;
// invoke method
ManagementBaseObject outParams = objVmsvc.InvokeMethod("ModifyKvpItems", inParams, null);
return CreateJobResultFromWmiMethodResults(outParams);
}
#endregion
#region Storage
public VirtualHardDiskInfo GetVirtualHardDiskInfo(string vhdPath)
{
ManagementObject objImgSvc = GetImageManagementService();
// get method params
ManagementBaseObject inParams = objImgSvc.GetMethodParameters("GetVirtualHardDiskInfo");
inParams["Path"] = FileUtils.EvaluateSystemVariables(vhdPath);
// execute method
ManagementBaseObject outParams = (ManagementBaseObject)objImgSvc.InvokeMethod("GetVirtualHardDiskInfo", inParams, null);
ReturnCode result = (ReturnCode)Convert.ToInt32(outParams["ReturnValue"]);
if (result == ReturnCode.OK)
{
// create XML
string xml = (string)outParams["Info"];
XmlDocument doc = new XmlDocument();
doc.LoadXml(xml);
// read properties
VirtualHardDiskInfo vhd = new VirtualHardDiskInfo();
vhd.DiskType = (VirtualHardDiskType)Enum.Parse(typeof(VirtualHardDiskType), GetPropertyValue("Type", doc), true);
vhd.FileSize = Int64.Parse(GetPropertyValue("FileSize", doc));
vhd.InSavedState = Boolean.Parse(GetPropertyValue("InSavedState", doc));
vhd.InUse = Boolean.Parse(GetPropertyValue("InUse", doc));
vhd.MaxInternalSize = Int64.Parse(GetPropertyValue("MaxInternalSize", doc));
vhd.ParentPath = GetPropertyValue("ParentPath", doc);
return vhd;
}
return null;
}
private string GetPropertyValue(string propertyName, XmlDocument doc)
{
string xpath = string.Format(@"//PROPERTY[@NAME = '{0}']/VALUE/child::text()", propertyName);
XmlNode node = doc.SelectSingleNode(xpath);
return node != null ? node.Value : null;
}
public MountedDiskInfo MountVirtualHardDisk(string vhdPath)
{
ManagementObject objImgSvc = GetImageManagementService();
// get method params
ManagementBaseObject inParams = objImgSvc.GetMethodParameters("Mount");
inParams["Path"] = FileUtils.EvaluateSystemVariables(vhdPath);
ManagementBaseObject outParams = (ManagementBaseObject)objImgSvc.InvokeMethod("Mount", inParams, null);
JobResult result = CreateJobResultFromWmiMethodResults(outParams);
// load storage job
if (result.ReturnValue != ReturnCode.JobStarted)
throw new Exception("Failed to start Mount job with the following error: " + result.ReturnValue); ;
ManagementObject objJob = wmi.GetWmiObject("msvm_StorageJob", "InstanceID = '{0}'", result.Job.Id);
if (!JobCompleted(result.Job))
throw new Exception("Failed to complete Mount job with the following error: " + result.Job.ErrorDescription);
try
{
List<string> volumes = new List<string>();
// load output data
ManagementObject objImage = wmi.GetRelatedWmiObject(objJob, "Msvm_MountedStorageImage");
int pathId = Convert.ToInt32(objImage["PathId"]);
int portNumber = Convert.ToInt32(objImage["PortNumber"]);
int targetId = Convert.ToInt32(objImage["TargetId"]);
int lun = Convert.ToInt32(objImage["Lun"]);
string diskAddress = String.Format("Port{0}Path{1}Target{2}Lun{3}", portNumber, pathId, targetId, lun);
Log.WriteInfo("Disk address: " + diskAddress);
// find mounted disk using VDS
Vds.Advanced.AdvancedDisk advancedDisk = null;
Vds.Pack diskPack = null;
// first attempt
System.Threading.Thread.Sleep(3000);
Log.WriteInfo("Trying to find mounted disk - first attempt");
FindVdsDisk(diskAddress, out advancedDisk, out diskPack);
// second attempt
if (advancedDisk == null)
{
System.Threading.Thread.Sleep(20000);
Log.WriteInfo("Trying to find mounted disk - second attempt");
FindVdsDisk(diskAddress, out advancedDisk, out diskPack);
}
if (advancedDisk == null)
throw new Exception("Could not find mounted disk");
// check if DiskPart must be used to bring disk online and clear read-only flag
bool useDiskPartToClearReadOnly = false;
if (ConfigurationManager.AppSettings[CONFIG_USE_DISKPART_TO_CLEAR_READONLY_FLAG] != null)
useDiskPartToClearReadOnly = Boolean.Parse(ConfigurationManager.AppSettings[CONFIG_USE_DISKPART_TO_CLEAR_READONLY_FLAG]);
// determine disk index for DiskPart
Wmi cimv2 = new Wmi(ServerNameSettings, WMI_CIMV2_NAMESPACE);
ManagementObject objDisk = cimv2.GetWmiObject("win32_diskdrive",
"Model='Msft Virtual Disk SCSI Disk Device' and ScsiTargetID={0} and ScsiLogicalUnit={1} and scsiPort={2}",
targetId, lun, portNumber);
if (useDiskPartToClearReadOnly)
{
// *** Clear Read-Only and bring disk online with DiskPart ***
Log.WriteInfo("Clearing disk Read-only flag and bringing disk online");
if (objDisk != null)
{
// disk found
// run DiskPart
string diskPartResult = RunDiskPart(String.Format(@"select disk {0}
attributes disk clear readonly
online disk
exit", Convert.ToInt32(objDisk["Index"])));
Log.WriteInfo("DiskPart Result: " + diskPartResult);
}
}
else
{
// *** Clear Read-Only and bring disk online with VDS ***
// clear Read-Only
if ((advancedDisk.Flags & Vds.DiskFlags.ReadOnly) == Vds.DiskFlags.ReadOnly)
{
Log.WriteInfo("Clearing disk Read-only flag");
advancedDisk.ClearFlags(Vds.DiskFlags.ReadOnly);
while ((advancedDisk.Flags & Vds.DiskFlags.ReadOnly) == Vds.DiskFlags.ReadOnly)
{
System.Threading.Thread.Sleep(100);
advancedDisk.Refresh();
}
}
// bring disk ONLINE
if (advancedDisk.Status == Vds.DiskStatus.Offline)
{
Log.WriteInfo("Bringing disk online");
advancedDisk.Online();
while (advancedDisk.Status == Vds.DiskStatus.Offline)
{
System.Threading.Thread.Sleep(100);
advancedDisk.Refresh();
}
}
}
// small pause after getting disk online
System.Threading.Thread.Sleep(3000);
// get disk again
FindVdsDisk(diskAddress, out advancedDisk, out diskPack);
// find volumes using VDS
Log.WriteInfo("Querying disk volumes with VDS");
foreach (Vds.Volume volume in diskPack.Volumes)
{
string letter = volume.DriveLetter.ToString();
if(letter != "")
volumes.Add(letter);
}
// find volumes using WMI
if (volumes.Count == 0 && objDisk != null)
{
Log.WriteInfo("Querying disk volumes with WMI");
foreach (ManagementObject objPartition in objDisk.GetRelated("Win32_DiskPartition"))
{
foreach (ManagementObject objVolume in objPartition.GetRelated("Win32_LogicalDisk"))
{
volumes.Add(objVolume["Name"].ToString().TrimEnd(':'));
}
}
}
Log.WriteInfo("Volumes found: " + volumes.Count);
// info object
MountedDiskInfo info = new MountedDiskInfo();
info.DiskAddress = diskAddress;
info.DiskVolumes = volumes.ToArray();
return info;
}
catch(Exception ex)
{
// unmount disk
UnmountVirtualHardDisk(vhdPath);
// throw error
throw ex;
}
}
private void FindVdsDisk(string diskAddress, out Vds.Advanced.AdvancedDisk advancedDisk, out Vds.Pack diskPack)
{
advancedDisk = null;
diskPack = null;
Vds.ServiceLoader serviceLoader = new Vds.ServiceLoader();
Vds.Service vds = serviceLoader.LoadService(ServerNameSettings);
vds.WaitForServiceReady();
foreach (Vds.Disk disk in vds.UnallocatedDisks)
{
if (disk.DiskAddress == diskAddress)
{
advancedDisk = (Vds.Advanced.AdvancedDisk)disk;
break;
}
}
if (advancedDisk == null)
{
vds.HardwareProvider = false;
vds.SoftwareProvider = true;
foreach (Vds.SoftwareProvider provider in vds.Providers)
foreach (Vds.Pack pack in provider.Packs)
foreach (Vds.Disk disk in pack.Disks)
if (disk.DiskAddress == diskAddress)
{
diskPack = pack;
advancedDisk = (Vds.Advanced.AdvancedDisk)disk;
break;
}
}
}
public ReturnCode UnmountVirtualHardDisk(string vhdPath)
{
ManagementObject objImgSvc = GetImageManagementService();
// get method params
ManagementBaseObject inParams = objImgSvc.GetMethodParameters("Unmount");
inParams["Path"] = FileUtils.EvaluateSystemVariables(vhdPath);
ManagementBaseObject outParams = (ManagementBaseObject)objImgSvc.InvokeMethod("Unmount", inParams, null);
return (ReturnCode)Convert.ToInt32(outParams["ReturnValue"]);
}
public JobResult ExpandVirtualHardDisk(string vhdPath, UInt64 sizeGB)
{
const UInt64 Size1G = 0x40000000;
ManagementObject objImgSvc = GetImageManagementService();
// get method params
ManagementBaseObject inParams = objImgSvc.GetMethodParameters("ExpandVirtualHardDisk");
inParams["Path"] = FileUtils.EvaluateSystemVariables(vhdPath);
inParams["MaxInternalSize"] = sizeGB * Size1G;
ManagementBaseObject outParams = (ManagementBaseObject)objImgSvc.InvokeMethod("ExpandVirtualHardDisk", inParams, null);
return CreateJobResultFromWmiMethodResults(outParams);
}
public JobResult ConvertVirtualHardDisk(string sourcePath, string destinationPath, VirtualHardDiskType diskType)
{
sourcePath = FileUtils.EvaluateSystemVariables(sourcePath);
destinationPath = FileUtils.EvaluateSystemVariables(destinationPath);
// check source file
if (!FileExists(sourcePath))
throw new Exception("Source VHD cannot be found: " + sourcePath);
// check destination folder
string destFolder = Path.GetDirectoryName(destinationPath);
if (!DirectoryExists(destFolder))
CreateFolder(destFolder);
ManagementObject objImgSvc = GetImageManagementService();
// get method params
ManagementBaseObject inParams = objImgSvc.GetMethodParameters("ConvertVirtualHardDisk");
inParams["SourcePath"] = sourcePath;
inParams["DestinationPath"] = destinationPath;
inParams["Type"] = (UInt16)diskType;
ManagementBaseObject outParams = (ManagementBaseObject)objImgSvc.InvokeMethod("ConvertVirtualHardDisk", inParams, null);
return CreateJobResultFromWmiMethodResults(outParams);
}
public void DeleteRemoteFile(string path)
{
if (DirectoryExists(path))
DeleteFolder(path); // WMI way
else if (FileExists(path))
DeleteFile(path); // WMI way
}
public void ExpandDiskVolume(string diskAddress, string volumeName)
{
// find mounted disk using VDS
Vds.Advanced.AdvancedDisk advancedDisk = null;
Vds.Pack diskPack = null;
FindVdsDisk(diskAddress, out advancedDisk, out diskPack);
if (advancedDisk == null)
throw new Exception("Could not find mounted disk");
// find volume
Vds.Volume diskVolume = null;
foreach (Vds.Volume volume in diskPack.Volumes)
{
if (volume.DriveLetter.ToString() == volumeName)
{
diskVolume = volume;
break;
}
}
if (diskVolume == null)
throw new Exception("Could not find disk volume: " + volumeName);
// determine maximum available space
ulong oneMegabyte = 1048576;
ulong freeSpace = 0;
foreach (Vds.DiskExtent extent in advancedDisk.Extents)
{
if (extent.Type != Microsoft.Storage.Vds.DiskExtentType.Free)
continue;
if (extent.Size > oneMegabyte)
freeSpace += extent.Size;
}
if (freeSpace == 0)
return;
// input disk
Vds.InputDisk inputDisk = new Vds.InputDisk();
foreach (Vds.VolumePlex plex in diskVolume.Plexes)
{
inputDisk.DiskId = advancedDisk.Id;
inputDisk.Size = freeSpace;
inputDisk.PlexId = plex.Id;
foreach (Vds.DiskExtent extent in plex.Extents)
inputDisk.MemberIndex = extent.MemberIndex;
break;
}
// extend volume
Vds.Async extendEvent = diskVolume.BeginExtend(new Vds.InputDisk[]{ inputDisk }, null, null);
while (!extendEvent.IsCompleted)
System.Threading.Thread.Sleep(100);
diskVolume.EndExtend(extendEvent);
}
// obsolete and currently is not used
private string RunDiskPart(string script)
{
// create temp script file name
string localPath = Path.Combine(GetTempRemoteFolder(), Guid.NewGuid().ToString("N"));
// save script to remote temp file
string remotePath = ConvertToUNC(localPath);
File.AppendAllText(remotePath, script);
// run diskpart
ExecuteRemoteProcess("DiskPart /s " + localPath);
// delete temp script
try
{
File.Delete(remotePath);
}
catch
{
// TODO
}
return "";
}
public string ReadRemoteFile(string path)
{
// temp file name on "system" drive available through hidden share
string tempPath = Path.Combine(GetTempRemoteFolder(), Guid.NewGuid().ToString("N"));
Log.WriteInfo("Read remote file: " + path);
Log.WriteInfo("Local file temp path: " + tempPath);
// copy remote file to temp file (WMI)
if (!CopyFile(path, tempPath))
return null;
// read content of temp file
string remoteTempPath = ConvertToUNC(tempPath);
Log.WriteInfo("Remote file temp path: " + remoteTempPath);
string content = File.ReadAllText(remoteTempPath);
// delete temp file (WMI)
DeleteFile(tempPath);
return content;
}
public void WriteRemoteFile(string path, string content)
{
// temp file name on "system" drive available through hidden share
string tempPath = Path.Combine(GetTempRemoteFolder(), Guid.NewGuid().ToString("N"));
// write to temp file
string remoteTempPath = ConvertToUNC(tempPath);
File.WriteAllText(remoteTempPath, content);
// delete file (WMI)
if (FileExists(path))
DeleteFile(path);
// copy (WMI)
CopyFile(tempPath, path);
// delete temp file (WMI)
DeleteFile(tempPath);
}
#endregion
#region Jobs
public ConcreteJob GetJob(string jobId)
{
ManagementObject objJob = wmi.GetWmiObject("CIM_ConcreteJob", "InstanceID = '{0}'", jobId);
return CreateJobFromWmiObject(objJob);
}
public List<ConcreteJob> GetAllJobs()
{
List<ConcreteJob> jobs = new List<ConcreteJob>();
ManagementObjectCollection objJobs = wmi.GetWmiObjects("CIM_ConcreteJob");
foreach (ManagementObject objJob in objJobs)
jobs.Add(CreateJobFromWmiObject(objJob));
return jobs;
}
public ChangeJobStateReturnCode ChangeJobState(string jobId, ConcreteJobRequestedState newState)
{
ManagementObject objJob = GetJobWmiObject(jobId);
// get method
ManagementBaseObject inParams = objJob.GetMethodParameters("RequestStateChange");
inParams["RequestedState"] = (Int32)newState;
// invoke method
ManagementBaseObject outParams = objJob.InvokeMethod("RequestStateChange", inParams, null);
return (ChangeJobStateReturnCode)Convert.ToInt32(outParams["ReturnValue"]);
}
#endregion
#region Configuration
public int GetProcessorCoresNumber()
{
Wmi w = new Wmi(ServerNameSettings, @"root\cimv2");
ManagementObject objCpu = w.GetWmiObject("win32_Processor");
return Convert.ToInt32(objCpu["NumberOfCores"]);
}
#endregion
#region IHostingServiceProvier methods
public override string[] Install()
{
List<string> messages = new List<string>();
// TODO
return messages.ToArray();
}
public override bool IsInstalled()
{
// check if Hyper-V role is installed and available for management
//Wmi root = new Wmi(ServerNameSettings, "root");
//ManagementObject objNamespace = root.GetWmiObject("__NAMESPACE", "name = 'virtualization'");
//return (objNamespace != null);
return true;
}
public override void ChangeServiceItemsState(ServiceProviderItem[] items, bool enabled)
{
foreach (ServiceProviderItem item in items)
{
if (item is VirtualMachine)
{
// start/stop virtual machine
VirtualMachine vm = item as VirtualMachine;
ChangeVirtualMachineServiceItemState(vm, enabled);
}
}
}
public override void DeleteServiceItems(ServiceProviderItem[] items)
{
foreach (ServiceProviderItem item in items)
{
if (item is VirtualMachine)
{
// delete virtual machine
VirtualMachine vm = item as VirtualMachine;
DeleteVirtualMachineServiceItem(vm);
}
else if (item is VirtualSwitch)
{
// delete switch
VirtualSwitch vs = item as VirtualSwitch;
DeleteVirtualSwitchServiceItem(vs);
}
}
}
private void ChangeVirtualMachineServiceItemState(VirtualMachine vm, bool started)
{
try
{
VirtualMachine vps = GetVirtualMachine(vm.VirtualMachineId);
JobResult result = null;
if (vps == null)
{
Log.WriteWarning(String.Format("Virtual machine '{0}' object with ID '{1}' was not found. Change state operation aborted.",
vm.Name, vm.VirtualMachineId));
return;
}
#region Start
if (started &&
(vps.State == VirtualMachineState.Off
|| vps.State == VirtualMachineState.Paused
|| vps.State == VirtualMachineState.Saved))
{
VirtualMachineRequestedState state = VirtualMachineRequestedState.Start;
if (vps.State == VirtualMachineState.Paused)
state = VirtualMachineRequestedState.Resume;
result = ChangeVirtualMachineState(vm.VirtualMachineId, state);
// check result
if (result.ReturnValue != ReturnCode.JobStarted)
{
Log.WriteWarning(String.Format("Cannot {0} '{1}' virtual machine: {2}",
state, vm.Name, result.ReturnValue));
return;
}
// wait for completion
if (!JobCompleted(result.Job))
{
Log.WriteWarning(String.Format("Cannot complete {0} '{1}' of virtual machine: {1}",
state, vm.Name, result.Job.ErrorDescription));
return;
}
}
#endregion
#region Stop
else if (!started &&
(vps.State == VirtualMachineState.Started
|| vps.State == VirtualMachineState.Paused))
{
if (vps.State == VirtualMachineState.Started)
{
// try to shutdown the system
ReturnCode code = ShutDownVirtualMachine(vm.VirtualMachineId, true, "Virtual Machine has been suspended from WebsitePanel");
if (code == ReturnCode.OK)
return;
}
// turn off
VirtualMachineRequestedState state = VirtualMachineRequestedState.TurnOff;
result = ChangeVirtualMachineState(vm.VirtualMachineId, state);
// check result
if (result.ReturnValue != ReturnCode.JobStarted)
{
Log.WriteWarning(String.Format("Cannot {0} '{1}' virtual machine: {2}",
state, vm.Name, result.ReturnValue));
return;
}
// wait for completion
if (!JobCompleted(result.Job))
{
Log.WriteWarning(String.Format("Cannot complete {0} '{1}' of virtual machine: {1}",
state, vm.Name, result.Job.ErrorDescription));
return;
}
}
#endregion
}
catch (Exception ex)
{
Log.WriteError(String.Format("Error {0} Virtual Machine '{1}'",
started ? "starting" : "turning off",
vm.Name), ex);
}
}
private void DeleteVirtualMachineServiceItem(VirtualMachine vm)
{
try
{
JobResult result = null;
VirtualMachine vps = GetVirtualMachine(vm.VirtualMachineId);
if (vps == null)
{
Log.WriteWarning(String.Format("Virtual machine '{0}' object with ID '{1}' was not found. Delete operation aborted.",
vm.Name, vm.VirtualMachineId));
return;
}
#region Turn off (if required)
if (vps.State != VirtualMachineState.Off)
{
result = ChangeVirtualMachineState(vm.VirtualMachineId, VirtualMachineRequestedState.TurnOff);
// check result
if (result.ReturnValue != ReturnCode.JobStarted)
{
Log.WriteWarning(String.Format("Cannot Turn off '{0}' virtual machine before deletion: {1}",
vm.Name, result.ReturnValue));
return;
}
// wait for completion
if (!JobCompleted(result.Job))
{
Log.WriteWarning(String.Format("Cannot complete Turn off '{0}' of virtual machine before deletion: {1}",
vm.Name, result.Job.ErrorDescription));
return;
}
}
#endregion
#region Delete virtual machine
result = DeleteVirtualMachine(vm.VirtualMachineId);
// check result
if (result.ReturnValue != ReturnCode.JobStarted)
{
Log.WriteWarning(String.Format("Cannot delete '{0}' virtual machine: {1}",
vm.Name, result.ReturnValue));
return;
}
// wait for completion
if (!JobCompleted(result.Job))
{
Log.WriteWarning(String.Format("Cannot complete deletion of '{0}' virtual machine: {1}",
vm.Name, result.Job.ErrorDescription));
return;
}
#endregion
#region Delete virtual machine
try
{
DeleteFile(vm.RootFolderPath);
}
catch (Exception ex)
{
Log.WriteError(String.Format("Cannot delete virtual machine folder '{0}'",
vm.RootFolderPath), ex);
}
#endregion
}
catch (Exception ex)
{
Log.WriteError(String.Format("Error deleting Virtual Machine '{0}'", vm.Name), ex);
}
}
private void DeleteVirtualSwitchServiceItem(VirtualSwitch vs)
{
try
{
// delete virtual switch
DeleteSwitch(vs.SwitchId);
}
catch (Exception ex)
{
Log.WriteError(String.Format("Error deleting Virtual Switch '{0}'", vs.Name), ex);
}
}
#endregion
#region Private Methods
protected JobResult CreateJobResultFromWmiMethodResults(ManagementBaseObject outParams)
{
JobResult result = new JobResult();
// return value
result.ReturnValue = (ReturnCode)Convert.ToInt32(outParams["ReturnValue"]);
// try getting job details job
try
{
ManagementBaseObject objJob = wmi.GetWmiObjectByPath((string)outParams["Job"]);
if (objJob != null && objJob.Properties.Count > 0)
{
result.Job = CreateJobFromWmiObject(objJob);
}
}
catch { /* dumb */ }
return result;
}
private ManagementObject GetJobWmiObject(string id)
{
return wmi.GetWmiObject("msvm_ConcreteJob", "InstanceID = '{0}'", id);
}
private ManagementObject GetVirtualSystemManagementService()
{
return wmi.GetWmiObject("msvm_VirtualSystemManagementService");
}
private ManagementObject GetVirtualSwitchManagementService()
{
return wmi.GetWmiObject("msvm_VirtualSwitchManagementService");
}
protected ManagementObject GetImageManagementService()
{
return wmi.GetWmiObject("msvm_ImageManagementService");
}
private ManagementObject GetVirtualMachineObject(string vmId)
{
return wmi.GetWmiObject("msvm_ComputerSystem", "Name = '{0}'", vmId);
}
private ManagementObject GetSnapshotObject(string snapshotId)
{
return wmi.GetWmiObject("Msvm_VirtualSystemSettingData", "InstanceID = '{0}'", snapshotId);
}
private VirtualMachine CreateVirtualMachineFromWmiObject(ManagementObject objVm)
{
if (objVm == null || objVm.Properties.Count == 0)
return null;
VirtualMachine vm = new VirtualMachine();
vm.VirtualMachineId = (string)objVm["Name"];
vm.Name = (string)objVm["ElementName"];
vm.State = (VirtualMachineState)Convert.ToInt32(objVm["EnabledState"]);
vm.Uptime = Convert.ToInt64(objVm["OnTimeInMilliseconds"]);
return vm;
}
private VirtualMachineSnapshot CreateSnapshotFromWmiObject(ManagementBaseObject objSnapshot)
{
if (objSnapshot == null || objSnapshot.Properties.Count == 0)
return null;
VirtualMachineSnapshot snapshot = new VirtualMachineSnapshot();
snapshot.Id = (string)objSnapshot["InstanceID"];
snapshot.Name = (string)objSnapshot["ElementName"];
string parentId = (string)objSnapshot["Parent"];
if (!String.IsNullOrEmpty(parentId))
{
int idx = parentId.IndexOf("Microsoft:");
snapshot.ParentId = parentId.Substring(idx, parentId.Length - idx - 1);
}
snapshot.Created = wmi.ToDateTime((string)objSnapshot["CreationTime"]);
return snapshot;
}
private VirtualSwitch CreateSwitchFromWmiObject(ManagementObject objSwitch)
{
if (objSwitch == null || objSwitch.Properties.Count == 0)
return null;
VirtualSwitch sw = new VirtualSwitch();
sw.SwitchId = (string)objSwitch["Name"];
sw.Name = (string)objSwitch["ElementName"];
return sw;
}
private ConcreteJob CreateJobFromWmiObject(ManagementBaseObject objJob)
{
if (objJob == null || objJob.Properties.Count == 0)
return null;
ConcreteJob job = new ConcreteJob();
job.Id = (string)objJob["InstanceID"];
job.JobState = (ConcreteJobState)Convert.ToInt32(objJob["JobState"]);
job.Caption = (string)objJob["Caption"];
job.Description = (string)objJob["Description"];
job.StartTime = wmi.ToDateTime((string)objJob["StartTime"]);
// TODO proper parsing of WMI time spans, e.g. 00000000000001.325247:000
job.ElapsedTime = DateTime.Now; //wmi.ToDateTime((string)objJob["ElapsedTime"]);
job.ErrorCode = Convert.ToInt32(objJob["ErrorCode"]);
job.ErrorDescription = (string)objJob["ErrorDescription"];
job.PercentComplete = Convert.ToInt32(objJob["PercentComplete"]);
return job;
}
private ManagementBaseObject GetSnapshotSummaryInformation(
string snapshotId,
SummaryInformationRequest requestedInformation)
{
// find VM settings object
ManagementObject objVmSetting = GetSnapshotObject(snapshotId);
// get summary
return GetSummaryInformation(objVmSetting, requestedInformation);
}
private ManagementBaseObject GetVirtualMachineSummaryInformation(
string vmId,
params SummaryInformationRequest[] requestedInformation)
{
// find VM settings object
ManagementObject objVmSetting = GetVirtualMachineSettingsObject(vmId);
// get summary
return GetSummaryInformation(objVmSetting, requestedInformation);
}
private ManagementBaseObject GetSummaryInformation(
ManagementObject objVmSetting, params SummaryInformationRequest[] requestedInformation)
{
if (requestedInformation == null || requestedInformation.Length == 0)
throw new ArgumentNullException("requestedInformation");
// get management service
ManagementObject objVmsvc = GetVirtualSystemManagementService();
uint[] reqif = new uint[requestedInformation.Length];
for (int i = 0; i < requestedInformation.Length; i++)
reqif[i] = (uint)requestedInformation[i];
// get method params
ManagementBaseObject inParams = objVmsvc.GetMethodParameters("GetSummaryInformation");
inParams["SettingData"] = new ManagementObject[] { objVmSetting };
inParams["RequestedInformation"] = reqif;
// invoke method
ManagementBaseObject outParams = objVmsvc.InvokeMethod("GetSummaryInformation", inParams, null);
return ((ManagementBaseObject[])outParams["SummaryInformation"])[0];
}
private ManagementObject GetVirtualMachineSettingsObject(string vmId)
{
return wmi.GetWmiObject("msvm_VirtualSystemSettingData", "InstanceID Like 'Microsoft:{0}%'", vmId);
}
private bool JobCompleted(ConcreteJob job)
{
bool jobCompleted = true;
while (job.JobState == ConcreteJobState.Starting ||
job.JobState == ConcreteJobState.Running)
{
System.Threading.Thread.Sleep(200);
job = GetJob(job.Id);
}
if (job.JobState != ConcreteJobState.Completed)
{
jobCompleted = false;
}
return jobCompleted;
}
#endregion
#region Remote File Methods
public bool FileExists(string path)
{
Log.WriteInfo("Check remote file exists: " + path);
if (path.StartsWith(@"\\")) // network share
return File.Exists(path);
else
{
Wmi cimv2 = new Wmi(ServerNameSettings, WMI_CIMV2_NAMESPACE);
ManagementObject objFile = cimv2.GetWmiObject("CIM_Datafile", "Name='{0}'", path.Replace("\\", "\\\\"));
return (objFile != null);
}
}
public bool DirectoryExists(string path)
{
if (path.StartsWith(@"\\")) // network share
return Directory.Exists(path);
else
{
Wmi cimv2 = new Wmi(ServerNameSettings, WMI_CIMV2_NAMESPACE);
ManagementObject objDir = cimv2.GetWmiObject("Win32_Directory", "Name='{0}'", path.Replace("\\", "\\\\"));
return (objDir != null);
}
}
public bool CopyFile(string sourceFileName, string destinationFileName)
{
Log.WriteInfo("Copy file - source: " + sourceFileName);
Log.WriteInfo("Copy file - destination: " + destinationFileName);
if (sourceFileName.StartsWith(@"\\")) // network share
{
if (!File.Exists(sourceFileName))
return false;
File.Copy(sourceFileName, destinationFileName);
}
else
{
if (!FileExists(sourceFileName))
return false;
// copy using WMI
Wmi cimv2 = new Wmi(ServerNameSettings, WMI_CIMV2_NAMESPACE);
ManagementObject objFile = cimv2.GetWmiObject("CIM_Datafile", "Name='{0}'", sourceFileName.Replace("\\", "\\\\"));
if (objFile == null)
throw new Exception("Source file does not exists: " + sourceFileName);
objFile.InvokeMethod("Copy", new object[] { destinationFileName });
}
return true;
}
public void DeleteFile(string path)
{
if (path.StartsWith(@"\\"))
{
// network share
File.Delete(path);
}
else
{
// delete file using WMI
Wmi cimv2 = new Wmi(ServerNameSettings, "root\\cimv2");
ManagementObject objFile = cimv2.GetWmiObject("CIM_Datafile", "Name='{0}'", path.Replace("\\", "\\\\"));
objFile.InvokeMethod("Delete", null);
}
}
public void DeleteFolder(string path)
{
if (path.StartsWith(@"\\"))
{
// network share
try
{
FileUtils.DeleteFile(path);
}
catch { /* just skip */ }
FileUtils.DeleteFile(path);
}
else
{
// local folder
// delete sub folders first
ManagementObjectCollection objSubFolders = GetSubFolders(path);
foreach (ManagementObject objSubFolder in objSubFolders)
DeleteFolder(objSubFolder["Name"].ToString());
// delete this folder itself
Wmi cimv2 = new Wmi(ServerNameSettings, "root\\cimv2");
ManagementObject objFolder = cimv2.GetWmiObject("Win32_Directory", "Name='{0}'", path.Replace("\\", "\\\\"));
objFolder.InvokeMethod("Delete", null);
}
}
private ManagementObjectCollection GetSubFolders(string path)
{
if (path.EndsWith("\\"))
path = path.Substring(0, path.Length - 1);
Wmi cimv2 = new Wmi(ServerNameSettings, "root\\cimv2");
return cimv2.ExecuteWmiQuery("Associators of {Win32_Directory.Name='"
+ path + "'} "
+ "Where AssocClass = Win32_Subdirectory "
+ "ResultRole = PartComponent");
}
public void CreateFolder(string path)
{
ExecuteRemoteProcess(String.Format("cmd.exe /c md \"{0}\"", path));
}
public void ExecuteRemoteProcess(string command)
{
Wmi cimv2 = new Wmi(ServerNameSettings, "root\\cimv2");
ManagementClass objProcess = cimv2.GetWmiClass("Win32_Process");
// run process
object[] methodArgs = { command, null, null, 0 };
objProcess.InvokeMethod("Create", methodArgs);
// process ID
int processId = Convert.ToInt32(methodArgs[3]);
// wait until finished
// Create event query to be notified within 1 second of
// a change in a service
WqlEventQuery query =
new WqlEventQuery("__InstanceDeletionEvent",
new TimeSpan(0, 0, 1),
"TargetInstance isa \"Win32_Process\"");
// Initialize an event watcher and subscribe to events
// that match this query
ManagementEventWatcher watcher = new ManagementEventWatcher(cimv2.GetScope(), query);
// times out watcher.WaitForNextEvent in 20 seconds
watcher.Options.Timeout = new TimeSpan(0, 0, 20);
// Block until the next event occurs
// Note: this can be done in a loop if waiting for
// more than one occurrence
while (true)
{
ManagementBaseObject e = null;
try
{
// wait untill next process finish
e = watcher.WaitForNextEvent();
}
catch
{
// nothing has been finished in timeout period
return; // exit
}
// check process id
int pid = Convert.ToInt32(((ManagementBaseObject)e["TargetInstance"])["ProcessID"]);
if (pid == processId)
{
//Cancel the subscription
watcher.Stop();
// exit
return;
}
}
}
public string GetTempRemoteFolder()
{
Wmi cimv2 = new Wmi(ServerNameSettings, "root\\cimv2");
ManagementObject objOS = cimv2.GetWmiObject("win32_OperatingSystem");
string sysPath = (string)objOS["SystemDirectory"];
// remove trailing slash
if (sysPath.EndsWith("\\"))
sysPath = sysPath.Substring(0, sysPath.Length - 1);
sysPath = sysPath.Substring(0, sysPath.LastIndexOf("\\") + 1) + "Temp";
return sysPath;
}
#endregion
#region Hyper-V Cloud
public bool CheckServerState(string connString)
{
return !String.IsNullOrEmpty(connString);
}
#endregion Hyper-V Cloud
}
}