commit 9ac196af3d4409e2d12740e1b1df4b5c7c5d38b6 Author: Enstrayed <48845980+Enstrayed@users.noreply.github.com> Date: Wed Nov 19 14:53:43 2025 -0800 init commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..cbbd0b5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +bin/ +obj/ \ No newline at end of file diff --git a/Program.cs b/Program.cs new file mode 100644 index 0000000..3d86122 --- /dev/null +++ b/Program.cs @@ -0,0 +1,74 @@ +// Libraries, liberals even +using System.Diagnostics; +using System.Net.Http; +using System.Net.Http.Json; +using System.Text; +using System.Text.Json; +using System.Text.Json.Serialization; + +// Local functions +var theHttpClient = new HttpClient(); +theHttpClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("rwYGDkbh52tXy62AbcCfBmppX"); + +string systemHostname = System.Environment.MachineName ?? "UNKNOWN_HOST"; + +async Task runProcess(string file, string args) +{ + var psi = new ProcessStartInfo + { + FileName = file, + Arguments = args, + RedirectStandardOutput = true, + RedirectStandardError = true, + UseShellExecute = false, + CreateNoWindow = true + }; + + using var process = Process.Start(psi) ?? throw new Exception("Error starting process (runProcess)"); + string processStdErr = await process.StandardError.ReadToEndAsync(); + if (processStdErr != "") + { + throw new Exception($"Process stderr was not empty: {processStdErr}"); + } + + string processStdOut = await process.StandardOutput.ReadToEndAsync(); + await process.WaitForExitAsync(); + return processStdOut; +} + +// Entrypoint +string queryPoolsStdOut = await runProcess("/usr/sbin/zpool","list -H"); + +List poolList = new List(); +foreach (string poolName in queryPoolsStdOut.Split("\n", StringSplitOptions.RemoveEmptyEntries)) +{ + string[] actualName = poolName.Split("\t"); + poolList.Add(actualName[0]); +} + +foreach (string poolName in poolList) +{ + string queryPoolInfoStdOut = await runProcess("/usr/sbin/zpool",$"status {poolName}"); + + var emailRequestBody = new emailRequestBodyTemplate { recipient = "nathan@enstrayed.com", subject = $"Zpool {poolName} on {systemHostname} is unhealthy", message = $"The pool {poolName} on {systemHostname} is no longer marked as healthy. Status output:\n\n{queryPoolInfoStdOut}"}; + var serializedEmailRequestBody = new StringContent(JsonSerializer.Serialize(emailRequestBody, emailRequestBodyContext.Default.emailRequestBodyTemplate), Encoding.UTF8, "application/json"); + + Console.WriteLine("Got to email send part"); + + HttpResponseMessage emailRequestResponse = await theHttpClient.PostAsync("https://enstrayed.com/api/sendemail", serializedEmailRequestBody); + + Console.WriteLine(emailRequestResponse.StatusCode.ToString()); +} + +// Classes +public class emailRequestBodyTemplate +{ + public required string recipient { get; set; } + public required string subject { get; set; } + public required string message { get; set; } +} + +[JsonSerializable(typeof(emailRequestBodyTemplate))] +internal partial class emailRequestBodyContext : JsonSerializerContext +{ +} \ No newline at end of file diff --git a/zpoolcheck.csproj b/zpoolcheck.csproj new file mode 100644 index 0000000..df3f6b3 --- /dev/null +++ b/zpoolcheck.csproj @@ -0,0 +1,17 @@ + + + + Exe + net9.0 + enable + enable + + + + true + true + linux-x64 + true + + + diff --git a/zpoolcheck.sln b/zpoolcheck.sln new file mode 100644 index 0000000..24540bc --- /dev/null +++ b/zpoolcheck.sln @@ -0,0 +1,24 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.5.2.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "zpoolcheck", "zpoolcheck.csproj", "{479E7CE9-BAA5-8B89-7B4F-333296E2F1A9}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {479E7CE9-BAA5-8B89-7B4F-333296E2F1A9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {479E7CE9-BAA5-8B89-7B4F-333296E2F1A9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {479E7CE9-BAA5-8B89-7B4F-333296E2F1A9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {479E7CE9-BAA5-8B89-7B4F-333296E2F1A9}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {B81ECAB6-E9E9-469D-8EB4-AA1D91F5E7BB} + EndGlobalSection +EndGlobal