diff --git a/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/HypervResourceController.cs b/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/HypervResourceController.cs index 6d5c599c2a3..0d56fef0acd 100644 --- a/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/HypervResourceController.cs +++ b/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/HypervResourceController.cs @@ -203,7 +203,7 @@ namespace HypervResource if (dataStore.nfsDataStoreTO != null) { NFSTO share = dataStore.nfsDataStoreTO; - Utils.connectToRemote(share.UncPath, share.Domain, share.User, share.Password); + 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); @@ -763,23 +763,40 @@ namespace HypervResource logger.Info(CloudStackTypes.ModifyStoragePoolCommand + cmd.ToString()); string details = null; string localPath; + StoragePoolType poolType; object ansContent; - bool result = ValidateStoragePoolCommand(cmd, out localPath, ref details); + bool result = ValidateStoragePoolCommand(cmd, out localPath, out poolType, ref details); if (!result) { ansContent = new - { - result = result, - details = details - }; + { + result = result, + details = details + }; return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.Answer); } var tInfo = new Dictionary(); - long capacityBytes; - long availableBytes; - GetCapacityForLocalPath(localPath, out capacityBytes, out availableBytes); + long capacityBytes = 0; + long availableBytes = 0; + if (poolType == StoragePoolType.Filesystem) + { + GetCapacityForLocalPath(localPath, out capacityBytes, out availableBytes); + } + else if (poolType == StoragePoolType.NetworkFilesystem) + { + NFSTO share = new NFSTO(); + String uriStr = "cifs://" + (string)cmd.pool.host + (string)cmd.pool.path; + share.uri = new Uri(uriStr); + // Check access to share. + Utils.ConnectToRemote(share.UncPath, share.Domain, share.User, share.Password); + Utils.GetShareDetails(share.UncPath, out capacityBytes, out availableBytes); + } + else + { + result = false; + } String uuid = null; var poolInfo = new @@ -794,34 +811,37 @@ namespace HypervResource }; ansContent = new - { - result = result, - details = details, - templateInfo = tInfo, - poolInfo = poolInfo - }; + { + result = result, + details = details, + templateInfo = tInfo, + poolInfo = poolInfo + }; + return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.ModifyStoragePoolAnswer); } } - private bool ValidateStoragePoolCommand(dynamic cmd, out string localPath, ref string details) + private bool ValidateStoragePoolCommand(dynamic cmd, out string localPath, out StoragePoolType poolType, ref string details) { dynamic pool = cmd.pool; string poolTypeStr = pool.type; - StoragePoolType poolType; localPath = cmd.localPath; - if (!Enum.TryParse(poolTypeStr, out poolType) || poolType != StoragePoolType.Filesystem) + if (!Enum.TryParse(poolTypeStr, out poolType)) { details = "Request to create / modify unsupported pool type: " + (poolTypeStr == null ? "NULL" : poolTypeStr) + "in cmd " + JsonConvert.SerializeObject(cmd); logger.Error(details); return false; } - if (!Directory.Exists(localPath)) + + if (poolType != StoragePoolType.Filesystem && + poolType != StoragePoolType.NetworkFilesystem) { - details = "Request to create / modify unsupported StoragePoolType.Filesystem with non-existent path:" + (localPath == null ? "NULL" : localPath) + "in cmd " + JsonConvert.SerializeObject(cmd); + details = "Request to create / modify unsupported pool type: " + (poolTypeStr == null ? "NULL" : poolTypeStr) + "in cmd " + JsonConvert.SerializeObject(cmd); logger.Error(details); return false; } + return true; } @@ -1385,6 +1405,70 @@ namespace HypervResource } } + // POST api/HypervResource/PrepareForMigrationCommand + [HttpPost] + [ActionName(CloudStackTypes.PrepareForMigrationCommand)] + public JContainer PrepareForMigrationCommand([FromBody]dynamic cmd) + { + using (log4net.NDC.Push(Guid.NewGuid().ToString())) + { + logger.Info(CloudStackTypes.PrepareForMigrationCommand + cmd.ToString()); + + string details = null; + bool result = false; + + try + { + details = "NOP - failure"; + } + catch (Exception sysEx) + { + details = CloudStackTypes.PrepareForMigrationCommand + " failed due to " + sysEx.Message; + logger.Error(details, sysEx); + } + + object ansContent = new + { + result = result, + details = details + }; + + return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.PrepareForMigrationAnswer); + } + } + + // POST api/HypervResource/MigrateCommand + [HttpPost] + [ActionName(CloudStackTypes.MigrateCommand)] + public JContainer MigrateCommand([FromBody]dynamic cmd) + { + using (log4net.NDC.Push(Guid.NewGuid().ToString())) + { + logger.Info(CloudStackTypes.MigrateCommand + cmd.ToString()); + + string details = null; + bool result = false; + + try + { + details = "NOP - failure"; + } + catch (Exception sysEx) + { + details = CloudStackTypes.MigrateCommand + " failed due to " + sysEx.Message; + logger.Error(details, sysEx); + } + + object ansContent = new + { + result = result, + details = details + }; + + return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.MigrateAnswer); + } + } + // POST api/HypervResource/StartupCommand [HttpPost] [ActionName(CloudStackTypes.StartupCommand)] diff --git a/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/Utils.cs b/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/Utils.cs index cc2b6673fd6..0f7505d67d8 100644 --- a/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/Utils.cs +++ b/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/Utils.cs @@ -113,7 +113,7 @@ namespace HypervResource } } - public static void connectToRemote(string remoteUNC, string domain, string username, string password) + public static void ConnectToRemote(string remoteUNC, string domain, string username, string password) { NETRESOURCE nr = new NETRESOURCE(); nr.dwType = RESOURCETYPE_DISK; @@ -130,7 +130,7 @@ namespace HypervResource } } - public static void disconnectRemote(string remoteUNC) + public static void DisconnectRemote(string remoteUNC) { int ret = WNetCancelConnection2(remoteUNC, CONNECT_UPDATE_PROFILE, false); if (ret != NO_ERROR) @@ -139,6 +139,21 @@ namespace HypervResource } } + public static void GetShareDetails(string remoteUNC, out long capacity, out long available) + { + ulong freeBytesAvailable; + ulong totalNumberOfBytes; + ulong totalNumberOfFreeBytes; + + if (!GetDiskFreeSpaceEx(remoteUNC, out freeBytesAvailable, out totalNumberOfBytes, out totalNumberOfFreeBytes)) + { + throw new ArgumentException("Not able to retrieve the capcity details of the share " + remoteUNC); + } + + available = freeBytesAvailable > 0 ? (long)freeBytesAvailable : 0; + capacity = totalNumberOfBytes > 0 ? (long)totalNumberOfBytes : 0; + } + // from http://stackoverflow.com/a/2541569/939250 #region imports [DllImport("advapi32.dll", SetLastError = true)] @@ -156,6 +171,12 @@ namespace HypervResource [DllImport("Mpr.dll")] private static extern int WNetCancelConnection2(string lpName, int dwFlags, bool fForce); + + [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)] + private static extern bool GetDiskFreeSpaceEx(string lpDirectoryName, + out ulong lpFreeBytesAvailable, + out ulong lpTotalNumberOfBytes, + out ulong lpTotalNumberOfFreeBytes); #endregion #region consts