mirror of
				https://github.com/apache/cloudstack.git
				synced 2025-10-26 08:42:29 +01:00 
			
		
		
		
	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:
		
							parent
							
								
									3ec7497e1e
								
							
						
					
					
						commit
						55f53e13e8
					
				| @ -86,6 +86,11 @@ | ||||
|   <ItemGroup> | ||||
|     <None Include="packages.config" /> | ||||
|   </ItemGroup> | ||||
|   <ItemGroup> | ||||
|     <None Include="heartbeat.bat"> | ||||
|       <CopyToOutputDirectory>Always</CopyToOutputDirectory> | ||||
|     </None> | ||||
|   </ItemGroup> | ||||
|   <ItemGroup> | ||||
|     <ProjectReference Include="..\WmiWrappers\WmiWrappers.csproj"> | ||||
|       <Project>{db824727-bdc3-437c-a364-7a811d8a160f}</Project> | ||||
|  | ||||
| @ -107,6 +107,21 @@ namespace HypervResource | ||||
|             config.Save(ConfigurationSaveMode.Modified); | ||||
|             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> | ||||
| @ -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; | ||||
|  | ||||
| @ -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"; | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Associate CloudStack object's content with a fully qualified type name. | ||||
|         /// </summary> | ||||
| @ -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)] | ||||
|  | ||||
| @ -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 | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user