Fixing the implementation for AttachCommand and DetachCommand in hyperv agent.

Also implemented RebootCommand for rebooting an instance on hyperv host.
This commit is contained in:
Devdeep Singh 2013-11-07 13:13:39 +05:30
parent 7095ea2b5e
commit e77ab38543
4 changed files with 260 additions and 30 deletions

View File

@ -279,6 +279,27 @@ namespace HypervResource
}
}
public class DiskTO
{
public string type;
public TemplateObjectTO templateObjectTO = null;
public static DiskTO ParseJson(dynamic json)
{
DiskTO result = null;
if (json != null)
{
result = new DiskTO()
{
templateObjectTO = TemplateObjectTO.ParseJson(json.data),
type = (string)json.type,
};
}
return result;
}
}
enum VolumeType
{
UNKNOWN,
@ -589,6 +610,7 @@ namespace HypervResource
public const string SwiftTO = "com.cloud.agent.api.to.SwiftTO";
public const string VirtualMachineTO = "com.cloud.agent.api.to.VirtualMachineTO";
public const string VolumeTO = "com.cloud.agent.api.to.VolumeTO";
public const string DiskTO = "com.cloud.agent.api.to.DiskTO";
public const string InternalErrorException = "com.cloud.exception.InternalErrorException";
public const string HostType = "com.cloud.host.Host.Type";
public const string HypervisorType = "com.cloud.hypervisor.Hypervisor.HypervisorType";

View File

@ -196,7 +196,19 @@ namespace HypervResource
try
{
string vmName = (string)cmd.vmName;
result = true;
DiskTO disk = DiskTO.ParseJson(cmd.disk);
TemplateObjectTO dataStore = disk.templateObjectTO;
if (dataStore.nfsDataStoreTO != null)
{
NFSTO share = dataStore.nfsDataStoreTO;
Utils.connectToRemote(share.UncPath, share.Domain, share.User, share.Password);
// The share is mapped, now attach the iso
string isoPath = Path.Combine(share.UncPath.Replace('/', Path.DirectorySeparatorChar), dataStore.path);
wmiCallsV2.AttachIso(vmName, isoPath);
result = true;
}
}
catch (Exception sysEx)
{
@ -229,7 +241,18 @@ namespace HypervResource
try
{
string vmName = (string)cmd.vmName;
result = true;
DiskTO disk = DiskTO.ParseJson(cmd.disk);
TemplateObjectTO dataStore = disk.templateObjectTO;
if (dataStore.nfsDataStoreTO != null)
{
NFSTO share = dataStore.nfsDataStoreTO;
// The share is mapped, now attach the iso
string isoPath = Path.Combine(share.UncPath.Replace('/', Path.DirectorySeparatorChar),
dataStore.path.Replace('/', Path.DirectorySeparatorChar));
wmiCallsV2.DetachDisk(vmName, isoPath);
result = true;
}
}
catch (Exception sysEx)
{
@ -247,6 +270,49 @@ namespace HypervResource
}
}
// POST api/HypervResource/RebootCommand
[HttpPost]
[ActionName(CloudStackTypes.RebootCommand)]
public JContainer RebootCommand([FromBody]dynamic cmd)
{
using (log4net.NDC.Push(Guid.NewGuid().ToString()))
{
logger.Info(CloudStackTypes.RebootCommand + cmd.ToString());
string details = null;
bool result = false;
try
{
string vmName = (string)cmd.vmName;
var sys = wmiCallsV2.GetComputerSystem(vmName);
if (sys == null)
{
details = CloudStackTypes.RebootCommand + " requested unknown VM " + vmName;
logger.Error(details);
}
else
{
wmiCallsV2.SetState(sys, RequiredState.Reset);
result = true;
}
}
catch (Exception sysEx)
{
details = CloudStackTypes.RebootCommand + " failed due to " + sysEx.Message;
logger.Error(details, sysEx);
}
object ansContent = new
{
result = result,
details = details
};
return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.RebootAnswer);
}
}
// POST api/HypervResource/DestroyCommand
[HttpPost]
[ActionName(CloudStackTypes.DestroyCommand)]

