CLOUDSTACK-6401: [hyper-v] fixed correct host state, if host is up and hyper-v agent is down then the host state will be shown as up(actual host state) in cloudstack

This commit is contained in:
Anshul Gangwar 2014-04-14 02:32:56 -07:00 committed by Devdeep Singh
parent 3ec7497e1e
commit 55f53e13e8
4 changed files with 161 additions and 2 deletions

View File

@ -87,6 +87,11 @@
<None Include="packages.config" /> <None Include="packages.config" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="heartbeat.bat">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\WmiWrappers\WmiWrappers.csproj"> <ProjectReference Include="..\WmiWrappers\WmiWrappers.csproj">
<Project>{db824727-bdc3-437c-a364-7a811d8a160f}</Project> <Project>{db824727-bdc3-437c-a364-7a811d8a160f}</Project>
<Name>WmiWrappers</Name> <Name>WmiWrappers</Name>

View File

@ -107,6 +107,21 @@ namespace HypervResource
config.Save(ConfigurationSaveMode.Modified); config.Save(ConfigurationSaveMode.Modified);
ConfigurationManager.RefreshSection("appSettings"); ConfigurationManager.RefreshSection("appSettings");
} }
public List<string> getAllPrimaryStorages()
{
List<string> poolPaths = new List<string>();
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;
}
} }
/// <summary> /// <summary>
@ -775,16 +790,67 @@ namespace HypervResource
using (log4net.NDC.Push(Guid.NewGuid().ToString())) using (log4net.NDC.Push(Guid.NewGuid().ToString()))
{ {
logger.Info(CloudStackTypes.CheckOnHostCommand + Utils.CleanString(cmd.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 object ansContent = new
{ {
result = true, result = result,
details = "resource is alive", details = details,
contextMap = contextMap contextMap = contextMap
}; };
return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.CheckOnHostAnswer); 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 // POST api/HypervResource/CheckSshCommand
// TODO: create test // TODO: create test
[HttpPost] [HttpPost]
@ -956,6 +1022,27 @@ namespace HypervResource
contextMap = contextMap 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); return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.ModifyStoragePoolAnswer);
} }
} }
@ -2151,6 +2238,7 @@ namespace HypervResource
// Insert networking details // Insert networking details
string privateIpAddress = strtRouteCmd.privateIpAddress; string privateIpAddress = strtRouteCmd.privateIpAddress;
config.PrivateIpAddress = privateIpAddress;
string subnet; string subnet;
System.Net.NetworkInformation.NetworkInterface privateNic = GetNicInfoFromIpAddress(privateIpAddress, out subnet); System.Net.NetworkInformation.NetworkInterface privateNic = GetNicInfoFromIpAddress(privateIpAddress, out subnet);
strtRouteCmd.privateIpAddress = privateIpAddress; strtRouteCmd.privateIpAddress = privateIpAddress;

View File

@ -24,6 +24,8 @@ using System.Runtime.InteropServices;
using System.Security.Principal; using System.Security.Principal;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Diagnostics;
using System.Reflection;
namespace HypervResource namespace HypervResource
{ {
@ -31,6 +33,9 @@ namespace HypervResource
{ {
private static ILog s_logger = LogManager.GetLogger(typeof(Utils)); private static ILog s_logger = LogManager.GetLogger(typeof(Utils));
private const string TASK_PREFIX = "cloudstack-heartbeat-";
private const string BATCH_FILE = "heartbeat.bat";
/// <summary> /// <summary>
/// Associate CloudStack object's content with a fully qualified type name. /// Associate CloudStack object's content with a fully qualified type name.
/// </summary> /// </summary>
@ -174,6 +179,44 @@ namespace HypervResource
return cleanString; 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 // from http://stackoverflow.com/a/2541569/939250
#region imports #region imports
[DllImport("advapi32.dll", SetLastError = true)] [DllImport("advapi32.dll", SetLastError = true)]

View File

@ -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