From 8de8d12ada8624eda5cab4aa7d07090a731780ac Mon Sep 17 00:00:00 2001 From: FloatingMilkshake Date: Tue, 9 Apr 2024 12:20:31 -0400 Subject: [PATCH] fix package update check message, optimize some things - fix an issue where the package update check message would only contain an asterisk for a host if there was a pending restart but all packages were up-to-date - create an object for holding update check results - remove `bool isPeriodicCheck` argument from `PackageUpdateCheck()`; move logic to timed task instead - adjust package update check output format in `/debug checks` --- Checks/PackageUpdateChecks.cs | 66 +++++++++++-------- .../Owner/HomeServerCommands/DebugCommands.cs | 12 +--- Entities/UpdateCheckResult.cs | 14 ++++ Program.cs | 6 +- 4 files changed, 59 insertions(+), 39 deletions(-) create mode 100644 Entities/UpdateCheckResult.cs diff --git a/Checks/PackageUpdateChecks.cs b/Checks/PackageUpdateChecks.cs index 58fdfa8..70fe42f 100644 --- a/Checks/PackageUpdateChecks.cs +++ b/Checks/PackageUpdateChecks.cs @@ -1,18 +1,22 @@ -namespace MechanicalMilkshake.Checks; +using Microsoft.VisualBasic.CompilerServices; + +namespace MechanicalMilkshake.Checks; public class PackageUpdateChecks { - public static async Task<(int numhostsChecked, int totalNumHosts, string checkResult)> - PackageUpdateCheck(bool isPeriodicCheck) + public static async Task<(int numhostsChecked, int totalNumHosts, string checkResult)> PackageUpdateCheck() { var numHostsChecked = 0; var totalNumHosts = Program.ConfigJson.Base.SshHosts.Length; if (totalNumHosts == 0) return (0, 0, ""); + + List updateCheckResults = []; var updatesAvailableResponse = ""; var updatesAvailable = false; var restartRequired = false; + var numPackageUpdates = 0; foreach (var rawHost in Program.ConfigJson.Base.SshHosts) { @@ -42,31 +46,27 @@ public class PackageUpdateChecks "[PackageUpdateCheck] Error:\n{Error}", cmdResult.Error); if (string.IsNullOrWhiteSpace(cmdResult.Output)) continue; + + // Get hostname of machine + Regex hostnamePattern = new(@"[A-Za-z0-9-]+\@([A-Za-z0-9-]+)"); + var hostnameMatch = hostnamePattern.Match(host); + var hostname = hostnameMatch.Groups[1].Value; if (cmdResult.Output.Contains(" can be upgraded")) { - // Get hostname of machine - Regex hostnamePattern = new(@"[A-Za-z0-9-]+\@([A-Za-z0-9-]+)"); - var hostnameMatch = hostnamePattern.Match(host); - var hostname = hostnameMatch.Groups[1].Value; - // Get number of packages that can be upgraded - Regex numPackageUpdatesPattern = new(@"([0-9]+) packages can be upgraded"); + Regex numPackageUpdatesPattern = new(@"([0-9]+) package[s]? can be upgraded"); var numPackageUpdatesMatch = numPackageUpdatesPattern.Match(cmdResult.Output); - var numPackageUpdates = numPackageUpdatesMatch.Groups[1].Value; - - updatesAvailableResponse += - $"{hostname}: {numPackageUpdates} package{(int.Parse(numPackageUpdates) > 1 ? "s" : "")}"; + var numPackageUpdatesStr = numPackageUpdatesMatch.Groups[1].Value; + numPackageUpdates = numPackageUpdatesStr == "" ? 0 : int.Parse(numPackageUpdatesStr); updatesAvailable = true; } if (cmdResult.Output.Contains("System restart required")) - { - updatesAvailableResponse += "*"; restartRequired = true; - } - - updatesAvailableResponse += "\n"; + + // assemble result & add to list + updateCheckResults.Add(new UpdateCheckResult(hostname, numPackageUpdates, restartRequired)); numHostsChecked++; } @@ -76,19 +76,27 @@ public class PackageUpdateChecks if (updatesAvailable || restartRequired) { - string restartRequiredMessage = ""; - if (restartRequired) - restartRequiredMessage = " Hosts marked with a * require a restart to apply updates."; + var restartRequiredMessage = restartRequired + ? "A restart is required on some hosts (\\*) to apply updates." + : ""; - if (updatesAvailable) - updatesAvailableResponse = $"Package updates are available.{restartRequiredMessage}\n{updatesAvailableResponse}"; - - var ownerMention = - Program.Discord.CurrentApplication.Owners.Aggregate("", - (current, user) => current + user.Mention + " "); + var updatesAvailableMessage = updatesAvailable + ? "Package updates are available." + : ""; - var response = updatesAvailableResponse; - if (isPeriodicCheck) await Program.HomeChannel.SendMessageAsync($"{ownerMention.Trim()}\n{response}"); + var hostsWithUpdates = ""; + foreach (var result in updateCheckResults) + { + if (result.UpdateCount > 0 || result.RestartRequired) + { + hostsWithUpdates += $"{result.Hostname}{(result.RestartRequired ? "\\*" : "")}"; + + if (result.UpdateCount > 0) + hostsWithUpdates += $": {result.UpdateCount} update{(result.UpdateCount > 1 ? "s" : "")}"; + } + } + + updatesAvailableResponse = $"{updatesAvailableMessage} {restartRequiredMessage}\n{hostsWithUpdates}"; } return (numHostsChecked, totalNumHosts, updatesAvailableResponse); diff --git a/Commands/Owner/HomeServerCommands/DebugCommands.cs b/Commands/Owner/HomeServerCommands/DebugCommands.cs index eb6bf6a..5856033 100644 --- a/Commands/Owner/HomeServerCommands/DebugCommands.cs +++ b/Commands/Owner/HomeServerCommands/DebugCommands.cs @@ -157,7 +157,7 @@ public static async Task DebugChecks(InteractionContext ctx, case "all": (numRemindersBefore, numRemindersAfter, numRemindersSent, numRemindersFailed, numRemindersWithNullTime) = await ReminderChecks.CheckRemindersAsync(); - (numHostsChecked, totalNumHosts, checkResult) = await PackageUpdateChecks.PackageUpdateCheck(false); + (numHostsChecked, totalNumHosts, checkResult) = await PackageUpdateChecks.PackageUpdateCheck(); dbPing = await DatabaseChecks.CheckDatabaseConnectionAsync(); break; case "reminders": @@ -168,7 +168,7 @@ public static async Task DebugChecks(InteractionContext ctx, dbPing = await DatabaseChecks.CheckDatabaseConnectionAsync(); break; case "packageUpdates": - (numHostsChecked, totalNumHosts, checkResult) = await PackageUpdateChecks.PackageUpdateCheck(false); + (numHostsChecked, totalNumHosts, checkResult) = await PackageUpdateChecks.PackageUpdateCheck(); break; } @@ -188,15 +188,9 @@ public static async Task DebugChecks(InteractionContext ctx, // package updates var packageUpdateCheckResultMessage = "**Package Updates:** " + (totalNumHosts == 0 ? "No hosts to check for package updates.\n" - : $"Checked `{numHostsChecked}`/`{totalNumHosts}` hosts for package updates.\n"); + : $"Checked `{numHostsChecked}`/`{totalNumHosts}` hosts for package updates.\n> "); if (numHostsChecked != 0 && checkResult is not null) - { - if (packageUpdateCheckResultMessage.EndsWith('\n')) - packageUpdateCheckResultMessage = packageUpdateCheckResultMessage[..^1] + " "; packageUpdateCheckResultMessage += $"{checkResult.Replace("\n", "\n> ")}"; - if (packageUpdateCheckResultMessage.EndsWith("\n> ")) - packageUpdateCheckResultMessage = packageUpdateCheckResultMessage[..^3]; - } // set up response msg content // include relevant check results (see variables) diff --git a/Entities/UpdateCheckResult.cs b/Entities/UpdateCheckResult.cs new file mode 100644 index 0000000..490833a --- /dev/null +++ b/Entities/UpdateCheckResult.cs @@ -0,0 +1,14 @@ +namespace MechanicalMilkshake.Entities; + +public class UpdateCheckResult +{ + public UpdateCheckResult(string hostname, int updateCount, bool restartRequired) + { + Hostname = hostname; + UpdateCount = updateCount; + RestartRequired = restartRequired; + } + public string Hostname { get; } + public int UpdateCount { get; } + public bool RestartRequired { get; } +} \ No newline at end of file diff --git a/Program.cs b/Program.cs index 16dc9fa..41ce836 100644 --- a/Program.cs +++ b/Program.cs @@ -266,7 +266,11 @@ internal static async Task Main() { while (true) { - await PackageUpdateChecks.PackageUpdateCheck(true); + var (_, _, checkResult) = await PackageUpdateChecks.PackageUpdateCheck(); + var ownerMention = + Discord.CurrentApplication.Owners.Aggregate("", (current, user) => current + user.Mention + " "); + await HomeChannel.SendMessageAsync($"{ownerMention.Trim()}\n{checkResult}"); + await Task.Delay(259200000); // 3 days } // ReSharper disable once FunctionNeverReturns