From e2d0b70c8f71a0595487e8a5603696764e5bdff6 Mon Sep 17 00:00:00 2001 From: Steven Yates Date: Sun, 13 Aug 2023 14:23:59 +0100 Subject: [PATCH 1/8] Update ReadMe - Typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3cc9b38..2473ccf 100644 --- a/README.md +++ b/README.md @@ -286,4 +286,4 @@ Put nginx in front of it and proxy to 443->80 on the docker image 2. ??? ### What if a health check type isn't supported? -Create your own or raise an issue on github. Take a look at WSM.PluginExample to see how you write your own health check. Once you've compiled it, drop it into the clients install direction\HealthChecks alongside `WSM.HealthChecks.dll` +Create your own or raise an issue on github. Take a look at WSM.PluginExample to see how you write your own health check. Once you've compiled it, drop it into the clients install directory\HealthChecks alongside `WSM.HealthChecks.dll` From 852f609aa1be2bdda9dc63152e4303b46031a107 Mon Sep 17 00:00:00 2001 From: Steven Yates Date: Sun, 13 Aug 2023 14:50:23 +0100 Subject: [PATCH 2/8] Add free memory healthcheck --- README.md | 14 +- .../FreeMemoryHealthCheckConfiguration.cs | 9 ++ .../FreeMemoryHealthCheckDefinition.cs | 10 ++ .../FreeMemoryHealthCheckJob.cs | 129 ++++++++++++++++++ WSM.HealthChecks/WSM.HealthChecks.csproj | 1 + 5 files changed, 162 insertions(+), 1 deletion(-) create mode 100644 WSM.HealthChecks/FreeMemoryHealthCheck/FreeMemoryHealthCheckConfiguration.cs create mode 100644 WSM.HealthChecks/FreeMemoryHealthCheck/FreeMemoryHealthCheckDefinition.cs create mode 100644 WSM.HealthChecks/FreeMemoryHealthCheck/FreeMemoryHealthCheckJob.cs diff --git a/README.md b/README.md index 2473ccf..2874896 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ WSM is a service for monitoring different aspects of a Windows server and alerting when certain conditions are met. ### What can WSM monitor? -See [Health Check Types](#health-check-types) for more detail but in a nutshell processes, ports, docker containers and disk space & http request for now. +See [Health Check Types](#health-check-types) for more detail but in a nutshell processes, ports, docker containers and disk space, free memory & http request for now. ### Why? I had a server which ran lots of different services, Plex, Game services, VPN, DNS and a bunch of docker containers and something would periodically fail, I wouldn't usually find this out until someone using one of the versions let me know. I wanted a tool that was free, and super easy to set up but couldn't find one that did everything I wanted, also I like coding so figured it was a good candidate for a project, 3 days later WSM was born. @@ -272,6 +272,18 @@ Sends a HTTP request and check for the correct status code, it can also optional - `RequestBody` (Optional) - The payload that can be sent, make sure you change the `Method` to the appropriate value - `ExpectedResponseBody` (Optional) - An expected response body to validate upon request completion +### FreeMemory +Checks the system for free memory +```json +{ + "Name": "Free Memory", + "Type": "Free Memory", + "Interval": "00:01:00", + "MinimumFreeMemory": 100000 +} +``` +- `MinimumFreeMemory` (Required) - The minimum number of free bytes you expect the server to have + ### Installing the Windows service Run `install-service.ps1` inside `C:\wsm.client\`, this will install and start the service diff --git a/WSM.HealthChecks/FreeMemoryHealthCheck/FreeMemoryHealthCheckConfiguration.cs b/WSM.HealthChecks/FreeMemoryHealthCheck/FreeMemoryHealthCheckConfiguration.cs new file mode 100644 index 0000000..5ad742b --- /dev/null +++ b/WSM.HealthChecks/FreeMemoryHealthCheck/FreeMemoryHealthCheckConfiguration.cs @@ -0,0 +1,9 @@ +using WSM.Client.Models; + +namespace WSM.PluginExample +{ + public class FreeMemoryHealthCheckConfiguration: HealthCheckConfigurationBase + { + public long MinimumFreeMemory { get; set; } + } +} diff --git a/WSM.HealthChecks/FreeMemoryHealthCheck/FreeMemoryHealthCheckDefinition.cs b/WSM.HealthChecks/FreeMemoryHealthCheck/FreeMemoryHealthCheckDefinition.cs new file mode 100644 index 0000000..3e44a12 --- /dev/null +++ b/WSM.HealthChecks/FreeMemoryHealthCheck/FreeMemoryHealthCheckDefinition.cs @@ -0,0 +1,10 @@ +using WSM.Client.Models; +using WSM.HealthChecks.FreeMemoryHealthCheck; + +namespace WSM.PluginExample +{ + public class FreeMemoryHealthCheckDefinition : HealthCheckDefinitionBase + { + public override string Type => "FreeMemory"; + } +} diff --git a/WSM.HealthChecks/FreeMemoryHealthCheck/FreeMemoryHealthCheckJob.cs b/WSM.HealthChecks/FreeMemoryHealthCheck/FreeMemoryHealthCheckJob.cs new file mode 100644 index 0000000..c9fcebd --- /dev/null +++ b/WSM.HealthChecks/FreeMemoryHealthCheck/FreeMemoryHealthCheckJob.cs @@ -0,0 +1,129 @@ +using Microsoft.Extensions.Logging; +using Quartz; +using WSM.Client.Jobs; +using WSM.Shared; +using WSM.PluginExample; +using System.Diagnostics; +using System.Runtime.InteropServices; + +namespace WSM.HealthChecks.FreeMemoryHealthCheck +{ + [DisallowConcurrentExecution] + public class FreeMemoryHealthCheckJob : HealthCheckJobBase + { + private readonly ILogger _logger; + private const string MemoryLowStatus = "Free memory low"; + public FreeMemoryHealthCheckJob(ILogger logger, WSMApiClient apiClient) : base(apiClient) + { + _logger = logger; + } + public override async Task Execute(IJobExecutionContext context) + { + var healthCheckConfiguration = GetConfiguration(context); + try + { + var freeSystemMemory = GetFreeSystemMemory(); + + if (freeSystemMemory < healthCheckConfiguration.MinimumFreeMemory) + { + string mbAvailable = FormatUtils.SizeSuffix(freeSystemMemory); + await CheckIn(healthCheckConfiguration, $"{MemoryLowStatus}, {mbAvailable} available"); + return; + } + + await CheckIn(healthCheckConfiguration, Constants.AvailableStatus); + } + catch (Exception ex) + { + _logger.LogError(ex, ""); + } + } + + private long GetFreeSystemMemory() + { + + MemoryMetricsClient client = new MemoryMetricsClient(); + return client.GetMetrics().Free; + } + + public class MemoryMetrics + { + public long Total; + public long Used; + public long Free; + } + + public class MemoryMetricsClient + { + public MemoryMetrics GetMetrics() + { + if (IsUnix()) + { + return GetUnixMetrics(); + } + + return GetWindowsMetrics(); + } + + private bool IsUnix() + { + var isUnix = RuntimeInformation.IsOSPlatform(OSPlatform.OSX) || + RuntimeInformation.IsOSPlatform(OSPlatform.Linux); + + return isUnix; + } + + private MemoryMetrics GetWindowsMetrics() + { + var output = ""; + + var info = new ProcessStartInfo(); + info.FileName = "wmic"; + info.Arguments = "OS get FreePhysicalMemory,TotalVisibleMemorySize /Value"; + info.RedirectStandardOutput = true; + + using (var process = Process.Start(info)) + { + output = process.StandardOutput.ReadToEnd(); + } + + var lines = output.Trim().Split("\n"); + var freeMemoryParts = lines[0].Split("=", StringSplitOptions.RemoveEmptyEntries); + var totalMemoryParts = lines[1].Split("=", StringSplitOptions.RemoveEmptyEntries); + + var metrics = new MemoryMetrics(); + metrics.Total = long.Parse(totalMemoryParts[1]) * 1000; + metrics.Free =long.Parse(freeMemoryParts[1]) * 1000; + metrics.Used = metrics.Total - metrics.Free; + + return metrics; + } + + private MemoryMetrics GetUnixMetrics() + { + var output = ""; + + var info = new ProcessStartInfo("free -m"); + info.FileName = "/bin/bash"; + info.Arguments = "-c \"free -m\""; + info.RedirectStandardOutput = true; + + using (var process = Process.Start(info)) + { + output = process.StandardOutput.ReadToEnd(); + Console.WriteLine(output); + } + + var lines = output.Split("\n"); + var memory = lines[1].Split(" ", StringSplitOptions.RemoveEmptyEntries); + + var metrics = new MemoryMetrics(); + metrics.Total = long.Parse(memory[1]); + metrics.Used = long.Parse(memory[2]); + metrics.Free = long.Parse(memory[3]); + + return metrics; + } + } + } +} diff --git a/WSM.HealthChecks/WSM.HealthChecks.csproj b/WSM.HealthChecks/WSM.HealthChecks.csproj index b9079ee..d40fa25 100644 --- a/WSM.HealthChecks/WSM.HealthChecks.csproj +++ b/WSM.HealthChecks/WSM.HealthChecks.csproj @@ -7,6 +7,7 @@ + From 839ee43120881e9a28de866168e7c6e021ee0159 Mon Sep 17 00:00:00 2001 From: Steven Yates Date: Sun, 13 Aug 2023 21:21:29 +0100 Subject: [PATCH 3/8] Remove unused package --- WSM.HealthChecks/WSM.HealthChecks.csproj | 1 - 1 file changed, 1 deletion(-) diff --git a/WSM.HealthChecks/WSM.HealthChecks.csproj b/WSM.HealthChecks/WSM.HealthChecks.csproj index d40fa25..b9079ee 100644 --- a/WSM.HealthChecks/WSM.HealthChecks.csproj +++ b/WSM.HealthChecks/WSM.HealthChecks.csproj @@ -7,7 +7,6 @@ - From c301807d903d5bfafdce9bbd89c5d0e66aa502eb Mon Sep 17 00:00:00 2001 From: Steven Yates Date: Sun, 13 Aug 2023 23:06:12 +0100 Subject: [PATCH 4/8] Add missing build step --- .github/workflows/dotnet.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml index 079a1ab..31a10b2 100644 --- a/.github/workflows/dotnet.yml +++ b/.github/workflows/dotnet.yml @@ -35,6 +35,12 @@ jobs: - name: Build & Publish WSM.Client run: dotnet publish "./WSM.Client/WSM.Client.csproj" -o ./build/wsm.client/ -c Release + + - name: Build & Copy Health Checks + run: | + dotnet build "./WSM.HealthChecks/WSM.HealthChecks.csproj" -c Release + cp ./WSM.HealthChecks/bin/Release/net6.0/WSM.HealthChecks.dll ./build/wsm.client/healthchecks + - name: Build WSM.Server Docker uses: docker/build-push-action@v4 From 2ffc41f1b424bdae1e1e0e8c2decc65e95a778e8 Mon Sep 17 00:00:00 2001 From: Steven Yates Date: Sun, 13 Aug 2023 23:08:15 +0100 Subject: [PATCH 5/8] Create and upload zip for all builds --- .github/workflows/dotnet.yml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml index 31a10b2..66a78d9 100644 --- a/.github/workflows/dotnet.yml +++ b/.github/workflows/dotnet.yml @@ -56,8 +56,7 @@ jobs: cp ./WSM.Client/install-service.ps1 ./build/wsm.client/install-service.ps1 cp ./WSM.Client/uninstall-service.ps1 ./build/wsm.client/uninstall-service.ps1 - - name: Create wsm.client.zip - if: github.ref == 'refs/heads/master' + - name: Create wsm.client.zip run: zip -r ./build/wsm.client.zip ./build/wsm.client - name: Create release @@ -74,8 +73,7 @@ jobs: draft: true prerelease: false - - name: Upload release asset - if: github.ref == 'refs/heads/master' + - name: Upload release asset uses: actions/upload-release-asset@v1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} From 8bb7ccdd60f3eb6cdeea6351d40f0dec74997682 Mon Sep 17 00:00:00 2001 From: Steven Yates Date: Sun, 13 Aug 2023 23:10:48 +0100 Subject: [PATCH 6/8] Fix typo --- .github/workflows/dotnet.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml index 66a78d9..d8e9108 100644 --- a/.github/workflows/dotnet.yml +++ b/.github/workflows/dotnet.yml @@ -39,7 +39,7 @@ jobs: - name: Build & Copy Health Checks run: | dotnet build "./WSM.HealthChecks/WSM.HealthChecks.csproj" -c Release - cp ./WSM.HealthChecks/bin/Release/net6.0/WSM.HealthChecks.dll ./build/wsm.client/healthchecks + cp ./WSM.HealthChecks/bin/Release/net6.0/WSM.HealthChecks.dll ./build/wsm.client/healthchecks/WSM.HealthChecks.dll - name: Build WSM.Server Docker From d3bff7e641de07771541b7e0c58641c8519976a0 Mon Sep 17 00:00:00 2001 From: Steven Yates Date: Sun, 13 Aug 2023 23:11:33 +0100 Subject: [PATCH 7/8] Remove step --- .github/workflows/dotnet.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml index d8e9108..2666893 100644 --- a/.github/workflows/dotnet.yml +++ b/.github/workflows/dotnet.yml @@ -73,7 +73,8 @@ jobs: draft: true prerelease: false - - name: Upload release asset + - name: Upload release asset + if: github.ref == 'refs/heads/master' uses: actions/upload-release-asset@v1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} From 76a997d8769446550b044b874d088ceaf5d6a8ca Mon Sep 17 00:00:00 2001 From: Steven Yates Date: Sun, 13 Aug 2023 23:14:21 +0100 Subject: [PATCH 8/8] Pre-create directory --- .github/workflows/dotnet.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml index 2666893..1cec04f 100644 --- a/.github/workflows/dotnet.yml +++ b/.github/workflows/dotnet.yml @@ -39,6 +39,7 @@ jobs: - name: Build & Copy Health Checks run: | dotnet build "./WSM.HealthChecks/WSM.HealthChecks.csproj" -c Release + mkdir -p ./build/wsm.client/healthchecks cp ./WSM.HealthChecks/bin/Release/net6.0/WSM.HealthChecks.dll ./build/wsm.client/healthchecks/WSM.HealthChecks.dll