diff --git a/src/Ombi.Api.CouchPotato/Ombi.Api.CouchPotato.csproj b/src/Ombi.Api.CouchPotato/Ombi.Api.CouchPotato.csproj index 3c31ecb84..809404bd4 100644 --- a/src/Ombi.Api.CouchPotato/Ombi.Api.CouchPotato.csproj +++ b/src/Ombi.Api.CouchPotato/Ombi.Api.CouchPotato.csproj @@ -2,6 +2,7 @@ netstandard2.1 + 8.0 diff --git a/src/Ombi.Api.Discord/Ombi.Api.Discord.csproj b/src/Ombi.Api.Discord/Ombi.Api.Discord.csproj index 84f215437..5c67fe577 100644 --- a/src/Ombi.Api.Discord/Ombi.Api.Discord.csproj +++ b/src/Ombi.Api.Discord/Ombi.Api.Discord.csproj @@ -6,6 +6,7 @@ 3.0.0.0 + 8.0 diff --git a/src/Ombi.Api.DogNzb/Ombi.Api.DogNzb.csproj b/src/Ombi.Api.DogNzb/Ombi.Api.DogNzb.csproj index 3c31ecb84..809404bd4 100644 --- a/src/Ombi.Api.DogNzb/Ombi.Api.DogNzb.csproj +++ b/src/Ombi.Api.DogNzb/Ombi.Api.DogNzb.csproj @@ -2,6 +2,7 @@ netstandard2.1 + 8.0 diff --git a/src/Ombi.Api.Emby/Ombi.Api.Emby.csproj b/src/Ombi.Api.Emby/Ombi.Api.Emby.csproj index 24c86a86f..2bb0c6352 100644 --- a/src/Ombi.Api.Emby/Ombi.Api.Emby.csproj +++ b/src/Ombi.Api.Emby/Ombi.Api.Emby.csproj @@ -6,6 +6,7 @@ 3.0.0.0 + 8.0 diff --git a/src/Ombi.Api.FanartTv/Ombi.Api.FanartTv.csproj b/src/Ombi.Api.FanartTv/Ombi.Api.FanartTv.csproj index 84f215437..5c67fe577 100644 --- a/src/Ombi.Api.FanartTv/Ombi.Api.FanartTv.csproj +++ b/src/Ombi.Api.FanartTv/Ombi.Api.FanartTv.csproj @@ -6,6 +6,7 @@ 3.0.0.0 + 8.0 diff --git a/src/Ombi.Api.Github/Ombi.Api.Github.csproj b/src/Ombi.Api.Github/Ombi.Api.Github.csproj index 3c31ecb84..809404bd4 100644 --- a/src/Ombi.Api.Github/Ombi.Api.Github.csproj +++ b/src/Ombi.Api.Github/Ombi.Api.Github.csproj @@ -2,6 +2,7 @@ netstandard2.1 + 8.0 diff --git a/src/Ombi.Api.Gotify/Ombi.Api.Gotify.csproj b/src/Ombi.Api.Gotify/Ombi.Api.Gotify.csproj index 7c02a2978..79414ab00 100644 --- a/src/Ombi.Api.Gotify/Ombi.Api.Gotify.csproj +++ b/src/Ombi.Api.Gotify/Ombi.Api.Gotify.csproj @@ -6,6 +6,7 @@ 3.0.0.0 + 8.0 diff --git a/src/Ombi.Api.GroupMe/Ombi.Api.GroupMe.csproj b/src/Ombi.Api.GroupMe/Ombi.Api.GroupMe.csproj index 3c31ecb84..809404bd4 100644 --- a/src/Ombi.Api.GroupMe/Ombi.Api.GroupMe.csproj +++ b/src/Ombi.Api.GroupMe/Ombi.Api.GroupMe.csproj @@ -2,6 +2,7 @@ netstandard2.1 + 8.0 diff --git a/src/Ombi.Api.Lidarr/Ombi.Api.Lidarr.csproj b/src/Ombi.Api.Lidarr/Ombi.Api.Lidarr.csproj index 3c31ecb84..809404bd4 100644 --- a/src/Ombi.Api.Lidarr/Ombi.Api.Lidarr.csproj +++ b/src/Ombi.Api.Lidarr/Ombi.Api.Lidarr.csproj @@ -2,6 +2,7 @@ netstandard2.1 + 8.0 diff --git a/src/Ombi.Api.Mattermost/Ombi.Api.Mattermost.csproj b/src/Ombi.Api.Mattermost/Ombi.Api.Mattermost.csproj index 1b93a9b39..2192220e6 100644 --- a/src/Ombi.Api.Mattermost/Ombi.Api.Mattermost.csproj +++ b/src/Ombi.Api.Mattermost/Ombi.Api.Mattermost.csproj @@ -6,6 +6,7 @@ 3.0.0.0 + 8.0 diff --git a/src/Ombi.Api.MusicBrainz/Ombi.Api.MusicBrainz.csproj b/src/Ombi.Api.MusicBrainz/Ombi.Api.MusicBrainz.csproj index e5ffec654..8b408314a 100644 --- a/src/Ombi.Api.MusicBrainz/Ombi.Api.MusicBrainz.csproj +++ b/src/Ombi.Api.MusicBrainz/Ombi.Api.MusicBrainz.csproj @@ -2,6 +2,7 @@ netstandard2.1 + 8.0 diff --git a/src/Ombi.Api.Notifications/Ombi.Api.Notifications.csproj b/src/Ombi.Api.Notifications/Ombi.Api.Notifications.csproj index 07a764ec0..002e44260 100644 --- a/src/Ombi.Api.Notifications/Ombi.Api.Notifications.csproj +++ b/src/Ombi.Api.Notifications/Ombi.Api.Notifications.csproj @@ -2,6 +2,7 @@ netstandard2.1 + 8.0 diff --git a/src/Ombi.Api.Plex/Ombi.Api.Plex.csproj b/src/Ombi.Api.Plex/Ombi.Api.Plex.csproj index d1a2a1c65..e5f5b3394 100644 --- a/src/Ombi.Api.Plex/Ombi.Api.Plex.csproj +++ b/src/Ombi.Api.Plex/Ombi.Api.Plex.csproj @@ -6,6 +6,7 @@ 3.0.0.0 + 8.0 diff --git a/src/Ombi.Api.Pushbullet/Ombi.Api.Pushbullet.csproj b/src/Ombi.Api.Pushbullet/Ombi.Api.Pushbullet.csproj index 84f215437..5c67fe577 100644 --- a/src/Ombi.Api.Pushbullet/Ombi.Api.Pushbullet.csproj +++ b/src/Ombi.Api.Pushbullet/Ombi.Api.Pushbullet.csproj @@ -6,6 +6,7 @@ 3.0.0.0 + 8.0 diff --git a/src/Ombi.Api.Pushover/Ombi.Api.Pushover.csproj b/src/Ombi.Api.Pushover/Ombi.Api.Pushover.csproj index 7c02a2978..79414ab00 100644 --- a/src/Ombi.Api.Pushover/Ombi.Api.Pushover.csproj +++ b/src/Ombi.Api.Pushover/Ombi.Api.Pushover.csproj @@ -6,6 +6,7 @@ 3.0.0.0 + 8.0 diff --git a/src/Ombi.Api.Radarr/Ombi.Api.Radarr.csproj b/src/Ombi.Api.Radarr/Ombi.Api.Radarr.csproj index 2efedfad6..4fc0becae 100644 --- a/src/Ombi.Api.Radarr/Ombi.Api.Radarr.csproj +++ b/src/Ombi.Api.Radarr/Ombi.Api.Radarr.csproj @@ -6,10 +6,11 @@ 3.0.0.0 + 8.0 - + diff --git a/src/Ombi.Api.Service/Ombi.Api.Service.csproj b/src/Ombi.Api.Service/Ombi.Api.Service.csproj index 1e466b24d..2a434c8cd 100644 --- a/src/Ombi.Api.Service/Ombi.Api.Service.csproj +++ b/src/Ombi.Api.Service/Ombi.Api.Service.csproj @@ -8,10 +8,11 @@ Ombi.Api.Service Ombi.Api.Service + 8.0 - + diff --git a/src/Ombi.Api.SickRage/Ombi.Api.SickRage.csproj b/src/Ombi.Api.SickRage/Ombi.Api.SickRage.csproj index 3c31ecb84..809404bd4 100644 --- a/src/Ombi.Api.SickRage/Ombi.Api.SickRage.csproj +++ b/src/Ombi.Api.SickRage/Ombi.Api.SickRage.csproj @@ -2,6 +2,7 @@ netstandard2.1 + 8.0 diff --git a/src/Ombi.Api.Slack/Ombi.Api.Slack.csproj b/src/Ombi.Api.Slack/Ombi.Api.Slack.csproj index 84f215437..5c67fe577 100644 --- a/src/Ombi.Api.Slack/Ombi.Api.Slack.csproj +++ b/src/Ombi.Api.Slack/Ombi.Api.Slack.csproj @@ -6,6 +6,7 @@ 3.0.0.0 + 8.0 diff --git a/src/Ombi.Api.Sonarr/Ombi.Api.Sonarr.csproj b/src/Ombi.Api.Sonarr/Ombi.Api.Sonarr.csproj index 84f215437..5c67fe577 100644 --- a/src/Ombi.Api.Sonarr/Ombi.Api.Sonarr.csproj +++ b/src/Ombi.Api.Sonarr/Ombi.Api.Sonarr.csproj @@ -6,6 +6,7 @@ 3.0.0.0 + 8.0 diff --git a/src/Ombi.Api.Telegram/Ombi.Api.Telegram.csproj b/src/Ombi.Api.Telegram/Ombi.Api.Telegram.csproj index 3c31ecb84..809404bd4 100644 --- a/src/Ombi.Api.Telegram/Ombi.Api.Telegram.csproj +++ b/src/Ombi.Api.Telegram/Ombi.Api.Telegram.csproj @@ -2,6 +2,7 @@ netstandard2.1 + 8.0 diff --git a/src/Ombi.Api.Trakt/Ombi.Api.Trakt.csproj b/src/Ombi.Api.Trakt/Ombi.Api.Trakt.csproj index 99ed0f20e..f7a2a3766 100644 --- a/src/Ombi.Api.Trakt/Ombi.Api.Trakt.csproj +++ b/src/Ombi.Api.Trakt/Ombi.Api.Trakt.csproj @@ -6,6 +6,7 @@ 3.0.0.0 + 8.0 diff --git a/src/Ombi.Api.TvMaze/Ombi.Api.TvMaze.csproj b/src/Ombi.Api.TvMaze/Ombi.Api.TvMaze.csproj index 24c86a86f..2bb0c6352 100644 --- a/src/Ombi.Api.TvMaze/Ombi.Api.TvMaze.csproj +++ b/src/Ombi.Api.TvMaze/Ombi.Api.TvMaze.csproj @@ -6,6 +6,7 @@ 3.0.0.0 + 8.0 diff --git a/src/Ombi.Api/Ombi.Api.csproj b/src/Ombi.Api/Ombi.Api.csproj index 4e9843866..34e051c00 100644 --- a/src/Ombi.Api/Ombi.Api.csproj +++ b/src/Ombi.Api/Ombi.Api.csproj @@ -6,10 +6,11 @@ 3.0.0.0 + 8.0 - + diff --git a/src/Ombi.Core.Tests/Ombi.Core.Tests.csproj b/src/Ombi.Core.Tests/Ombi.Core.Tests.csproj index 89ff21a7c..a629080a4 100644 --- a/src/Ombi.Core.Tests/Ombi.Core.Tests.csproj +++ b/src/Ombi.Core.Tests/Ombi.Core.Tests.csproj @@ -1,7 +1,7 @@ - netcoreapp3.0 + netcoreapp3.1 diff --git a/src/Ombi.Core/Engine/MovieRequestEngine.cs b/src/Ombi.Core/Engine/MovieRequestEngine.cs index 934690242..ce7d1d1d4 100644 --- a/src/Ombi.Core/Engine/MovieRequestEngine.cs +++ b/src/Ombi.Core/Engine/MovieRequestEngine.cs @@ -226,12 +226,12 @@ namespace Ombi.Core.Engine //var secondProp = TypeDescriptor.GetProperties(propType).Find(properties[1], true); } - allRequests = sortOrder.Equals("asc", StringComparison.InvariantCultureIgnoreCase) - ? allRequests.OrderBy(x => prop.GetValue(x)) - : allRequests.OrderByDescending(x => prop.GetValue(x)); - var total = await allRequests.CountAsync(); - var requests = await allRequests.Skip(position).Take(count) - .ToListAsync(); + // TODO fix this so we execute this on the server + var requests = sortOrder.Equals("asc", StringComparison.InvariantCultureIgnoreCase) + ? allRequests.ToList().OrderBy(x => x.RequestedDate).ToList() + : allRequests.ToList().OrderByDescending(x => prop.GetValue(x)).ToList(); + var total = requests.Count(); + requests = requests.Skip(position).Take(count).ToList(); await CheckForSubscription(shouldHide, requests); return new RequestsViewModel diff --git a/src/Ombi.Core/Ombi.Core.csproj b/src/Ombi.Core/Ombi.Core.csproj index 7d4598d9c..99c531183 100644 --- a/src/Ombi.Core/Ombi.Core.csproj +++ b/src/Ombi.Core/Ombi.Core.csproj @@ -6,13 +6,14 @@ 3.0.0.0 + 8.0 - - + + diff --git a/src/Ombi.Core/Senders/TvSender.cs b/src/Ombi.Core/Senders/TvSender.cs index 5cf28fa8a..91c38428a 100644 --- a/src/Ombi.Core/Senders/TvSender.cs +++ b/src/Ombi.Core/Senders/TvSender.cs @@ -16,7 +16,6 @@ using Ombi.Settings.Settings.Models.External; using Ombi.Store.Entities; using Ombi.Store.Entities.Requests; using Ombi.Store.Repository; -using Remotion.Linq.Parsing.Structure.IntermediateModel; namespace Ombi.Core.Senders { diff --git a/src/Ombi.DependencyInjection/IocExtensions.cs b/src/Ombi.DependencyInjection/IocExtensions.cs index 1a36093ec..575508e99 100644 --- a/src/Ombi.DependencyInjection/IocExtensions.cs +++ b/src/Ombi.DependencyInjection/IocExtensions.cs @@ -1,7 +1,6 @@ using System.Diagnostics.CodeAnalysis; using System.Security.Principal; using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.SignalR; using Microsoft.Extensions.DependencyInjection; using Ombi.Api.Discord; @@ -62,7 +61,6 @@ using Ombi.Schedule.Jobs.Lidarr; using Ombi.Schedule.Jobs.Plex.Interfaces; using Ombi.Schedule.Jobs.SickRage; using Ombi.Schedule.Processor; -using Ombi.Store.Entities; using Quartz.Spi; using Ombi.Api.MusicBrainz; using Ombi.Api.Twilio; diff --git a/src/Ombi.DependencyInjection/Ombi.DependencyInjection.csproj b/src/Ombi.DependencyInjection/Ombi.DependencyInjection.csproj index a7aedbfa6..0a5768500 100644 --- a/src/Ombi.DependencyInjection/Ombi.DependencyInjection.csproj +++ b/src/Ombi.DependencyInjection/Ombi.DependencyInjection.csproj @@ -6,12 +6,13 @@ 3.0.0.0 + 8.0 - - - + + + diff --git a/src/Ombi.HealthChecks/Checks/BaseHealthCheck.cs b/src/Ombi.HealthChecks/Checks/BaseHealthCheck.cs new file mode 100644 index 000000000..d0c14196c --- /dev/null +++ b/src/Ombi.HealthChecks/Checks/BaseHealthCheck.cs @@ -0,0 +1,26 @@ +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Diagnostics.HealthChecks; +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace Ombi.HealthChecks.Checks +{ + public abstract class BaseHealthCheck : IHealthCheck + { + private readonly IServiceScopeFactory _serviceScopeFactory; + public BaseHealthCheck(IServiceScopeFactory serviceScopeFactory) + { + _serviceScopeFactory = serviceScopeFactory; + } + + public abstract Task CheckHealthAsync(HealthCheckContext context, CancellationToken cancellationToken = default); + + protected IServiceScope CreateScope() + { + return _serviceScopeFactory.CreateScope(); + } + } +} 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/EmbyHealthCheck.cs b/src/Ombi.HealthChecks/Checks/EmbyHealthCheck.cs new file mode 100644 index 000000000..d601cdeef --- /dev/null +++ b/src/Ombi.HealthChecks/Checks/EmbyHealthCheck.cs @@ -0,0 +1,53 @@ +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Diagnostics.HealthChecks; +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 System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; + +namespace Ombi.HealthChecks.Checks +{ + public class EmbyHealthCheck : BaseHealthCheck + { + public EmbyHealthCheck(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 == null) + { + return HealthCheckResult.Healthy("Emby is not configured."); + } + + var taskResult = new List>(); + foreach (var server in settings.Servers) + { + taskResult.Add(api.GetSystemInformation(server.ApiKey, server.FullUri)); + } + + try + { + var result = await Task.WhenAll(taskResult.ToArray()); + return HealthCheckResult.Healthy(); + } + catch (Exception e) + { + return HealthCheckResult.Unhealthy("Could not communicate with Emby", e); + } + } + } + } +} diff --git a/src/Ombi.HealthChecks/Checks/LidarrHealthCheck.cs b/src/Ombi.HealthChecks/Checks/LidarrHealthCheck.cs new file mode 100644 index 000000000..4efc0a904 --- /dev/null +++ b/src/Ombi.HealthChecks/Checks/LidarrHealthCheck.cs @@ -0,0 +1,48 @@ +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Diagnostics.HealthChecks; +using Ombi.Api.Lidarr; +using Ombi.Core.Settings; +using Ombi.Settings.Settings.Models.External; +using System; +using System.Threading; +using System.Threading.Tasks; + +namespace Ombi.HealthChecks.Checks +{ + public class LidarrHealthCheck : BaseHealthCheck + { + public LidarrHealthCheck(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("Lidarr 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 Lidarr"); + } + catch (Exception e) + { + return HealthCheckResult.Unhealthy("Could not communicate with Lidarr", 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/PlexHealthCheck.cs b/src/Ombi.HealthChecks/Checks/PlexHealthCheck.cs new file mode 100644 index 000000000..182c1b2f8 --- /dev/null +++ b/src/Ombi.HealthChecks/Checks/PlexHealthCheck.cs @@ -0,0 +1,51 @@ +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Diagnostics.HealthChecks; +using Ombi.Api.Plex; +using Ombi.Api.Plex.Models.Status; +using Ombi.Core.Settings; +using Ombi.Core.Settings.Models.External; +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; + +namespace Ombi.HealthChecks.Checks +{ + public class PlexHealthCheck : BaseHealthCheck + { + public PlexHealthCheck(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 == null) + { + return HealthCheckResult.Healthy("Plex is not confiured."); + } + + var taskResult = new List>(); + foreach (var server in settings.Servers) + { + taskResult.Add(api.GetStatus(server.PlexAuthToken, server.FullUri)); + } + + try + { + var result = await Task.WhenAll(taskResult.ToArray()); + return HealthCheckResult.Healthy(); + } + catch (Exception e) + { + return HealthCheckResult.Unhealthy("Could not communicate with Plex", e); + } + } + } + } +} diff --git a/src/Ombi.HealthChecks/Checks/RadarrHealthCheck.cs b/src/Ombi.HealthChecks/Checks/RadarrHealthCheck.cs new file mode 100644 index 000000000..e365c73bb --- /dev/null +++ b/src/Ombi.HealthChecks/Checks/RadarrHealthCheck.cs @@ -0,0 +1,47 @@ +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Diagnostics.HealthChecks; +using Ombi.Api.Radarr; +using Ombi.Core.Settings; +using Ombi.Settings.Settings.Models.External; +using System; +using System.Threading; +using System.Threading.Tasks; + +namespace Ombi.HealthChecks.Checks +{ + public class RadarrHealthCheck : BaseHealthCheck, IHealthCheck + { + public RadarrHealthCheck(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("Radarr is not configured."); + } + + try + { + var result = await api.SystemStatus(settings.ApiKey, settings.FullUri); + if (result != null) + { + return HealthCheckResult.Healthy(); + } + return HealthCheckResult.Degraded("Couldn't get the status from Radarr"); + } + catch (Exception e) + { + return HealthCheckResult.Unhealthy("Could not communicate with Radarr", e); + } + } + } + } +} 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/Checks/SonarrHealthCheck.cs b/src/Ombi.HealthChecks/Checks/SonarrHealthCheck.cs new file mode 100644 index 000000000..35f2bb46a --- /dev/null +++ b/src/Ombi.HealthChecks/Checks/SonarrHealthCheck.cs @@ -0,0 +1,48 @@ +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Diagnostics.HealthChecks; +using Ombi.Api.Sonarr; +using Ombi.Core.Settings; +using Ombi.Settings.Settings.Models.External; +using System; +using System.Threading; +using System.Threading.Tasks; + +namespace Ombi.HealthChecks.Checks +{ + public class SonarrHealthCheck : BaseHealthCheck + { + public SonarrHealthCheck(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("Sonarr is not configured."); + } + + try + { + var result = await api.SystemStatus(settings.ApiKey, settings.FullUri); + if (result != null) + { + return HealthCheckResult.Healthy(); + } + return HealthCheckResult.Degraded("Couldn't get the status from Sonarr"); + } + catch (Exception e) + { + return HealthCheckResult.Unhealthy("Could not communicate with Sonarr", e); + } + } + } + } +} diff --git a/src/Ombi.HealthChecks/HealthCheckExtensions.cs b/src/Ombi.HealthChecks/HealthCheckExtensions.cs new file mode 100644 index 000000000..e608d5ec0 --- /dev/null +++ b/src/Ombi.HealthChecks/HealthCheckExtensions.cs @@ -0,0 +1,55 @@ +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Diagnostics.HealthChecks; +using Ombi.HealthChecks.Checks; +using System; +using System.Collections.Generic; + +namespace Ombi.HealthChecks +{ + public static class HealthCheckExtensions + { + public static IHealthChecksBuilder AddOmbiHealthChecks(this IHealthChecksBuilder builder) + { + builder.AddCheck("Plex", tags: new string[] { "MediaServer" }); + builder.AddCheck("Emby", tags: new string[] { "MediaServer" }); + 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 new file mode 100644 index 000000000..57c2ef059 --- /dev/null +++ b/src/Ombi.HealthChecks/Ombi.HealthChecks.csproj @@ -0,0 +1,23 @@ + + + + netstandard2.1 + + + + + + + + + + + + + + + + + + + diff --git a/src/Ombi.Helpers.Tests/Ombi.Helpers.Tests.csproj b/src/Ombi.Helpers.Tests/Ombi.Helpers.Tests.csproj index 45f2f537e..1046f9e68 100644 --- a/src/Ombi.Helpers.Tests/Ombi.Helpers.Tests.csproj +++ b/src/Ombi.Helpers.Tests/Ombi.Helpers.Tests.csproj @@ -1,7 +1,7 @@ - + - netcoreapp3.0 + netcoreapp3.1 false diff --git a/src/Ombi.Helpers/Ombi.Helpers.csproj b/src/Ombi.Helpers/Ombi.Helpers.csproj index bade3fd90..cd33b9455 100644 --- a/src/Ombi.Helpers/Ombi.Helpers.csproj +++ b/src/Ombi.Helpers/Ombi.Helpers.csproj @@ -6,12 +6,13 @@ 3.0.0.0 + 8.0 - - + + diff --git a/src/Ombi.Hubs/Ombi.Hubs.csproj b/src/Ombi.Hubs/Ombi.Hubs.csproj index 69a439574..ae2e158ad 100644 --- a/src/Ombi.Hubs/Ombi.Hubs.csproj +++ b/src/Ombi.Hubs/Ombi.Hubs.csproj @@ -2,6 +2,7 @@ netstandard2.1 + 8.0 diff --git a/src/Ombi.Mapping/Ombi.Mapping.csproj b/src/Ombi.Mapping/Ombi.Mapping.csproj index 94c8c42d7..2f5172663 100644 --- a/src/Ombi.Mapping/Ombi.Mapping.csproj +++ b/src/Ombi.Mapping/Ombi.Mapping.csproj @@ -6,6 +6,7 @@ 3.0.0.0 + 8.0 diff --git a/src/Ombi.Notifications.Templates/Ombi.Notifications.Templates.csproj b/src/Ombi.Notifications.Templates/Ombi.Notifications.Templates.csproj index a02def1dc..6a296fa24 100644 --- a/src/Ombi.Notifications.Templates/Ombi.Notifications.Templates.csproj +++ b/src/Ombi.Notifications.Templates/Ombi.Notifications.Templates.csproj @@ -6,6 +6,7 @@ 3.0.0.0 + 8.0 diff --git a/src/Ombi.Notifications.Tests/Ombi.Notifications.Tests.csproj b/src/Ombi.Notifications.Tests/Ombi.Notifications.Tests.csproj index 8ce8ab43b..ecbcbdae2 100644 --- a/src/Ombi.Notifications.Tests/Ombi.Notifications.Tests.csproj +++ b/src/Ombi.Notifications.Tests/Ombi.Notifications.Tests.csproj @@ -1,7 +1,7 @@ - netcoreapp3.0 + netcoreapp3.1 diff --git a/src/Ombi.Notifications/Ombi.Notifications.csproj b/src/Ombi.Notifications/Ombi.Notifications.csproj index 4ab81a8b4..63f024647 100644 --- a/src/Ombi.Notifications/Ombi.Notifications.csproj +++ b/src/Ombi.Notifications/Ombi.Notifications.csproj @@ -6,11 +6,12 @@ 3.0.0.0 + 8.0 - + diff --git a/src/Ombi.Schedule.Tests/Ombi.Schedule.Tests.csproj b/src/Ombi.Schedule.Tests/Ombi.Schedule.Tests.csproj index 70a456b6a..2964f71b9 100644 --- a/src/Ombi.Schedule.Tests/Ombi.Schedule.Tests.csproj +++ b/src/Ombi.Schedule.Tests/Ombi.Schedule.Tests.csproj @@ -1,7 +1,7 @@ - netcoreapp3.0 + netcoreapp3.1 @@ -18,10 +18,4 @@ - - - ..\..\..\..\Program Files\dotnet\sdk\NuGetFallbackFolder\microsoft.aspnetcore.signalr.core\1.1.0\lib\netstandard2.0\Microsoft.AspNetCore.SignalR.Core.dll - - - diff --git a/src/Ombi.Schedule/Jobs/Lidarr/LidarrAvailabilityChecker.cs b/src/Ombi.Schedule/Jobs/Lidarr/LidarrAvailabilityChecker.cs index 10518a51e..99b27fec7 100644 --- a/src/Ombi.Schedule/Jobs/Lidarr/LidarrAvailabilityChecker.cs +++ b/src/Ombi.Schedule/Jobs/Lidarr/LidarrAvailabilityChecker.cs @@ -19,7 +19,7 @@ namespace Ombi.Schedule.Jobs.Lidarr { public class LidarrAvailabilityChecker : ILidarrAvailabilityChecker { - public LidarrAvailabilityChecker(IMusicRequestRepository requests, IRepository albums, ILogger log, + public LidarrAvailabilityChecker(IMusicRequestRepository requests, IExternalRepository albums, ILogger log, INotificationHelper notification, IHubContext notificationHub) { _cachedAlbums = albums; @@ -30,7 +30,7 @@ namespace Ombi.Schedule.Jobs.Lidarr } private readonly IMusicRequestRepository _requestRepository; - private readonly IRepository _cachedAlbums; + private readonly IExternalRepository _cachedAlbums; private readonly ILogger _logger; private readonly INotificationHelper _notificationService; private readonly IHubContext _notification; diff --git a/src/Ombi.Schedule/Jobs/Ombi/RefreshMetadata.cs b/src/Ombi.Schedule/Jobs/Ombi/RefreshMetadata.cs index 10daef789..a24914e99 100644 --- a/src/Ombi.Schedule/Jobs/Ombi/RefreshMetadata.cs +++ b/src/Ombi.Schedule/Jobs/Ombi/RefreshMetadata.cs @@ -83,12 +83,12 @@ namespace Ombi.Schedule.Jobs.Ombi { // Ensure we check that we have not linked this item to a request var allMovies = _plexRepo.GetAll().Where(x => - x.Type == PlexMediaTypeEntity.Movie && !x.RequestId.HasValue && (!x.TheMovieDbId.HasValue() || !x.ImdbId.HasValue())); + x.Type == PlexMediaTypeEntity.Movie && x.RequestId == null && (x.TheMovieDbId == null || x.ImdbId == null)); await StartPlexMovies(allMovies); // Now Tv var allTv = _plexRepo.GetAll().Where(x => - x.Type == PlexMediaTypeEntity.Show && !x.RequestId.HasValue && (!x.TheMovieDbId.HasValue() || !x.ImdbId.HasValue() || !x.TvDbId.HasValue())); + x.Type == PlexMediaTypeEntity.Show && x.RequestId == null && (x.TheMovieDbId == null || x.ImdbId == null || x.TvDbId == null)); await StartPlexTv(allTv); } diff --git a/src/Ombi.Schedule/Ombi.Schedule.csproj b/src/Ombi.Schedule/Ombi.Schedule.csproj index c66cd9b25..a6d992c0e 100644 --- a/src/Ombi.Schedule/Ombi.Schedule.csproj +++ b/src/Ombi.Schedule/Ombi.Schedule.csproj @@ -6,6 +6,7 @@ 3.0.0.0 + 8.0 diff --git a/src/Ombi.Schedule/OmbiScheduler.cs b/src/Ombi.Schedule/OmbiScheduler.cs index 71f20ad91..6ccdecb45 100644 --- a/src/Ombi.Schedule/OmbiScheduler.cs +++ b/src/Ombi.Schedule/OmbiScheduler.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Threading.Tasks; -using Microsoft.AspNetCore.Builder; using Ombi.Core.Notifications; using Ombi.Core.Settings; using Ombi.Helpers; @@ -16,7 +15,6 @@ using Ombi.Schedule.Jobs.Radarr; using Ombi.Schedule.Jobs.SickRage; using Ombi.Schedule.Jobs.Sonarr; using Ombi.Settings.Settings.Models; -using Quartz; using Quartz.Spi; namespace Ombi.Schedule diff --git a/src/Ombi.Settings.Tests/Ombi.Settings.Tests.csproj b/src/Ombi.Settings.Tests/Ombi.Settings.Tests.csproj index ad99af008..d55c38004 100644 --- a/src/Ombi.Settings.Tests/Ombi.Settings.Tests.csproj +++ b/src/Ombi.Settings.Tests/Ombi.Settings.Tests.csproj @@ -1,6 +1,6 @@ - netcoreapp3.0 + netcoreapp3.1 false diff --git a/src/Ombi.Settings/Ombi.Settings.csproj b/src/Ombi.Settings/Ombi.Settings.csproj index 96f01a823..1012f01e0 100644 --- a/src/Ombi.Settings/Ombi.Settings.csproj +++ b/src/Ombi.Settings/Ombi.Settings.csproj @@ -6,10 +6,11 @@ 3.0.0.0 + 8.0 - + 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.Store/Ombi.Store.csproj b/src/Ombi.Store/Ombi.Store.csproj index b33052157..dade5a1b9 100644 --- a/src/Ombi.Store/Ombi.Store.csproj +++ b/src/Ombi.Store/Ombi.Store.csproj @@ -7,15 +7,18 @@ true + 8.0 - - - - + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + - + diff --git a/src/Ombi.Test.Common/Ombi.Test.Common.csproj b/src/Ombi.Test.Common/Ombi.Test.Common.csproj index d43dad1b2..3c328ec19 100644 --- a/src/Ombi.Test.Common/Ombi.Test.Common.csproj +++ b/src/Ombi.Test.Common/Ombi.Test.Common.csproj @@ -2,6 +2,7 @@ netstandard2.1 + 8.0 diff --git a/src/Ombi.Tests/Ombi.Tests.csproj b/src/Ombi.Tests/Ombi.Tests.csproj index a2ac1aac6..25fdd3ebe 100644 --- a/src/Ombi.Tests/Ombi.Tests.csproj +++ b/src/Ombi.Tests/Ombi.Tests.csproj @@ -1,7 +1,7 @@ - netcoreapp3.0 + netcoreapp3.1 false diff --git a/src/Ombi.TheMovieDbApi/Ombi.Api.TheMovieDb.csproj b/src/Ombi.TheMovieDbApi/Ombi.Api.TheMovieDb.csproj index 8ed3686b7..c3713684c 100644 --- a/src/Ombi.TheMovieDbApi/Ombi.Api.TheMovieDb.csproj +++ b/src/Ombi.TheMovieDbApi/Ombi.Api.TheMovieDb.csproj @@ -7,6 +7,7 @@ 3.0.0.0 + 8.0 diff --git a/src/Ombi.Updater/Ombi.Updater.csproj b/src/Ombi.Updater/Ombi.Updater.csproj index 68adbb762..1a305bb14 100644 --- a/src/Ombi.Updater/Ombi.Updater.csproj +++ b/src/Ombi.Updater/Ombi.Updater.csproj @@ -3,7 +3,7 @@ Exe win10-x64;win10-x86;osx-x64;ubuntu-x64;debian.8-x64;centos.7-x64;linux-x64;linux-arm;linux-arm64; - netcoreapp3.0 + netcoreapp3.1 3.0.0.0 3.0.0.0 @@ -12,14 +12,14 @@ - - - - - - - - + + + + + + + + diff --git a/src/Ombi.sln b/src/Ombi.sln index 57d4962d9..eff7f2e57 100644 --- a/src/Ombi.sln +++ b/src/Ombi.sln @@ -110,7 +110,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ombi.Api.GroupMe", "Ombi.Ap EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ombi.Api.MusicBrainz", "Ombi.Api.MusicBrainz\Ombi.Api.MusicBrainz.csproj", "{C5C1769B-4197-4410-A160-0EEF39EDDC98}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ombi.Api.Twilio", "Ombi.Api.Twilio\Ombi.Api.Twilio.csproj", "{34E5DD1A-6A90-448B-9E71-64D1ACD6C1A3}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ombi.Api.Twilio", "Ombi.Api.Twilio\Ombi.Api.Twilio.csproj", "{34E5DD1A-6A90-448B-9E71-64D1ACD6C1A3}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ombi.HealthChecks", "Ombi.HealthChecks\Ombi.HealthChecks.csproj", "{59D19538-0496-44EE-936E-EBBC22CF7B27}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ombi.Api.Webhook", "Ombi.Api.Webhook\Ombi.Api.Webhook.csproj", "{E2186FDA-D827-4781-8663-130AC382F12C}" EndProject @@ -300,6 +302,10 @@ Global {34E5DD1A-6A90-448B-9E71-64D1ACD6C1A3}.Debug|Any CPU.Build.0 = Debug|Any CPU {34E5DD1A-6A90-448B-9E71-64D1ACD6C1A3}.Release|Any CPU.ActiveCfg = Release|Any CPU {34E5DD1A-6A90-448B-9E71-64D1ACD6C1A3}.Release|Any CPU.Build.0 = Release|Any CPU + {59D19538-0496-44EE-936E-EBBC22CF7B27}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {59D19538-0496-44EE-936E-EBBC22CF7B27}.Debug|Any CPU.Build.0 = Debug|Any CPU + {59D19538-0496-44EE-936E-EBBC22CF7B27}.Release|Any CPU.ActiveCfg = Release|Any CPU + {59D19538-0496-44EE-936E-EBBC22CF7B27}.Release|Any CPU.Build.0 = Release|Any CPU {E2186FDA-D827-4781-8663-130AC382F12C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {E2186FDA-D827-4781-8663-130AC382F12C}.Debug|Any CPU.Build.0 = Debug|Any CPU {E2186FDA-D827-4781-8663-130AC382F12C}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -348,6 +354,7 @@ Global {9266403C-B04D-4C0F-AC39-82F12C781949} = {9293CA11-360A-4C20-A674-B9E794431BF5} {C5C1769B-4197-4410-A160-0EEF39EDDC98} = {9293CA11-360A-4C20-A674-B9E794431BF5} {34E5DD1A-6A90-448B-9E71-64D1ACD6C1A3} = {9293CA11-360A-4C20-A674-B9E794431BF5} + {59D19538-0496-44EE-936E-EBBC22CF7B27} = {410F36CF-9C60-428A-B191-6FD90610991A} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {192E9BF8-00B4-45E4-BCCC-4C215725C869} diff --git a/src/Ombi/.gitignore b/src/Ombi/.gitignore index 49c402ee8..d28f49b37 100644 --- a/src/Ombi/.gitignore +++ b/src/Ombi/.gitignore @@ -7,4 +7,4 @@ wwwroot/dist /connect.lock /coverage/* /Logs/** -**.db +**.db \ 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 - + - - - + + + + + - - Api Key - - + + Api Key + + - - - + + + - - - + + + + + + + + + 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/Controllers/V1/JobController.cs b/src/Ombi/Controllers/V1/JobController.cs index f8f3609e8..668a4ccf4 100644 --- a/src/Ombi/Controllers/V1/JobController.cs +++ b/src/Ombi/Controllers/V1/JobController.cs @@ -67,11 +67,14 @@ namespace Ombi.Controllers.V1 var val = await _memCache.GetOrAdd(CacheKeys.Update, async () => { var productArray = _updater.GetVersion(); - var version = productArray[0]; - var branch = productArray[1]; - var updateAvailable = await _updater.UpdateAvailable(branch, version); + if (productArray.Length > 1) + { + var version = productArray[0]; + var branch = productArray[1]; + var updateAvailable = await _updater.UpdateAvailable(branch, version); + } - return updateAvailable; + return true; }); return val; } diff --git a/src/Ombi/Controllers/V1/SettingsController.cs b/src/Ombi/Controllers/V1/SettingsController.cs index d3a3a5c4c..200fc59d9 100644 --- a/src/Ombi/Controllers/V1/SettingsController.cs +++ b/src/Ombi/Controllers/V1/SettingsController.cs @@ -1145,7 +1145,8 @@ namespace Ombi.Controllers.V1 // Make sure we do not display the newsletter templates = templates.Where(x => x.NotificationType != NotificationType.Newsletter); } - return templates.OrderBy(x => x.NotificationType.ToString()).ToList(); + var tem = templates.ToList(); + return tem.OrderBy(x => x.NotificationType.ToString()).ToList(); } private async Task Get() diff --git a/src/Ombi/Controllers/V2/SystemController.cs b/src/Ombi/Controllers/V2/SystemController.cs index ab1e89578..590c2f2cd 100644 --- a/src/Ombi/Controllers/V2/SystemController.cs +++ b/src/Ombi/Controllers/V2/SystemController.cs @@ -33,18 +33,22 @@ namespace Ombi.Controllers.V2 public async Task ReadLogFile(string logFileName, CancellationToken token) { var logFile = Path.Combine(_hosting.ContentRootPath, "Logs", logFileName); - await using var fs = new FileStream(logFile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); - using StreamReader reader = new StreamReader(fs); - return Ok(await reader.ReadToEndAsync()); + using (var fs = new FileStream(logFile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) + using (StreamReader reader = new StreamReader(fs)) + { + return Ok(await reader.ReadToEndAsync()); + } } - + [HttpGet("logs/download/{logFileName}")] public IActionResult Download(string logFileName, CancellationToken token) { var logFile = Path.Combine(_hosting.ContentRootPath, "Logs", logFileName); - using var fs = new FileStream(logFile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); - using StreamReader reader = new StreamReader(fs); - return File(reader.BaseStream, "application/octet-stream", logFileName); + using (var fs = new FileStream(logFile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) + using (StreamReader reader = new StreamReader(fs)) + { + return File(reader.BaseStream, "application/octet-stream", logFileName); + } } } } \ No newline at end of file diff --git a/src/Ombi/Extensions/DatabaseExtensions.cs b/src/Ombi/Extensions/DatabaseExtensions.cs index 2c6d13d06..21680f8b9 100644 --- a/src/Ombi/Extensions/DatabaseExtensions.cs +++ b/src/Ombi/Extensions/DatabaseExtensions.cs @@ -2,6 +2,7 @@ using System.IO; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Diagnostics.HealthChecks; using Newtonsoft.Json; using Ombi.Helpers; using Ombi.Store.Context; @@ -17,7 +18,7 @@ namespace Ombi.Extensions public const string SqliteDatabase = "Sqlite"; public const string MySqlDatabase = "MySQL"; - public static void ConfigureDatabases(this IServiceCollection services) + public static void ConfigureDatabases(this IServiceCollection services, IHealthChecksBuilder hcBuilder) { var configuration = GetDatabaseConfiguration(); @@ -26,9 +27,11 @@ namespace Ombi.Extensions { case var type when type.Equals(SqliteDatabase, StringComparison.InvariantCultureIgnoreCase): services.AddDbContext(x => ConfigureSqlite(x, configuration.OmbiDatabase)); + AddSqliteHealthCheck(hcBuilder, "Ombi Database", configuration.OmbiDatabase); break; case var type when type.Equals(MySqlDatabase, StringComparison.InvariantCultureIgnoreCase): services.AddDbContext(x => ConfigureMySql(x, configuration.OmbiDatabase)); + AddMySqlHealthCheck(hcBuilder, "Ombi Database", configuration.OmbiDatabase); break; } @@ -36,9 +39,11 @@ namespace Ombi.Extensions { case var type when type.Equals(SqliteDatabase, StringComparison.InvariantCultureIgnoreCase): services.AddDbContext(x => ConfigureSqlite(x, configuration.ExternalDatabase)); + AddSqliteHealthCheck(hcBuilder, "External Database", configuration.ExternalDatabase); break; case var type when type.Equals(MySqlDatabase, StringComparison.InvariantCultureIgnoreCase): services.AddDbContext(x => ConfigureMySql(x, configuration.ExternalDatabase)); + AddMySqlHealthCheck(hcBuilder, "External Database", configuration.ExternalDatabase); break; } @@ -46,9 +51,11 @@ namespace Ombi.Extensions { case var type when type.Equals(SqliteDatabase, StringComparison.InvariantCultureIgnoreCase): services.AddDbContext(x => ConfigureSqlite(x, configuration.SettingsDatabase)); + AddSqliteHealthCheck(hcBuilder, "Settings Database", configuration.SettingsDatabase); break; case var type when type.Equals(MySqlDatabase, StringComparison.InvariantCultureIgnoreCase): services.AddDbContext(x => ConfigureMySql(x, configuration.SettingsDatabase)); + AddMySqlHealthCheck(hcBuilder, "Settings Database", configuration.SettingsDatabase); break; } } @@ -62,7 +69,7 @@ namespace Ombi.Extensions } var databaseFileLocation = Path.Combine(i.StoragePath, "database.json"); - + var configuration = new DatabaseConfiguration(i.StoragePath); if (File.Exists(databaseFileLocation)) { @@ -78,11 +85,36 @@ namespace Ombi.Extensions return configuration; } + + private static void AddSqliteHealthCheck(IHealthChecksBuilder builder, string dbName, PerDatabaseConfiguration config) + { + if (builder != null) + { + builder.AddSqlite( + sqliteConnectionString: config.ConnectionString, + name: dbName, + failureStatus: HealthStatus.Unhealthy, + tags: new string[] { "db" }); + } + } + + private static void AddMySqlHealthCheck(IHealthChecksBuilder builder, string dbName, PerDatabaseConfiguration config) + { + if (builder != null) + { + builder.AddMySql( + connectionString: config.ConnectionString, + name: dbName, + failureStatus: HealthStatus.Unhealthy, + tags: new string[] { "db" } + ); + } + } + public static void ConfigureSqlite(DbContextOptionsBuilder options, PerDatabaseConfiguration config) { SQLitePCL.Batteries.Init(); SQLitePCL.raw.sqlite3_config(raw.SQLITE_CONFIG_MULTITHREAD); - options.UseSqlite(config.ConnectionString); } diff --git a/src/Ombi/HealthCheck.css b/src/Ombi/HealthCheck.css new file mode 100644 index 000000000..fc303c8c9 --- /dev/null +++ b/src/Ombi/HealthCheck.css @@ -0,0 +1,14 @@ +:root { + --primaryColor: #424242; + --secondaryColor: #f9dc43; + --bgMenuActive: #f9dc43; + --bgButton: #f9dc43; + --logoImageUrl: url('https://ombi.io/img/logo-orange-small.png'); + --bgAside: var(--primaryColor); + +} + +#outer-container > aside > nav > a:nth-child(2) { + display: none; +} + diff --git a/src/Ombi/Ombi.csproj b/src/Ombi/Ombi.csproj index 883dad833..ea748694f 100644 --- a/src/Ombi/Ombi.csproj +++ b/src/Ombi/Ombi.csproj @@ -1,6 +1,6 @@ - netcoreapp3.0 + netcoreapp3.1 win10-x64;win10-x86;osx-x64;linux-x64;linux-arm;linux-arm64; false Latest @@ -56,24 +56,29 @@ + + + + + - - + + - + - + - - - + + + @@ -84,6 +89,7 @@ + @@ -92,6 +98,12 @@ + + + Always + + + diff --git a/src/Ombi/Program.cs b/src/Ombi/Program.cs index ac9c5bea0..6ddce97ae 100644 --- a/src/Ombi/Program.cs +++ b/src/Ombi/Program.cs @@ -59,7 +59,7 @@ namespace Ombi //CheckAndMigrate(); var services = new ServiceCollection(); - services.ConfigureDatabases(); + services.ConfigureDatabases(null); using (var provider = services.BuildServiceProvider()) { var settingsDb = provider.GetRequiredService(); diff --git a/src/Ombi/Startup.cs b/src/Ombi/Startup.cs index 44d37509d..2f7c6a346 100644 --- a/src/Ombi/Startup.cs +++ b/src/Ombi/Startup.cs @@ -28,6 +28,9 @@ using Microsoft.AspNetCore.StaticFiles.Infrastructure; using Microsoft.Extensions.Hosting; using Newtonsoft.Json; using ILogger = Serilog.ILogger; +using HealthChecks.UI.Client; +using Microsoft.AspNetCore.Diagnostics.HealthChecks; +using Ombi.HealthChecks; namespace Ombi { @@ -73,8 +76,14 @@ namespace Ombi options.User.AllowedUserNameCharacters = string.Empty; }); - services.ConfigureDatabases(); - services.AddHealthChecks(); + var hcBuilder = services.AddHealthChecks(); + hcBuilder.AddOmbiHealthChecks(); + services.ConfigureDatabases(hcBuilder); + // 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); @@ -107,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 { @@ -204,17 +213,25 @@ namespace Ombi { endpoints.MapControllers(); endpoints.MapHub("/hubs/notification"); - endpoints.MapHealthChecks("/health"); + if (!settings.DisableHealthChecks) + { + endpoints.MapHealthChecks("/health", new HealthCheckOptions + { + Predicate = _ => true, + ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse + }); + endpoints.MapHealthChecksUI(opts => + { + opts.AddCustomStylesheet("HealthCheck.css"); + }); + } }); app.UseSpa(spa => { #if DEBUG - //if (env.IsDevelopment()) - //{ spa.Options.SourcePath = "ClientApp"; spa.UseProxyToSpaDevelopmentServer("http://localhost:3578"); - //} #endif });