Creating a VM
Trying to create Test VM from within Duplicati Refactored some code backup up VM
This commit is contained in:
@@ -41,6 +41,7 @@
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Management" />
|
||||
<Reference Include="System.Xml" />
|
||||
<Reference Include="System.Core" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
<Prefer32Bit>false</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Microsoft.VisualBasic" />
|
||||
<Reference Include="nunit.framework, Version=3.2.1.0, Culture=neutral, PublicKeyToken=2638cd05610744eb, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\..\packages\NUnit.3.2.1\lib\net45\nunit.framework.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
@@ -63,7 +64,7 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="DefineDosDevice.cs" />
|
||||
<Compile Include="HyperVBackup.cs" />
|
||||
<Compile Include="HyperVUtility.cs" />
|
||||
<Compile Include="ISnapshotService.cs" />
|
||||
<Compile Include="LinuxSnapshot.cs" />
|
||||
<Compile Include="Program.cs" />
|
||||
|
||||
@@ -1,87 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Management;
|
||||
using System.Text;
|
||||
|
||||
namespace Duplicati.Library.Snapshots
|
||||
{
|
||||
|
||||
//Original code: HVBackup Project
|
||||
public class HyperVBackup
|
||||
{
|
||||
private string _wmiQuery;
|
||||
private readonly string _wmiScope;
|
||||
private readonly string _vmIdField;
|
||||
private readonly string _wmiHost = "localhost"; //We could backup remote Hyper-V Machines in the future
|
||||
private readonly bool _wmiv2Namespace;
|
||||
|
||||
public List<string> RequestedVmNames = new List<string>();
|
||||
readonly IDictionary<string, string> _hyperVMachines = new Dictionary<string, string>();
|
||||
|
||||
public HyperVBackup()
|
||||
{
|
||||
//Set the namespace depending off host OS
|
||||
_wmiv2Namespace = Environment.OSVersion.Version.Major >= 6 && Environment.OSVersion.Version.Minor >= 2;
|
||||
//Set the scope to use in MWI. V2 for Server 2012 or newer.
|
||||
_wmiScope = _wmiv2Namespace ? $"\\\\{_wmiHost}\\root\\virtualization\\v2"
|
||||
: $"\\\\{_wmiHost}\\root\\virtualization";
|
||||
//Set the VM ID Selector Field for the WMI Query
|
||||
_vmIdField = _wmiv2Namespace ? "VirtualSystemIdentifier" : "SystemName";
|
||||
|
||||
}
|
||||
|
||||
public HyperVBackup(List<string> reqVmNames)
|
||||
{
|
||||
_wmiv2Namespace = Environment.OSVersion.Version.Major >= 6 && Environment.OSVersion.Version.Minor >= 2;
|
||||
_wmiScope = _wmiv2Namespace ? $"\\\\{_wmiHost}\\root\\virtualization\\v2"
|
||||
: $"\\\\{_wmiHost}\\root\\virtualization";
|
||||
_vmIdField = _wmiv2Namespace ? "VirtualSystemIdentifier" : "SystemName";
|
||||
//Store requested VM's
|
||||
RequestedVmNames = reqVmNames;
|
||||
}
|
||||
|
||||
public IDictionary<string, string> GetHyperVMachines()
|
||||
{
|
||||
//Set the WMI Query according the WMI Namespace
|
||||
SetWmiQueryVmidField();
|
||||
//We MOSearcher to search for the Hyper-V Machines
|
||||
using (ManagementObjectSearcher moSearcher = new ManagementObjectSearcher(new ManagementScope(_wmiScope), new ObjectQuery(_wmiQuery)))
|
||||
{
|
||||
using (var moCollection = moSearcher.Get())
|
||||
foreach (var mObject in moCollection)
|
||||
using (mObject)
|
||||
_hyperVMachines.Add((string)mObject[_vmIdField], (string)mObject["ElementName"]);
|
||||
}
|
||||
|
||||
return _hyperVMachines;
|
||||
}
|
||||
|
||||
private void SetWmiQueryVmidField()
|
||||
{
|
||||
_wmiQuery = _wmiv2Namespace ? "SELECT VirtualSystemIdentifier, ElementName FROM Msvm_VirtualSystemSettingData WHERE VirtualSystemType = 'Microsoft:Hyper-V:System:Realized'"
|
||||
: "SELECT SystemName, ElementName FROM Msvm_VirtualSystemSettingData WHERE SettingType = 3";
|
||||
|
||||
//Temporary Stringbuilder to build up the VM selectors
|
||||
var sb = new StringBuilder();
|
||||
|
||||
if (RequestedVmNames == null || !RequestedVmNames.Any()) return;
|
||||
foreach (var vmName in RequestedVmNames)
|
||||
{
|
||||
if (sb.Length > 0)
|
||||
sb.Append(" OR ");
|
||||
sb.Append($"ElementName = \'{vmName.Replace("'", "''")}\'");
|
||||
}
|
||||
_wmiQuery += $" AND ({sb})";
|
||||
}
|
||||
//private string GetWMIScope(string host = "localhost")
|
||||
//{
|
||||
// //string scopeFormatStr;
|
||||
// //if (IsNameSpaceWMIV2)
|
||||
// // scopeFormatStr = "\\\\{0}\\root\\virtualization\\v2";
|
||||
// //else
|
||||
// // scopeFormatStr = "\\\\{0}\\root\\virtualization";
|
||||
// //return (string.Format(scopeFormatStr, host));
|
||||
//}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,270 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Management;
|
||||
using System.Text;
|
||||
|
||||
using System.Globalization;
|
||||
|
||||
namespace Duplicati.Library.Snapshots
|
||||
{
|
||||
|
||||
//Original code: HVBackup Project
|
||||
public class HyperVUtility
|
||||
{
|
||||
private string _wmiQuery;
|
||||
private readonly ManagementScope _wmiScope;
|
||||
private readonly string _vmIdField;
|
||||
private readonly string _wmiHost = "localhost"; //We could backup remote Hyper-V Machines in the future
|
||||
private readonly bool _wmiv2Namespace;
|
||||
|
||||
public List<string> RequestedVmNames = new List<string>();
|
||||
readonly IDictionary<string, string> _hyperVMachines = new Dictionary<string, string>();
|
||||
|
||||
public HyperVUtility()
|
||||
{
|
||||
//Set the namespace depending off host OS
|
||||
_wmiv2Namespace = Environment.OSVersion.Version.Major >= 6 && Environment.OSVersion.Version.Minor >= 2;
|
||||
//Set the scope to use in MWI. V2 for Server 2012 or newer.
|
||||
_wmiScope = _wmiv2Namespace
|
||||
? new ManagementScope(string.Format("\\\\{0}\\root\\virtualization\\v2", _wmiHost))
|
||||
: new ManagementScope(string.Format("\\\\{0}\\root\\virtualization", _wmiHost));
|
||||
//Set the VM ID Selector Field for the WMI Query
|
||||
_vmIdField = _wmiv2Namespace ? "VirtualSystemIdentifier" : "SystemName";
|
||||
|
||||
}
|
||||
|
||||
public HyperVUtility(List<string> reqVmNames)
|
||||
{
|
||||
_wmiv2Namespace = Environment.OSVersion.Version.Major >= 6 && Environment.OSVersion.Version.Minor >= 2;
|
||||
_wmiScope = _wmiv2Namespace
|
||||
? new ManagementScope(string.Format("\\\\{0}\\root\\virtualization\\v2", _wmiHost))
|
||||
: new ManagementScope(string.Format("\\\\{0}\\root\\virtualization", _wmiHost));
|
||||
_vmIdField = _wmiv2Namespace ? "VirtualSystemIdentifier" : "SystemName";
|
||||
//Store requested VM's
|
||||
RequestedVmNames = reqVmNames;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// We query the Hyper-V for all requested Virtual Machines
|
||||
/// </summary>
|
||||
/// <returns>List of Hyper-V Machines</returns>
|
||||
public IDictionary<string, string> GetHyperVMachines()
|
||||
{
|
||||
ManagementObjectCollection moCollection = GetWmiObjects(WmiQueryHyperVMachines());
|
||||
foreach (ManagementBaseObject mObject in moCollection)
|
||||
using (mObject)
|
||||
_hyperVMachines.Add((string)mObject[_vmIdField], (string)mObject["ElementName"]);
|
||||
|
||||
return _hyperVMachines;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// We build up the wmi-query to retrieve all Virtual Machines
|
||||
/// </summary>
|
||||
/// <returns>WMI query</returns>
|
||||
private string WmiQueryHyperVMachines()
|
||||
{
|
||||
string wmiQuery = _wmiv2Namespace
|
||||
? "SELECT VirtualSystemIdentifier, ElementName FROM Msvm_VirtualSystemSettingData WHERE VirtualSystemType = 'Microsoft:Hyper-V:System:Realized'"
|
||||
: "SELECT SystemName, ElementName FROM Msvm_VirtualSystemSettingData WHERE SettingType = 3";
|
||||
|
||||
//Temporary Stringbuilder to build up the VM selectors
|
||||
var sb = new StringBuilder();
|
||||
|
||||
if (RequestedVmNames == null || !RequestedVmNames.Any()) return null;
|
||||
foreach (var vmName in RequestedVmNames)
|
||||
{
|
||||
if (sb.Length > 0)
|
||||
sb.Append(" OR ");
|
||||
sb.Append(string.Format("ElementName = \'{0}\'", vmName.Replace("'", "''")));
|
||||
}
|
||||
wmiQuery += string.Format(" AND ({0})", sb);
|
||||
|
||||
return wmiQuery;
|
||||
}
|
||||
#region Wmi helpers
|
||||
/// <summary>
|
||||
/// Executes the WMI Query
|
||||
/// </summary>
|
||||
/// <param name="query"></param>
|
||||
/// <returns>A collection of results</returns>
|
||||
private ManagementObjectCollection GetWmiObjects(string query)
|
||||
{
|
||||
ManagementObjectSearcher moSearcher = new ManagementObjectSearcher(_wmiScope, new ObjectQuery(query));
|
||||
ManagementObjectCollection resultset = moSearcher.Get();
|
||||
return resultset;
|
||||
}
|
||||
#endregion Wmi helpers
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#region Recovery Virtual Machines
|
||||
public void CreateHyperVMachine()
|
||||
{
|
||||
ManagementObject sysMan = GetMsVM_VirtualSystemManagementService("MsVM_VirtualSystemManagementService", null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Please refer to https://blogs.msdn.microsoft.com/sergeim/2008/06/03/prepare-vm-create-vm-programmatically-hyper-v-api-c-version/
|
||||
/// </summary>
|
||||
/// <param name="className"></param>
|
||||
/// <param name="where"></param>
|
||||
/// <returns></returns>
|
||||
private ManagementObject GetMsVM_VirtualSystemManagementService(string className, string where)
|
||||
{
|
||||
var query = @where != null
|
||||
? string.Format("select * from {0} where {1}", className, where)
|
||||
: string.Format("select * from {0}", className);
|
||||
|
||||
ManagementObjectCollection resultset = GetWmiObjects(query);
|
||||
|
||||
if (resultset.Count != 1)
|
||||
throw new InvalidOperationException(string.Format("Cannot locate {0} where {1}", className, where));
|
||||
|
||||
try
|
||||
{
|
||||
ManagementObjectCollection.ManagementObjectEnumerator en = resultset.GetEnumerator();
|
||||
en.MoveNext();
|
||||
return en.Current as ManagementObject;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
throw new InvalidOperationException(string.Format("Failure retrieving {0} where {1}", className, where));
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Please refer to https://blogs.msdn.microsoft.com/sergeim/2008/06/03/prepare-vm-create-vm-programmatically-hyper-v-api-c-version/
|
||||
/// </summary>
|
||||
/// <param name="className"></param>
|
||||
/// <param name="where"></param>
|
||||
/// <returns></returns>
|
||||
public void CreateVm(string displayName)
|
||||
{
|
||||
string notes = "Created" + DateTime.Now;
|
||||
|
||||
ManagementObject sysMan = GetMsVM_VirtualSystemManagementService();
|
||||
// Create VM with empty settings
|
||||
ManagementBaseObject definition = sysMan.InvokeMethod(Constants.DefineVirtualSystem, sysMan.GetMethodParameters(Constants.DefineVirtualSystem), null); //Empty set
|
||||
uint retCode = (uint)definition["returnvalue"];
|
||||
|
||||
if (retCode != Constants.ERROR_SUCCESS)
|
||||
throw new InvalidOperationException("DefineVirtualSystem failed");
|
||||
|
||||
// Obtain WMI root\virtualization:ComputerSystem object.
|
||||
// we will need "Name" of it, which is GUID
|
||||
|
||||
string vmPath = definition["DefinedSystem"] as string;
|
||||
ManagementObject computerSystemTemplate = new ManagementObject(vmPath);
|
||||
string vmName = (string)computerSystemTemplate["name"];
|
||||
|
||||
// this is GUID; will need to locate settings for this VM
|
||||
ManagementObject settings = GetMsvm_VirtualSystemSettingData(vmName);
|
||||
|
||||
// Now, set settings of this MSVM_ComputerSystem as we like
|
||||
|
||||
settings["elementname"] = displayName;
|
||||
settings["notes"] = notes;
|
||||
settings["BIOSGUID"] = new Guid();
|
||||
settings["BIOSSerialNumber"] = "1234567890";
|
||||
settings["BIOSNumLock"] = "true";
|
||||
|
||||
// settings["…"] = …;
|
||||
// … set whatever you like; see list at
|
||||
// http://msdn.microsoft.com/en-us/library/cc136944(VS.85).aspx
|
||||
|
||||
settings.Put();
|
||||
|
||||
// Now, set the settings which were build above to newly created ComputerSystem
|
||||
ManagementBaseObject inParams = sysMan.GetMethodParameters(Constants.ModifyVirtualSystem);
|
||||
string settingsText = settings.GetText(TextFormat.WmiDtd20);
|
||||
inParams["ComputerSystem"] = computerSystemTemplate;
|
||||
inParams["SystemSettingData"] = settingsText;
|
||||
ManagementBaseObject resultToCheck = sysMan.InvokeMethod(Constants.ModifyVirtualSystem, inParams, null);
|
||||
|
||||
// Almost done – now apply the settings to newly created ComputerSystem
|
||||
ManagementObject settingsAsSet = (ManagementObject)resultToCheck["ModifiedSettingData"];
|
||||
|
||||
// Optionally print settingsAsSet here
|
||||
|
||||
Log(string.Format("Created: VM with name {0} and GUID name {1}", displayName, vmName));
|
||||
|
||||
} // CreateVm
|
||||
|
||||
private ManagementObject GetMsVM_VirtualSystemManagementService()
|
||||
{
|
||||
return GetWmiObject("MsVM_VirtualSystemManagementService", null);
|
||||
}
|
||||
|
||||
private ManagementObject GetMsvm_VirtualSystemSettingData(string vmName)
|
||||
{
|
||||
return GetWmiObject("Msvm_VirtualSystemSettingData", string.Format("systemname = '{0}'", vmName));
|
||||
}
|
||||
|
||||
#region Wmi Helpers
|
||||
|
||||
private ManagementObject GetWmiObject(string classname, string where)
|
||||
{
|
||||
ManagementObjectCollection resultset = GetWmiObjects(classname, where);
|
||||
|
||||
if (resultset.Count != 1)
|
||||
throw new InvalidOperationException(string.Format("Cannot locate {0} where {1}", classname, where));
|
||||
|
||||
ManagementObjectCollection.ManagementObjectEnumerator en = resultset.GetEnumerator();
|
||||
en.MoveNext();
|
||||
ManagementObject result = en.Current as ManagementObject;
|
||||
|
||||
if (result == null) throw new InvalidOperationException("Failure retrieving " +classname + " where " +where);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private ManagementObjectCollection GetWmiObjects(string className, string where)
|
||||
{
|
||||
string query;
|
||||
ManagementScope scope = new ManagementScope(@"root\virtualization", null);
|
||||
if (where != null)
|
||||
{
|
||||
query = string.Format("select * from {0} where {1}", className, where);
|
||||
} else {
|
||||
query = string.Format("select * from {0}", className);
|
||||
}
|
||||
|
||||
ManagementObjectSearcher searcher = new ManagementObjectSearcher(scope, new ObjectQuery(query));
|
||||
ManagementObjectCollection resultset = searcher.Get();
|
||||
return resultset;
|
||||
}
|
||||
#endregion Wmi helpers
|
||||
|
||||
private static void Log(string message, params object[] data)
|
||||
{
|
||||
Console.WriteLine(message, data);
|
||||
}
|
||||
|
||||
private static void Oops(object sender, UnhandledExceptionEventArgs e)
|
||||
{
|
||||
Console.BackgroundColor = ConsoleColor.White;
|
||||
Console.ForegroundColor = ConsoleColor.Black;
|
||||
Exception ex = e.ExceptionObject as Exception;
|
||||
Log(ex.Message);
|
||||
Console.ResetColor();
|
||||
Log(ex.ToString());
|
||||
}
|
||||
|
||||
} // class MainCreateVm
|
||||
|
||||
class Constants
|
||||
{
|
||||
internal const string DefineVirtualSystem = "DefineVirtualSystem";
|
||||
internal const string ModifyVirtualSystem = "ModifyVirtualSystem";
|
||||
internal const uint ERROR_SUCCESS = 0;
|
||||
internal const uint ERROR_INV_ARGUMENTS = 87;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -115,12 +115,15 @@ namespace Duplicati.Library.Snapshots
|
||||
//Do not hardcode the VM in the future, the front-end will provide this.
|
||||
var requestedVMs = new List<string> {"TESTTS-CLNT"};
|
||||
//Make an hyper V Backup object with the requested VMs
|
||||
var hyperVBackup = new HyperVBackup(requestedVMs);
|
||||
var hyperVUtility = new HyperVUtility(requestedVMs);
|
||||
//Retrieve all information about VMs
|
||||
_hyperVMachines = hyperVBackup.GetHyperVMachines();
|
||||
_hyperVMachines = hyperVUtility.GetHyperVMachines();
|
||||
////Add the HyperV vss-writer; This is already implicitly included in the vss-writers
|
||||
//Enabling this vss-writer will disable all other vss-writers
|
||||
//m_backup.EnableWriterClasses(hyperVWriterGuid));
|
||||
|
||||
//attempt to create a vm
|
||||
hyperVUtility.CreateVm("createtest");
|
||||
}
|
||||
|
||||
m_backup.StartSnapshotSet();
|
||||
@@ -135,17 +138,17 @@ namespace Duplicati.Library.Snapshots
|
||||
//Gather information on all Vss writers
|
||||
m_backup.GatherWriterMetadata();
|
||||
|
||||
//If we are backup up Hyper V Machines then we need to update our sourcepaths
|
||||
#region HyperVBackup
|
||||
//Update the sourcepaths if we're backing up Hyper-V Machines
|
||||
if (options.ContainsKey("hyperv-backup-vm"))
|
||||
{
|
||||
//We will need the Hyper-V WriterMetaData to find the corresponding sourcepaths
|
||||
//Find sourcepaths in Hyper-V WriterMetaData
|
||||
var m_backup_wmd = m_backup.WriterMetadata.FirstOrDefault(o => o.WriterId.Equals(HyperVWriterGuid));
|
||||
if (m_backup_wmd != null)
|
||||
foreach (var component in m_backup_wmd.Components)
|
||||
{
|
||||
//For all the components found cross reference the requested Hyper-V Machines to backup
|
||||
//Cross reference the requested Hyper-V Machines to backup and add the sources
|
||||
if (!_hyperVMachines.ContainsKey(component.ComponentName)) continue;
|
||||
//Each component is in fact a Hyper-V Machine, which contains several files.
|
||||
int m_sourcepathsStartPos = m_sourcepaths.Length;
|
||||
int i = 0;
|
||||
Array.Resize(ref m_sourcepaths, m_sourcepaths.Length + component.Files.Count());
|
||||
@@ -159,7 +162,7 @@ namespace Duplicati.Library.Snapshots
|
||||
//Now clean up the sourcepaths
|
||||
m_sourcepaths = m_sourcepaths.Where(x => !string.IsNullOrEmpty(x)).ToArray();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
m_backup.FreeWriterMetadata();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user