diff --git a/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/HypervResource.csproj b/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/HypervResource.csproj
index ec4456881cf..8bebfffbeef 100644
--- a/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/HypervResource.csproj
+++ b/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/HypervResource.csproj
@@ -87,6 +87,11 @@
+
+ Always
+
+
+
{db824727-bdc3-437c-a364-7a811d8a160f}
WmiWrappers
diff --git a/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/HypervResourceController.cs b/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/HypervResourceController.cs
index 52307af4209..0f084dbe679 100644
--- a/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/HypervResourceController.cs
+++ b/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/HypervResourceController.cs
@@ -107,6 +107,21 @@ namespace HypervResource
config.Save(ConfigurationSaveMode.Modified);
ConfigurationManager.RefreshSection("appSettings");
}
+
+ public List getAllPrimaryStorages()
+ {
+ List poolPaths = new List();
+ Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
+ KeyValueConfigurationCollection settings = config.AppSettings.Settings;
+ foreach (string key in settings.AllKeys)
+ {
+ if (key.Contains("primary_storage_"))
+ {
+ poolPaths.Add(settings[key].Value);
+ }
+ }
+ return poolPaths;
+ }
}
///
@@ -775,16 +790,67 @@ namespace HypervResource
using (log4net.NDC.Push(Guid.NewGuid().ToString()))
{
logger.Info(CloudStackTypes.CheckOnHostCommand + Utils.CleanString(cmd.ToString()));
+ string details = "host is not alive";
+ bool result = true;
+ try
+ {
+ foreach (string poolPath in config.getAllPrimaryStorages())
+ {
+ if (IsHostAlive(poolPath, (string)cmd.host.privateNetwork.ip))
+ {
+ result = false;
+ details = "host is alive";
+ break;
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ logger.Error("Error Occurred in " + CloudStackTypes.CheckOnHostCommand + " : " + e.Message);
+ }
+
object ansContent = new
{
- result = true,
- details = "resource is alive",
+ result = result,
+ details = details,
contextMap = contextMap
};
return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.CheckOnHostAnswer);
}
}
+ private bool IsHostAlive(string poolPath, string privateIp)
+ {
+ bool hostAlive = false;
+ try
+ {
+ string hbFile = Path.Combine(poolPath, "hb-" + privateIp);
+ FileInfo file = new FileInfo(hbFile);
+ using (StreamReader sr = file.OpenText())
+ {
+ string epoch = sr.ReadLine();
+ string[] dateTime = epoch.Split('@');
+ string[] date = dateTime[0].Split('-');
+ string[] time = dateTime[1].Split(':');
+ DateTime epochTime = new DateTime(Convert.ToInt32(date[0]), Convert.ToInt32(date[1]), Convert.ToInt32(date[2]), Convert.ToInt32(time[0]),
+ Convert.ToInt32(time[1]), Convert.ToInt32(time[2]), DateTimeKind.Utc);
+ DateTime currentTime = DateTime.UtcNow;
+ DateTime ThreeMinuteLaterEpoch = epochTime.AddMinutes(3);
+ if (currentTime.CompareTo(ThreeMinuteLaterEpoch) < 0)
+ {
+ hostAlive = true;
+ }
+ sr.Close();
+ }
+ }
+ catch (Exception e)
+ {
+ logger.Info("Exception occurred in verifying host " + e.Message);
+ }
+
+ return hostAlive;
+ }
+
// POST api/HypervResource/CheckSshCommand
// TODO: create test
[HttpPost]
@@ -956,6 +1022,27 @@ namespace HypervResource
contextMap = contextMap
};
+ if (result)
+ {
+ try
+ {
+ if ((bool)cmd.add)
+ {
+ logger.Info("Adding HeartBeat Task to task scheduler for pool " + (string)cmd.pool.uuid);
+ Utils.AddHeartBeatTask((string)cmd.pool.uuid, hostPath, config.PrivateIpAddress);
+ }
+ else
+ {
+ logger.Info("Deleting HeartBeat Task from task scheduler for pool " + (string)cmd.pool.uuid);
+ Utils.RemoveHeartBeatTask(cmd.pool.uuid);
+ }
+ }
+ catch (Exception e)
+ {
+ logger.Error("Error occurred in adding/delete HeartBeat Task to/from Task Scheduler : " + e.Message);
+ }
+ }
+
return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.ModifyStoragePoolAnswer);
}
}
@@ -2151,6 +2238,7 @@ namespace HypervResource
// Insert networking details
string privateIpAddress = strtRouteCmd.privateIpAddress;
+ config.PrivateIpAddress = privateIpAddress;
string subnet;
System.Net.NetworkInformation.NetworkInterface privateNic = GetNicInfoFromIpAddress(privateIpAddress, out subnet);
strtRouteCmd.privateIpAddress = privateIpAddress;
diff --git a/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/Utils.cs b/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/Utils.cs
index 5ddcbef2b96..d0d3d838288 100644
--- a/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/Utils.cs
+++ b/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/Utils.cs
@@ -24,6 +24,8 @@ using System.Runtime.InteropServices;
using System.Security.Principal;
using System.Text;
using System.Threading.Tasks;
+using System.Diagnostics;
+using System.Reflection;
namespace HypervResource
{
@@ -31,6 +33,9 @@ namespace HypervResource
{
private static ILog s_logger = LogManager.GetLogger(typeof(Utils));
+ private const string TASK_PREFIX = "cloudstack-heartbeat-";
+ private const string BATCH_FILE = "heartbeat.bat";
+
///
/// Associate CloudStack object's content with a fully qualified type name.
///
@@ -174,6 +179,44 @@ namespace HypervResource
return cleanString;
}
+ public static void AddHeartBeatTask(string poolGuid, string poolPath, string hostPrivateIp)
+ {
+ string taskName = TASK_PREFIX + poolGuid;
+ UriBuilder uri = new UriBuilder(Assembly.GetExecutingAssembly().CodeBase);
+ string alocation = Uri.UnescapeDataString(uri.Path);
+ string batchFileLocation = Path.Combine(Path.GetDirectoryName(alocation), BATCH_FILE);
+ string hbFile = Path.Combine(poolPath, "hb-" + hostPrivateIp);
+ ExecuteTask("schtasks.exe", "/Create /RU \"SYSTEM\" /SC MINUTE /MO 1 /TN " + taskName + " /F /TR \"" + batchFileLocation + " " + hbFile + "\"");
+ }
+
+ public static void RemoveHeartBeatTask(string poolGuid)
+ {
+ string taskName = TASK_PREFIX + poolGuid;
+ ExecuteTask("schtasks.exe", "/Delete /TN " + taskName + " /F");
+ }
+
+ public static void ExecuteTask(string command, string args)
+ {
+ ProcessStartInfo startInfo = new ProcessStartInfo();
+ startInfo.CreateNoWindow = false;
+ startInfo.UseShellExecute = true;
+ startInfo.FileName = command;
+ startInfo.WindowStyle = ProcessWindowStyle.Hidden;
+ startInfo.Arguments = args;
+
+ try
+ {
+ using (Process exeProcess = Process.Start(startInfo))
+ {
+ exeProcess.WaitForExit();
+ }
+ }
+ catch (Exception e)
+ {
+ s_logger.Error("Error occurred in deleting or adding a scheduled task " + e.Message);
+ }
+ }
+
// from http://stackoverflow.com/a/2541569/939250
#region imports
[DllImport("advapi32.dll", SetLastError = true)]
diff --git a/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/heartbeat.bat b/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/heartbeat.bat
new file mode 100644
index 00000000000..85f6e7b8fbe
--- /dev/null
+++ b/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/heartbeat.bat
@@ -0,0 +1,23 @@
+@REM Licensed to the Apache Software Foundation (ASF) under one
+@REM or more contributor license agreements. See the NOTICE file
+@REM distributed with this work for additional information
+@REM regarding copyright ownership. The ASF licenses this file
+@REM to you under the Apache License, Version 2.0 (the
+@REM "License"); you may not use this file except in compliance
+@REM with the License. You may obtain a copy of the License at
+@REM
+@REM http://www.apache.org/licenses/LICENSE-2.0
+@REM
+@REM Unless required by applicable law or agreed to in writing,
+@REM software distributed under the License is distributed on an
+@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+@REM KIND, either express or implied. See the License for the
+@REM specific language governing permissions and limitations
+@REM under the License.
+@REM
+@echo off
+@REM This script is based on:
+@REM http://stackoverflow.com/questions/9871499/how-to-get-utc-time-with-windows-batch-file
+
+for /f %%x in ('wmic path win32_utctime get /format:list ^| findstr "="') do set %%x
+echo %Year%-%Month%-%Day%@%Hour%:%Minute%:%Second%>%1
\ No newline at end of file