// Spludlow Software // Copyright © Samuel P. Ludlow 2020 All Rights Reserved // Distributed under the terms of the GNU General Public License version 3 // Distributed WITHOUT ANY WARRANTY; without implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE // https://www.spludlow.co.uk/LICENCE.TXT // The Spludlow logo is a registered trademark of Samuel P. Ludlow and may not be used without permission // v1.14 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Data; using System.ServiceModel; namespace Spludlow { public class Status { public static string[] WatchedQueues(string host) { return (string[])Spludlow.Call.Now(host, "Spludlow", "Spludlow.Status", "WatchedQueues"); } public static string[] WatchedQueues() { List queueNames = new List(); DataTable serviceTable = QueryLocal().Tables[0]; foreach (DataRow threadRow in serviceTable.Select("Type = 'Spludlow.QueueProcessor'")) queueNames.Add((string)threadRow["Parameters"]); return queueNames.ToArray(); } private static string WebServiceAdminApplicationId = "Spludlow-WebService-Admin"; public static void ReStartAll(string host) { Spludlow.Call.Now(host, "Spludlow", "Spludlow.Status", "ReStartAll"); } public static void ReStartAll() { DataRow row = Spludlow.Config.Application(WebServiceAdminApplicationId); string hosted = (string)row["Hosted"]; // Admin Web Service now using new credential Spludlow.Admin.WebRecycle(hosted); Spludlow.Log.Info("ReStartAll; WebRecycled ADMIN: " + hosted); // New process will use new credential Spludlow.SpawnProcess.RunMethodNoWait("Spludlow", "Spludlow.Status", "ReStartAllProcess", new object[] { Spludlow.Release.UpdateMagic }); Spludlow.Log.Info("ReStartAll; SpawnProcess"); } public static void ReStartAllProcess(string updateMagic) { System.Threading.Thread.Sleep(1000); Spludlow.Log.Info("ReStartAll; ReStartAllProcess"); DataTable table = Spludlow.Config.Applications().Tables[0]; List webAppPools = new List(); List services = new List(); foreach (DataRow row in table.Rows) { if (row.IsNull("Hosted") == true) continue; string app = (string)row["ApplicationId"]; if (app == WebServiceAdminApplicationId) // Should have been restarted before process spawned continue; string appType = (string)row["ApplicationType"]; string hosted = (string)row["Hosted"]; if (appType == "Web") { if (webAppPools.Contains(hosted) == false) webAppPools.Add(hosted); } if (appType == "Service") { if (services.Contains(hosted) == false) services.Add(hosted); } } Spludlow.Log.Info("ReStartAll; before WebRecycles: " + webAppPools.Count); foreach (string webAppPool in webAppPools) { Spludlow.Admin.WebRecycle(webAppPool); Spludlow.Log.Info("ReStartAll; WebRecycled: " + webAppPool); } Spludlow.Log.Info("ReStartAll; after WebRecycles"); if (services.Count > 0) { foreach (string service in services) { try { Spludlow.Admin.ServiceStop(service); System.Threading.Thread.Sleep(0); Spludlow.Admin.ServiceStart(service); Spludlow.Log.Report("ReStartAll; Restarted Service:\t" + service); } catch (Exception ee) { Spludlow.Log.Error("ReStartAll; Restarting Service:\t" + service, ee); } } } Spludlow.Log.Info("ReStartAll; END"); } public static void StartStopped(string host) { Spludlow.Call.Now(host, "Spludlow", "Spludlow.Status", "StartStopped"); } public static void StartStopped() { Spludlow.SysTables.StatusDataTable table = (Spludlow.SysTables.StatusDataTable)QueryLocal().Tables[0]; bool iisStopped = false; List serviceProcesses = new List(); foreach (Spludlow.SysTables.StatusRow row in table.Rows) { if (row.IsTaskTypeNull() == true || row.IsHostedNull() == true || row.IsServiceStateNull() == true) { continue; } if (row.TaskType == "Web" && row.ServiceState == "Stopped") { iisStopped = true; continue; } if (row.TaskType != "Method" && row.TaskType != "Server") continue; if (row.ServiceState != "Stopped") continue; if (serviceProcesses.Contains(row.Hosted) == false) serviceProcesses.Add(row.Hosted); } if (iisStopped == true) serviceProcesses.Add("W3SVC"); if (serviceProcesses.Count > 0) Spludlow.Log.Warning("Status, StartStopped; Stopped Service Count:\t" + serviceProcesses.Count, new object[] { serviceProcesses.ToArray() }); foreach (string serviceProcess in serviceProcesses) { Spludlow.Admin.ServiceStart(serviceProcess); } table = (Spludlow.SysTables.StatusDataTable)QueryLocal().Tables[0]; List serviceThreads = new List(); foreach (Spludlow.SysTables.StatusRow row in table.Rows) { if (row.IsTaskTypeNull() == true || row.IsHostedNull() == true || row.IsServiceStateNull() == true) { continue; } if (row.TaskType != "Method") continue; if (row.ServiceState != "Running") { Spludlow.Log.Warning("Status, StartStopped; Service not running:\t" + row.Hosted); continue; } if (row.IsThreadStateNull() == true) { Spludlow.Log.Warning("Status, StartStopped; ThreadState is Null: " + row.Hosted + ", " + row.Thread); continue; } if (row.ThreadState != "Aborted" && row.ThreadState != "Stopped") continue; serviceThreads.Add(new string[] { row.Hosted, row.Thread }); } if (serviceThreads.Count > 0) Spludlow.Log.Warning("Status, StartStopped; Stopped Thread Count:\t" + serviceThreads.Count, new object[] { serviceThreads.ToArray() }); foreach (string[] words in serviceThreads) { string service = words[0]; string thread = words[1]; Spludlow.Log.Warning("Status, StartStopped; Starting Thread:\t" + service + ", " + thread); try { Spludlow.Service.StartThreadWork(service, thread); } catch (Exception ee) { Spludlow.Log.Error("Status, StartStopped; Starting Thread: " + service + ", " + thread, ee); } Spludlow.Log.Report("Status, StartStopped; Started Thread:\t" + service + ", " + thread); } table = (Spludlow.SysTables.StatusDataTable)QueryLocal().Tables[0]; List applicationPools = new List(); foreach (Spludlow.SysTables.StatusRow row in table.Rows) { if (row.IsTaskTypeNull() == true || row.IsHostedNull() == true || row.IsServiceStateNull() == true || row.IsThreadStateNull() == true) { continue; } if (row.TaskType != "Web") continue; if (row.ServiceState != "Running") { Spludlow.Log.Warning("Status, StartStopped; IIS not running:\t" + row.Hosted); continue; } if (row.ThreadState != "Stopped") continue; if (applicationPools.Contains(row.Hosted) == false) applicationPools.Add(row.Hosted); } if (applicationPools.Count > 0) Spludlow.Log.Warning("Status, StartStopped; Stopped Application Pool Count:\t" + applicationPools.Count, new object[] { applicationPools.ToArray() }); foreach (string applicationPool in applicationPools) { Spludlow.Log.Warning("Status, StartStopped; Starting Application Pool:\t" + applicationPool); Spludlow.Admin.WebStart(applicationPool); Spludlow.Log.Report("Status, StartStopped; Started Application Pool:\t" + applicationPool); } } public static DataSet Query() { return Query(Spludlow.Config.Hosts()); } public static DataSet Query(string[] hosts) { Spludlow.SysTables.StatusDataTable table = new SysTables.StatusDataTable(); Task[] tasks = new Task[hosts.Length]; for (int index = 0; index < hosts.Length; ++index) { string host = hosts[index]; tasks[index] = new Task(() => QueryWorker(table, host)); } foreach (Task task in tasks) task.Start(); Task.WaitAll(tasks); return Spludlow.Data.ADO.WireDataSet(table); } public static DataSet Query(string host) { Spludlow.SysTables.StatusDataTable table = new SysTables.StatusDataTable(); QueryWorker(table, host); return Spludlow.Data.ADO.WireDataSet(table); } private static void QueryWorker(Spludlow.SysTables.StatusDataTable table, string host) { DataSet dataSet = null; try { dataSet = (DataSet)Spludlow.Call.Now(host, "Spludlow", "Spludlow.Status", "QueryLocal", CallFlags.NonPersistent); } catch (Exception ee) { Spludlow.Log.Warning("Status QueryWorker Exception", ee, ee.Message); lock (table) { Spludlow.SysTables.StatusRow row = table.NewStatusRow(); row.HostId = host; row.OrganizationId = Spludlow.Config.OrganizationId(host); row.NetworkId = Spludlow.Config.NetworkId(host); row.LastErrorTime = DateTime.Now; row.LastError = ExceptionMessage(ee); table.Rows.Add(row); } } if (dataSet != null) { lock (table) { foreach (DataRow row in dataSet.Tables[0].Rows) table.ImportRow(row); } } } private static string ExceptionMessage(Exception ee) { string message = ee.Message; if (ee is ProtocolException && message.StartsWith("The content type text/html") == true) message = "ProtocolException: " + Spludlow.Text.ChopBetween(message, "", "", false); return message; } public static DataSet QueryLocal() { Spludlow.SysTables.StatusDataTable table = new SysTables.StatusDataTable(); Spludlow.SysTables.StatusDataTable tempTable = new SysTables.StatusDataTable(); DataTable applicationsTable = Spludlow.Config.Applications().Tables[0]; string organizationId = Spludlow.Config.Get("Spludlow.OrganizationId"); string networkId = Spludlow.Config.Get("Spludlow.NetworkId"); string hostId = Environment.MachineName; string iisStatus = "Not Available"; try { iisStatus = Spludlow.Admin.ServiceQuery("W3SVC"); } catch (Exception ee) { Spludlow.Log.Warning("Status, QueryLocal; Getting IIS Status", ee); } foreach (DataRow applicationRow in applicationsTable.Rows) { if (applicationRow.IsNull("Hosted") == true) // lib & process, skip continue; string appId = (string)applicationRow["ApplicationId"]; string appType = (string)applicationRow["ApplicationType"]; string hosted = (string)applicationRow["Hosted"]; int portNumber = 0; if (applicationRow.IsNull("PortNumber") == false) portNumber = (int)applicationRow["PortNumber"]; appType = appType.ToLower(); Spludlow.SysTables.StatusRow row = tempTable.NewStatusRow(); row.ApplicationId = appId; row.Hosted = hosted; try { switch (appType) { case "web": row.ServiceState = iisStatus; row.TaskType = "Web"; if (iisStatus == "Running") { row.ThreadState = Spludlow.Admin.WebQuery(hosted); if (hosted == "Spludlow-WebService") // Better way ?!!!!!!!!!!!!!!!!!!!!!!!!!!!!! not right app pool name ? { string[] webCheck = (string[])Spludlow.Call.Now(hostId, "Spludlow", "Spludlow.Status", "CheckWebService"); row.UserDomain = webCheck[0]; row.UserName = webCheck[1]; row.Architecture = webCheck[2]; } } break; case "service": row.TaskType = "Service"; string serviceStatus = Spludlow.Admin.ServiceQuery(hosted); row.ServiceState = serviceStatus; if (portNumber > 0) { DataTable serviceTable; if (serviceStatus == "Running") serviceTable = Spludlow.Service.StatusOnLine(appId).Tables[0]; else serviceTable = Spludlow.Service.StatusOffLine(appId).Tables[0]; foreach (DataRow serviceRow in serviceTable.Rows) { if (serviceRow.IsNull("QueueName") == false) serviceRow["QueueLength"] = Spludlow.MessageQueues.MessageCount((string)serviceRow["QueueName"]); serviceRow["ApplicationId"] = appId; serviceRow["Hosted"] = hosted; serviceRow["ServiceState"] = serviceStatus; table.ImportRow(serviceRow); } row = null; } break; default: throw new ApplicationException("Unknown application type:\t" + appType); } } catch (Exception ee) { Spludlow.Log.Warning("Status QueryLocal Exception", ee); row.LastErrorTime = DateTime.Now; row.LastError = ExceptionMessage(ee); } if (row != null) { tempTable.Rows.Add(row); table.ImportRow(row); } } foreach (Spludlow.SysTables.StatusRow row in table.Rows) { row.OrganizationId = organizationId; row.NetworkId = networkId; row.HostId = hostId; } return Spludlow.Data.ADO.WireDataSet(table); } public static Spludlow.SysTables.StatusRow NewStatusRow(Spludlow.SysTables.StatusDataTable table) { Spludlow.SysTables.StatusRow row = table.NewStatusRow(); table.Rows.Add(row); return row; } public static string[] CheckWebService() { string architecture = "64"; if (Environment.Is64BitProcess == false) architecture = "32"; return new string[] { Environment.UserDomainName, Environment.UserName, architecture }; } } }