View File

@ -66,30 +66,30 @@ namespace HypervResource
bool isSuccess = LogonUser(cifsShareDetails.User, cifsShareDetails.Domain, cifsShareDetails.Password, LOGON32_LOGON_NEW_CREDENTIALS, LOGON32_PROVIDER_DEFAULT, ref token);
using (WindowsImpersonationContext remoteIdentity = new WindowsIdentity(token).Impersonate())
{
String dest = "";
if (filePathRelativeToShare.EndsWith(".iso") || filePathRelativeToShare.EndsWith(".vhd") || filePathRelativeToShare.EndsWith(".vhdx"))
{
dest = Path.Combine(cifsShareDetails.UncPath, filePathRelativeToShare);
dest = dest.Replace('/', Path.DirectorySeparatorChar);
}
// if the filePathRelativeToShare string don't have filename and only a dir point then find the vhd files in that folder and use
// In the clean setup, first copy command wont be having the filename it contains onlyu dir path.
// we need to scan the folder point and then copy the file to destination.
else if (!filePathRelativeToShare.EndsWith(".vhd") || !filePathRelativeToShare.EndsWith(".vhdx"))
{
// scan the folder and get the vhd filename.
String uncPath = Path.Combine(cifsShareDetails.UncPath, Path.Combine(filePathRelativeToShare.Split('/')));
//uncPath = uncPath.Replace("/", "\\");
DirectoryInfo dir = new DirectoryInfo(uncPath);
FileInfo[] vhdFiles = dir.GetFiles("*.vhd*");
if (vhdFiles.Length > 0)
{
FileInfo file = vhdFiles[0];
dest = file.FullName;
}
}
s_logger.Info(CloudStackTypes.CopyCommand + ": copy " + Path.Combine(cifsShareDetails.UncPath, filePathRelativeToShare) + " to " + destFile);
String dest = "";
if (filePathRelativeToShare.EndsWith(".iso") || filePathRelativeToShare.EndsWith(".vhd") || filePathRelativeToShare.EndsWith(".vhdx"))
{
dest = Path.Combine(cifsShareDetails.UncPath, filePathRelativeToShare);
dest = dest.Replace('/', Path.DirectorySeparatorChar);
}
// if the filePathRelativeToShare string don't have filename and only a dir point then find the vhd files in that folder and use
// In the clean setup, first copy command wont be having the filename it contains onlyu dir path.
// we need to scan the folder point and then copy the file to destination.
else if (!filePathRelativeToShare.EndsWith(".vhd") || !filePathRelativeToShare.EndsWith(".vhdx"))
{
// scan the folder and get the vhd filename.
String uncPath = Path.Combine(cifsShareDetails.UncPath, Path.Combine(filePathRelativeToShare.Split('/')));
//uncPath = uncPath.Replace("/", "\\");
DirectoryInfo dir = new DirectoryInfo(uncPath);
FileInfo[] vhdFiles = dir.GetFiles("*.vhd*");
if (vhdFiles.Length > 0)
{
FileInfo file = vhdFiles[0];
dest = file.FullName;
}
}
s_logger.Info(CloudStackTypes.CopyCommand + ": copy " + Path.Combine(cifsShareDetails.UncPath, filePathRelativeToShare) + " to " + destFile);
File.Copy(dest, destFile, true);
remoteIdentity.Undo();
}
@ -103,6 +103,32 @@ namespace HypervResource
}
}
public static void connectToRemote(string remoteUNC, string domain, string username, string password)
{
NETRESOURCE nr = new NETRESOURCE();
nr.dwType = RESOURCETYPE_DISK;
nr.lpRemoteName = remoteUNC.Replace('/', Path.DirectorySeparatorChar);
if (domain != null)
{
username = domain + @"\" + username;
}
int ret = WNetUseConnection(IntPtr.Zero, nr, password, username, 0, null, null, null);
if (ret != NO_ERROR)
{
throw new ArgumentException("net use of share " + remoteUNC + "failed with "+ getErrorForNumber(ret));
}
}
public static void disconnectRemote(string remoteUNC)
{
int ret = WNetCancelConnection2(remoteUNC, CONNECT_UPDATE_PROFILE, false);
if (ret != NO_ERROR)
{
throw new ArgumentException("net disconnect of share " + remoteUNC + "failed with " + getErrorForNumber(ret));
}
}
// from http://stackoverflow.com/a/2541569/939250
#region imports
[DllImport("advapi32.dll", SetLastError = true)]
@ -113,9 +139,16 @@ namespace HypervResource
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public extern static bool DuplicateToken(IntPtr existingTokenHandle, int SECURITY_IMPERSONATION_LEVEL, ref IntPtr duplicateTokenHandle);
[DllImport("Mpr.dll")]
private static extern int WNetUseConnection(IntPtr hwndOwner, NETRESOURCE lpNetResource, string lpPassword, string lpUserID, int dwFlags,
string lpAccessName, string lpBufferSize, string lpResult);
[DllImport("Mpr.dll")]
private static extern int WNetCancelConnection2(string lpName, int dwFlags, bool fForce);
#endregion
#region logon consts
#region consts
// logon types
const int LOGON32_LOGON_INTERACTIVE = 2;
const int LOGON32_LOGON_NETWORK = 3;
@ -126,6 +159,115 @@ namespace HypervResource
const int LOGON32_PROVIDER_WINNT50 = 3;
const int LOGON32_PROVIDER_WINNT40 = 2;
const int LOGON32_PROVIDER_WINNT35 = 1;
const int RESOURCE_CONNECTED = 0x00000001;
const int RESOURCE_GLOBALNET = 0x00000002;
const int RESOURCE_REMEMBERED = 0x00000003;
const int RESOURCETYPE_ANY = 0x00000000;
const int RESOURCETYPE_DISK = 0x00000001;
const int RESOURCETYPE_PRINT = 0x00000002;
const int RESOURCEDISPLAYTYPE_GENERIC = 0x00000000;
const int RESOURCEDISPLAYTYPE_DOMAIN = 0x00000001;
const int RESOURCEDISPLAYTYPE_SERVER = 0x00000002;
const int RESOURCEDISPLAYTYPE_SHARE = 0x00000003;
const int RESOURCEDISPLAYTYPE_FILE = 0x00000004;
const int RESOURCEDISPLAYTYPE_GROUP = 0x00000005;
const int RESOURCEUSAGE_CONNECTABLE = 0x00000001;
const int RESOURCEUSAGE_CONTAINER = 0x00000002;
const int CONNECT_INTERACTIVE = 0x00000008;
const int CONNECT_PROMPT = 0x00000010;
const int CONNECT_REDIRECT = 0x00000080;
const int CONNECT_UPDATE_PROFILE = 0x00000001;
const int CONNECT_COMMANDLINE = 0x00000800;
const int CONNECT_CMD_SAVECRED = 0x00001000;
const int CONNECT_LOCALDRIVE = 0x00000100;
#endregion
#region Errors
const int NO_ERROR = 0;
const int ERROR_ACCESS_DENIED = 5;
const int ERROR_ALREADY_ASSIGNED = 85;
const int ERROR_BAD_DEVICE = 1200;
const int ERROR_BAD_NET_NAME = 67;
const int ERROR_BAD_PROVIDER = 1204;
const int ERROR_CANCELLED = 1223;
const int ERROR_EXTENDED_ERROR = 1208;
const int ERROR_INVALID_ADDRESS = 487;
const int ERROR_INVALID_PARAMETER = 87;
const int ERROR_INVALID_PASSWORD = 1216;
const int ERROR_MORE_DATA = 234;
const int ERROR_NO_MORE_ITEMS = 259;
const int ERROR_NO_NET_OR_BAD_PATH = 1203;
const int ERROR_NO_NETWORK = 1222;
const int ERROR_BAD_PROFILE = 1206;
const int ERROR_CANNOT_OPEN_PROFILE = 1205;
const int ERROR_DEVICE_IN_USE = 2404;
const int ERROR_NOT_CONNECTED = 2250;
const int ERROR_OPEN_FILES = 2401;
private struct ErrorClass
{
public int num;
public string message;
public ErrorClass(int num, string message)
{
this.num = num;
this.message = message;
}
}
private static ErrorClass[] ERROR_LIST = new ErrorClass[] {
new ErrorClass(ERROR_ACCESS_DENIED, "Error: Access Denied"),
new ErrorClass(ERROR_ALREADY_ASSIGNED, "Error: Already Assigned"),
new ErrorClass(ERROR_BAD_DEVICE, "Error: Bad Device"),
new ErrorClass(ERROR_BAD_NET_NAME, "Error: Bad Net Name"),
new ErrorClass(ERROR_BAD_PROVIDER, "Error: Bad Provider"),
new ErrorClass(ERROR_CANCELLED, "Error: Cancelled"),
new ErrorClass(ERROR_EXTENDED_ERROR, "Error: Extended Error"),
new ErrorClass(ERROR_INVALID_ADDRESS, "Error: Invalid Address"),
new ErrorClass(ERROR_INVALID_PARAMETER, "Error: Invalid Parameter"),
new ErrorClass(ERROR_INVALID_PASSWORD, "Error: Invalid Password"),
new ErrorClass(ERROR_MORE_DATA, "Error: More Data"),
new ErrorClass(ERROR_NO_MORE_ITEMS, "Error: No More Items"),
new ErrorClass(ERROR_NO_NET_OR_BAD_PATH, "Error: No Net Or Bad Path"),
new ErrorClass(ERROR_NO_NETWORK, "Error: No Network"),
new ErrorClass(ERROR_BAD_PROFILE, "Error: Bad Profile"),
new ErrorClass(ERROR_CANNOT_OPEN_PROFILE, "Error: Cannot Open Profile"),
new ErrorClass(ERROR_DEVICE_IN_USE, "Error: Device In Use"),
new ErrorClass(ERROR_EXTENDED_ERROR, "Error: Extended Error"),
new ErrorClass(ERROR_NOT_CONNECTED, "Error: Not Connected"),
new ErrorClass(ERROR_OPEN_FILES, "Error: Open Files"),
};
private static string getErrorForNumber(int errNum)
{
foreach (ErrorClass er in ERROR_LIST)
{
if (er.num == errNum) return er.message;
}
return "Error: Unknown, " + errNum;
}
#endregion
[StructLayout(LayoutKind.Sequential)]
private class NETRESOURCE
{
public int dwScope = 0;
public int dwType = 0;
public int dwDisplayType = 0;
public int dwUsage = 0;
public string lpLocalName = "";
public string lpRemoteName = "";
public string lpComment = "";
public string lpProvider = "";
}
}
}

View File

@ -447,6 +447,7 @@ namespace HypervResource
pingReply = pingSender.Send(ipAddress, pingTimeout, buffer, pingOptions);
if (pingReply.Status == IPStatus.Success)
{
System.Threading.Thread.Sleep(30000);
return true;
}
else
@ -591,11 +592,11 @@ namespace HypervResource
}
string hostResource = item.HostResource[0];
if (!hostResource.Equals(diskFileName))
if (Path.Equals(hostResource, diskFileName))
{
continue;
imageToRemove = item;
break;
}
imageToRemove = item;
}
// assert
@ -739,7 +740,6 @@ namespace HypervResource
// Disk drives are attached to a 'Parent' IDE controller. We IDE Controller's settings for the 'Path', which our new Disk drive will use to reference it.
VirtualSystemSettingData vmSettings = GetVmSettings(vm);
var driveWmiObj = GetDvdDriveSettings(vmSettings);
InsertDiskImage(vm, isoPath, IDE_ISO_DISK, driveWmiObj.Path);
}