diff --git a/src/Ombi.HealthChecks/Checks/CouchPotatoHealthCheck.cs b/src/Ombi.HealthChecks/Checks/CouchPotatoHealthCheck.cs new file mode 100644 index 000000000..a68ce327b --- /dev/null +++ b/src/Ombi.HealthChecks/Checks/CouchPotatoHealthCheck.cs @@ -0,0 +1,53 @@ +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Diagnostics.HealthChecks; +using Ombi.Api.CouchPotato; +using Ombi.Api.Emby; +using Ombi.Api.Emby.Models; +using Ombi.Api.Plex; +using Ombi.Api.Plex.Models.Status; +using Ombi.Core.Settings; +using Ombi.Core.Settings.Models.External; +using Ombi.Settings.Settings.Models.External; +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; + +namespace Ombi.HealthChecks.Checks +{ + public class CouchPotatoHealthCheck : BaseHealthCheck + { + public CouchPotatoHealthCheck(IServiceScopeFactory serviceScopeFactory) : base(serviceScopeFactory) + { + } + public override async Task CheckHealthAsync( + HealthCheckContext context, + CancellationToken cancellationToken = default) + { + using (var scope = CreateScope()) + { + var settingsProvider = scope.ServiceProvider.GetRequiredService>(); + var api = scope.ServiceProvider.GetRequiredService(); + var settings = await settingsProvider.GetSettingsAsync(); + if (!settings.Enabled) + { + return HealthCheckResult.Healthy("CouchPotato is not configured."); + } + + try + { + var result = await api.Status(settings.ApiKey, settings.FullUri); + if (result != null) + { + return HealthCheckResult.Healthy(); + } + return HealthCheckResult.Degraded("Couldn't get the status from CouchPotato"); + } + catch (Exception e) + { + return HealthCheckResult.Unhealthy("Could not communicate with CouchPotato", e); + } + } + } + } +} diff --git a/src/Ombi.HealthChecks/Checks/OmbiPingHealthCheck.cs b/src/Ombi.HealthChecks/Checks/OmbiPingHealthCheck.cs new file mode 100644 index 000000000..726d02078 --- /dev/null +++ b/src/Ombi.HealthChecks/Checks/OmbiPingHealthCheck.cs @@ -0,0 +1,47 @@ +using HealthChecks.Network; +using Microsoft.Extensions.Diagnostics.HealthChecks; +using System; +using System.Collections.Generic; +using System.Net.NetworkInformation; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace Ombi.HealthChecks.Checks +{ + public class OmbiPingHealthCheck + : IHealthCheck + { + private readonly OmbiPingHealthCheckOptions _options; + public OmbiPingHealthCheck(OmbiPingHealthCheckOptions options) + { + _options = options ?? throw new ArgumentNullException(nameof(options)); + } + public async Task CheckHealthAsync(HealthCheckContext context, CancellationToken cancellationToken = default) + { + var configuredHosts = _options.ConfiguredHosts.Values; + + try + { + foreach (var (host, timeout, status) in configuredHosts) + { + using (var ping = new Ping()) + { + var pingReply = await ping.SendPingAsync(host, timeout); + + if (pingReply.Status != IPStatus.Success) + { + return new HealthCheckResult(status, description: $"Ping check for host {host} is failed with status reply:{pingReply.Status}"); + } + } + } + + return HealthCheckResult.Healthy(); + } + catch (Exception ex) + { + return new HealthCheckResult(context.Registration.FailureStatus, exception: ex); + } + } + } +} diff --git a/src/Ombi.HealthChecks/Checks/OmbiPingHealthCheckOptions.cs b/src/Ombi.HealthChecks/Checks/OmbiPingHealthCheckOptions.cs new file mode 100644 index 000000000..f89c71a52 --- /dev/null +++ b/src/Ombi.HealthChecks/Checks/OmbiPingHealthCheckOptions.cs @@ -0,0 +1,16 @@ +using Microsoft.Extensions.Diagnostics.HealthChecks; +using System.Collections.Generic; + +namespace Ombi.HealthChecks.Checks +{ + public class OmbiPingHealthCheckOptions + { + internal Dictionary ConfiguredHosts { get; } = new Dictionary(); + + public OmbiPingHealthCheckOptions AddHost(string host, int timeout, HealthStatus status) + { + ConfiguredHosts.Add(host, (host, timeout, status)); + return this; + } + } +} diff --git a/src/Ombi.HealthChecks/Checks/SickrageHealthCheck.cs b/src/Ombi.HealthChecks/Checks/SickrageHealthCheck.cs new file mode 100644 index 000000000..c348e8edf --- /dev/null +++ b/src/Ombi.HealthChecks/Checks/SickrageHealthCheck.cs @@ -0,0 +1,54 @@ +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Diagnostics.HealthChecks; +using Ombi.Api.CouchPotato; +using Ombi.Api.Emby; +using Ombi.Api.Emby.Models; +using Ombi.Api.Plex; +using Ombi.Api.Plex.Models.Status; +using Ombi.Api.SickRage; +using Ombi.Core.Settings; +using Ombi.Core.Settings.Models.External; +using Ombi.Settings.Settings.Models.External; +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; + +namespace Ombi.HealthChecks.Checks +{ + public class SickrageHealthCheck : BaseHealthCheck + { + public SickrageHealthCheck(IServiceScopeFactory serviceScopeFactory) : base(serviceScopeFactory) + { + } + public override async Task CheckHealthAsync( + HealthCheckContext context, + CancellationToken cancellationToken = default) + { + using (var scope = CreateScope()) + { + var settingsProvider = scope.ServiceProvider.GetRequiredService>(); + var api = scope.ServiceProvider.GetRequiredService(); + var settings = await settingsProvider.GetSettingsAsync(); + if (!settings.Enabled) + { + return HealthCheckResult.Healthy("SickRage is not configured."); + } + + try + { + var result = await api.Ping(settings.ApiKey, settings.FullUri); + if (result != null) + { + return HealthCheckResult.Healthy(); + } + return HealthCheckResult.Degraded("Couldn't get the status from SickRage"); + } + catch (Exception e) + { + return HealthCheckResult.Unhealthy("Could not communicate with SickRage", e); + } + } + } + } +} diff --git a/src/Ombi.HealthChecks/HealthCheckExtensions.cs b/src/Ombi.HealthChecks/HealthCheckExtensions.cs index 2b5dbb667..e608d5ec0 100644 --- a/src/Ombi.HealthChecks/HealthCheckExtensions.cs +++ b/src/Ombi.HealthChecks/HealthCheckExtensions.cs @@ -1,5 +1,8 @@ using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Diagnostics.HealthChecks; using Ombi.HealthChecks.Checks; +using System; +using System.Collections.Generic; namespace Ombi.HealthChecks { @@ -12,8 +15,41 @@ namespace Ombi.HealthChecks builder.AddCheck("Lidarr", tags: new string[] { "DVR" }); builder.AddCheck("Sonarr", tags: new string[] { "DVR" }); builder.AddCheck("Radarr", tags: new string[] { "DVR" }); + builder.AddCheck("CouchPotato", tags: new string[] { "DVR" }); + builder.AddCheck("SickRage", tags: new string[] { "DVR" }); + builder.AddOmbiPingHealthCheck(options => + { + options.AddHost("www.google.co.uk", 5000, HealthStatus.Unhealthy); + options.AddHost("www.google.com", 3000, HealthStatus.Degraded); + }, "External Ping", tags: new string[] { "System" }); return builder; } + + /// + /// Add a health check for network ping. + /// + /// The . + /// The action to configure the ping parameters. + /// The health check name. Optional. If null the type name 'ping' will be used for the name. + /// + /// The that should be reported when the health check fails. Optional. If null then + /// the default status of will be reported. + /// + /// A list of tags that can be used to filter sets of health checks. Optional. + /// An optional System.TimeSpan representing the timeout of the check. + /// The . + public static IHealthChecksBuilder AddOmbiPingHealthCheck(this IHealthChecksBuilder builder, Action setup, string name = default, HealthStatus? failureStatus = default, IEnumerable tags = default, TimeSpan? timeout = default) + { + var options = new OmbiPingHealthCheckOptions(); + setup?.Invoke(options); + + return builder.Add(new HealthCheckRegistration( + name, + sp => new OmbiPingHealthCheck(options), + failureStatus, + tags, + timeout)); + } } } diff --git a/src/Ombi.HealthChecks/Ombi.HealthChecks.csproj b/src/Ombi.HealthChecks/Ombi.HealthChecks.csproj index 9b75bfed5..57c2ef059 100644 --- a/src/Ombi.HealthChecks/Ombi.HealthChecks.csproj +++ b/src/Ombi.HealthChecks/Ombi.HealthChecks.csproj @@ -5,14 +5,18 @@ + + + + diff --git a/src/Ombi.Settings/Settings/Models/OmbiSettings.cs b/src/Ombi.Settings/Settings/Models/OmbiSettings.cs index e0787326e..d7af8ffe4 100644 --- a/src/Ombi.Settings/Settings/Models/OmbiSettings.cs +++ b/src/Ombi.Settings/Settings/Models/OmbiSettings.cs @@ -10,6 +10,7 @@ public bool IgnoreCertificateErrors { get; set; } public bool DoNotSendNotificationsForAutoApprove { get; set; } public bool HideRequestsUsers { get; set; } + public bool DisableHealthChecks { get; set; } public string DefaultLanguageCode { get; set; } = "en"; } } \ No newline at end of file diff --git a/src/Ombi/ClientApp/src/app/interfaces/ISettings.ts b/src/Ombi/ClientApp/src/app/interfaces/ISettings.ts index e56c517ca..8eb595a6c 100644 --- a/src/Ombi/ClientApp/src/app/interfaces/ISettings.ts +++ b/src/Ombi/ClientApp/src/app/interfaces/ISettings.ts @@ -16,6 +16,7 @@ export interface IOmbiSettings extends ISettings { doNotSendNotificationsForAutoApprove: boolean; hideRequestsUsers: boolean; defaultLanguageCode: string; + disableHealthChecks: boolean; } export interface IUpdateSettings extends ISettings { diff --git a/src/Ombi/ClientApp/src/app/settings/ombi/ombi.component.html b/src/Ombi/ClientApp/src/app/settings/ombi/ombi.component.html index 48a5d8883..a39250ff2 100644 --- a/src/Ombi/ClientApp/src/app/settings/ombi/ombi.component.html +++ b/src/Ombi/ClientApp/src/app/settings/ombi/ombi.component.html @@ -2,50 +2,57 @@
- Ombi Configuration - -
+ Ombi Configuration -
+ - - - +
+ + + + -
- -
- +
+ +
+ -
-
-
+
+
+
-
-
-
+
+
+
+
+
+
+
+ + Do not send Notifications if a User has the Auto Approve permission +
+
+ + Hide requests from other users + +
+
+ + Ignore any certificate errors + +
+
+ + Allow us to collect anonymous analytical data e.g. browser used + +
+
+ + Disable the health checks page /healthchecks-ui
-
-
-
- - Do not send Notifications if a User has the Auto Approve permission -
- - Hide requests from other users - -
- - Ignore any certificate errors - -
- - Allow us to collect anonymous analytical data e.g. browser used - -
+
-- @@ -62,4 +69,4 @@
-
+ \ No newline at end of file diff --git a/src/Ombi/ClientApp/src/app/settings/ombi/ombi.component.ts b/src/Ombi/ClientApp/src/app/settings/ombi/ombi.component.ts index 4aec1a57c..6439cd787 100644 --- a/src/Ombi/ClientApp/src/app/settings/ombi/ombi.component.ts +++ b/src/Ombi/ClientApp/src/app/settings/ombi/ombi.component.ts @@ -29,6 +29,7 @@ export class OmbiComponent implements OnInit { doNotSendNotificationsForAutoApprove: [x.doNotSendNotificationsForAutoApprove], hideRequestsUsers: [x.hideRequestsUsers], defaultLanguageCode: [x.defaultLanguageCode], + disableHealthChecks: [x.disableHealthChecks] }); }); this.langauges = languageData; diff --git a/src/Ombi/HealthCheck.css b/src/Ombi/HealthCheck.css index bcdfe4d06..fc303c8c9 100644 --- a/src/Ombi/HealthCheck.css +++ b/src/Ombi/HealthCheck.css @@ -10,4 +10,5 @@ #outer-container > aside > nav > a:nth-child(2) { display: none; -} \ No newline at end of file +} + diff --git a/src/Ombi/Startup.cs b/src/Ombi/Startup.cs index 0b86d9000..2f7c6a346 100644 --- a/src/Ombi/Startup.cs +++ b/src/Ombi/Startup.cs @@ -79,10 +79,11 @@ namespace Ombi var hcBuilder = services.AddHealthChecks(); hcBuilder.AddOmbiHealthChecks(); services.ConfigureDatabases(hcBuilder); - services.AddHealthChecksUI(setupSettings: setup => - { - setup.AddHealthCheckEndpoint("Ombi", "http://localhost:3577/healthz"); - }); + // Need to wait until https://github.com/Xabaril/AspNetCore.Diagnostics.HealthChecks/issues/410 is resolved + //services.AddHealthChecksUI(setupSettings: setup => + //{ + // setup.AddHealthCheckEndpoint("Ombi", "/health"); + //}); services.AddMemoryCache(); services.AddJwtAuthentication(Configuration); @@ -115,7 +116,7 @@ namespace Ombi } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. - public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory loggerFactory, IServiceProvider serviceProvider) + public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory, IServiceProvider serviceProvider) { app.UseForwardedHeaders(new ForwardedHeadersOptions { @@ -212,24 +213,26 @@ namespace Ombi { endpoints.MapControllers(); endpoints.MapHub("/hubs/notification"); - endpoints.MapHealthChecks("/health"); - endpoints.MapHealthChecks("/healthz", new HealthCheckOptions + if (!settings.DisableHealthChecks) { - Predicate = _ => true, - ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse - }); - endpoints.MapHealthChecksUI(opts => - { - opts.AddCustomStylesheet("HealthCheck.css"); - }); + endpoints.MapHealthChecks("/health", new HealthCheckOptions + { + Predicate = _ => true, + ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse + }); + endpoints.MapHealthChecksUI(opts => + { + opts.AddCustomStylesheet("HealthCheck.css"); + }); + } }); app.UseSpa(spa => { -//#if DEBUG -// spa.Options.SourcePath = "ClientApp"; -// spa.UseProxyToSpaDevelopmentServer("http://localhost:3578"); -//#endif +#if DEBUG + spa.Options.SourcePath = "ClientApp"; + spa.UseProxyToSpaDevelopmentServer("http://localhost:3578"); +#endif }); } diff --git a/src/Ombi/healthchecksdb b/src/Ombi/healthchecksdb deleted file mode 100644 index 90c88cbb9..000000000 Binary files a/src/Ombi/healthchecksdb and /dev/null differ