From a22f598b0c129110f2a3b663e9b40c84f3a1f02b Mon Sep 17 00:00:00 2001 From: Bogdan Date: Sun, 14 May 2023 19:09:19 +0300 Subject: [PATCH] Minor improvements in health checks --- .../Checks/DownloadClientRootFolderCheck.cs | 8 +-- .../Checks/ImportMechanismCheck.cs | 4 +- .../Checks/IndexerJackettAllCheck.cs | 14 +++-- .../Checks/IndexerLongTermStatusCheck.cs | 13 ++--- .../HealthCheck/Checks/IndexerStatusCheck.cs | 13 ++--- .../HealthCheck/Checks/MountCheck.cs | 8 +-- .../HealthCheck/Checks/ProxyCheck.cs | 47 ++++++++------- .../Checks/RemotePathMappingCheck.cs | 58 ++++++++----------- .../HealthCheck/Checks/RemovedSeriesCheck.cs | 5 +- .../HealthCheck/Checks/RootFolderCheck.cs | 6 +- .../HealthCheck/Checks/SystemTimeCheck.cs | 4 +- .../HealthCheck/Checks/UpdateCheck.cs | 7 +-- 12 files changed, 86 insertions(+), 101 deletions(-) diff --git a/src/NzbDrone.Core/HealthCheck/Checks/DownloadClientRootFolderCheck.cs b/src/NzbDrone.Core/HealthCheck/Checks/DownloadClientRootFolderCheck.cs index 5b2775ed9..16f864981 100644 --- a/src/NzbDrone.Core/HealthCheck/Checks/DownloadClientRootFolderCheck.cs +++ b/src/NzbDrone.Core/HealthCheck/Checks/DownloadClientRootFolderCheck.cs @@ -44,13 +44,11 @@ namespace NzbDrone.Core.HealthCheck.Checks try { var status = client.GetStatus(); - var folders = status.OutputRootFolders; + var folders = status.OutputRootFolders.Where(folder => rootFolders.Any(r => r.Path.PathEquals(folder.FullPath))); + foreach (var folder in folders) { - if (rootFolders.Any(r => r.Path.PathEquals(folder.FullPath))) - { - return new HealthCheck(GetType(), HealthCheckResult.Warning, string.Format("Download client {0} places downloads in the root folder {1}. You should not download to a root folder.", client.Definition.Name, folder.FullPath), "#downloads-in-root-folder"); - } + return new HealthCheck(GetType(), HealthCheckResult.Warning, string.Format("Download client {0} places downloads in the root folder {1}. You should not download to a root folder.", client.Definition.Name, folder.FullPath), "#downloads-in-root-folder"); } } catch (DownloadClientException ex) diff --git a/src/NzbDrone.Core/HealthCheck/Checks/ImportMechanismCheck.cs b/src/NzbDrone.Core/HealthCheck/Checks/ImportMechanismCheck.cs index 64fd8e893..c0b1abbee 100644 --- a/src/NzbDrone.Core/HealthCheck/Checks/ImportMechanismCheck.cs +++ b/src/NzbDrone.Core/HealthCheck/Checks/ImportMechanismCheck.cs @@ -42,10 +42,10 @@ namespace NzbDrone.Core.HealthCheck.Checks return new HealthCheck(GetType()); } - var downloadClientIsLocalHost = downloadClients.All(v => v.Status.IsLocalhost); - if (!_configService.IsDefined("EnableCompletedDownloadHandling")) { + var downloadClientIsLocalHost = downloadClients.All(v => v.Status.IsLocalhost); + // Migration helper logic if (!downloadClientIsLocalHost) { diff --git a/src/NzbDrone.Core/HealthCheck/Checks/IndexerJackettAllCheck.cs b/src/NzbDrone.Core/HealthCheck/Checks/IndexerJackettAllCheck.cs index 28fc9e16a..133b7a6d7 100644 --- a/src/NzbDrone.Core/HealthCheck/Checks/IndexerJackettAllCheck.cs +++ b/src/NzbDrone.Core/HealthCheck/Checks/IndexerJackettAllCheck.cs @@ -21,12 +21,14 @@ namespace NzbDrone.Core.HealthCheck.Checks public override HealthCheck Check() { - var jackettAllProviders = _providerFactory.All().Where( - i => i.ConfigContract.Equals("TorznabSettings") && - ((i.Settings as TorznabSettings).BaseUrl.Contains("/torznab/all/api", StringComparison.InvariantCultureIgnoreCase) || - (i.Settings as TorznabSettings).BaseUrl.Contains("/api/v2.0/indexers/all/results/torznab", StringComparison.InvariantCultureIgnoreCase) || - (i.Settings as TorznabSettings).ApiPath.Contains("/torznab/all/api", StringComparison.InvariantCultureIgnoreCase) || - (i.Settings as TorznabSettings).ApiPath.Contains("/api/v2.0/indexers/all/results/torznab", StringComparison.InvariantCultureIgnoreCase))); + var jackettAllProviders = _providerFactory.All() + .Where( + i => i.ConfigContract.Equals("TorznabSettings") && + (((TorznabSettings)i.Settings).BaseUrl.Contains("/torznab/all/api", StringComparison.InvariantCultureIgnoreCase) || + ((TorznabSettings)i.Settings).BaseUrl.Contains("/api/v2.0/indexers/all/results/torznab", StringComparison.InvariantCultureIgnoreCase) || + ((TorznabSettings)i.Settings).ApiPath.Contains("/torznab/all/api", StringComparison.InvariantCultureIgnoreCase) || + ((TorznabSettings)i.Settings).ApiPath.Contains("/api/v2.0/indexers/all/results/torznab", StringComparison.InvariantCultureIgnoreCase))) + .ToArray(); if (jackettAllProviders.Empty()) { diff --git a/src/NzbDrone.Core/HealthCheck/Checks/IndexerLongTermStatusCheck.cs b/src/NzbDrone.Core/HealthCheck/Checks/IndexerLongTermStatusCheck.cs index 7539a6ffd..268c4787f 100644 --- a/src/NzbDrone.Core/HealthCheck/Checks/IndexerLongTermStatusCheck.cs +++ b/src/NzbDrone.Core/HealthCheck/Checks/IndexerLongTermStatusCheck.cs @@ -24,13 +24,12 @@ namespace NzbDrone.Core.HealthCheck.Checks { var enabledProviders = _providerFactory.GetAvailableProviders(); var backOffProviders = enabledProviders.Join(_providerStatusService.GetBlockedProviders(), - i => i.Definition.Id, - s => s.ProviderId, - (i, s) => new { Provider = i, Status = s }) - .Where(p => p.Status.InitialFailure.HasValue && - p.Status.InitialFailure.Value.Before( - DateTime.UtcNow.AddHours(-6))) - .ToList(); + i => i.Definition.Id, + s => s.ProviderId, + (i, s) => new { Provider = i, Status = s }) + .Where(p => p.Status.InitialFailure.HasValue && + p.Status.InitialFailure.Value.Before(DateTime.UtcNow.AddHours(-6))) + .ToList(); if (backOffProviders.Empty()) { diff --git a/src/NzbDrone.Core/HealthCheck/Checks/IndexerStatusCheck.cs b/src/NzbDrone.Core/HealthCheck/Checks/IndexerStatusCheck.cs index 6b6152558..f78458226 100644 --- a/src/NzbDrone.Core/HealthCheck/Checks/IndexerStatusCheck.cs +++ b/src/NzbDrone.Core/HealthCheck/Checks/IndexerStatusCheck.cs @@ -24,13 +24,12 @@ namespace NzbDrone.Core.HealthCheck.Checks { var enabledProviders = _providerFactory.GetAvailableProviders(); var backOffProviders = enabledProviders.Join(_providerStatusService.GetBlockedProviders(), - i => i.Definition.Id, - s => s.ProviderId, - (i, s) => new { Provider = i, Status = s }) - .Where(p => p.Status.InitialFailure.HasValue && - p.Status.InitialFailure.Value.After( - DateTime.UtcNow.AddHours(-6))) - .ToList(); + i => i.Definition.Id, + s => s.ProviderId, + (i, s) => new { Provider = i, Status = s }) + .Where(p => p.Status.InitialFailure.HasValue && + p.Status.InitialFailure.Value.After(DateTime.UtcNow.AddHours(-6))) + .ToList(); if (backOffProviders.Empty()) { diff --git a/src/NzbDrone.Core/HealthCheck/Checks/MountCheck.cs b/src/NzbDrone.Core/HealthCheck/Checks/MountCheck.cs index fa70365ee..8bee99048 100644 --- a/src/NzbDrone.Core/HealthCheck/Checks/MountCheck.cs +++ b/src/NzbDrone.Core/HealthCheck/Checks/MountCheck.cs @@ -19,10 +19,10 @@ namespace NzbDrone.Core.HealthCheck.Checks { // Not best for optimization but due to possible symlinks and junctions, we get mounts based on series path so internals can handle mount resolution. var mounts = _seriesService.GetAllSeriesPaths() - .Select(s => _diskProvider.GetMount(s.Value)) - .Where(m => m != null && m.MountOptions != null && m.MountOptions.IsReadOnly) - .DistinctBy(m => m.RootDirectory) - .ToList(); + .Select(s => _diskProvider.GetMount(s.Value)) + .Where(m => m is { MountOptions.IsReadOnly: true }) + .DistinctBy(m => m.RootDirectory) + .ToList(); if (mounts.Any()) { diff --git a/src/NzbDrone.Core/HealthCheck/Checks/ProxyCheck.cs b/src/NzbDrone.Core/HealthCheck/Checks/ProxyCheck.cs index f80767337..2af1b2078 100644 --- a/src/NzbDrone.Core/HealthCheck/Checks/ProxyCheck.cs +++ b/src/NzbDrone.Core/HealthCheck/Checks/ProxyCheck.cs @@ -29,35 +29,38 @@ namespace NzbDrone.Core.HealthCheck.Checks public override HealthCheck Check() { - if (_configService.ProxyEnabled) + if (!_configService.ProxyEnabled) { - var addresses = Dns.GetHostAddresses(_configService.ProxyHostname); - if (!addresses.Any()) - { - return new HealthCheck(GetType(), HealthCheckResult.Error, string.Format("Failed to resolve the IP Address for the Configured Proxy Host {0}", _configService.ProxyHostname), "#proxy-failed-resolve-ip"); - } + return new HealthCheck(GetType()); + } - var request = _cloudRequestBuilder.Create() - .Resource("/ping") - .Build(); + var addresses = Dns.GetHostAddresses(_configService.ProxyHostname); - try - { - var response = _client.Execute(request); + if (!addresses.Any()) + { + return new HealthCheck(GetType(), HealthCheckResult.Error, string.Format("Failed to resolve the IP Address for the Configured Proxy Host {0}", _configService.ProxyHostname), "#proxy-failed-resolve-ip"); + } - // We only care about 400 responses, other error codes can be ignored - if (response.StatusCode == HttpStatusCode.BadRequest) - { - _logger.Error("Proxy Health Check failed: {0}", response.StatusCode); - return new HealthCheck(GetType(), HealthCheckResult.Error, $"Failed to test proxy. StatusCode: {response.StatusCode}", "#proxy-failed-test"); - } - } - catch (Exception ex) + var request = _cloudRequestBuilder.Create() + .Resource("/ping") + .Build(); + + try + { + var response = _client.Execute(request); + + // We only care about 400 responses, other error codes can be ignored + if (response.StatusCode == HttpStatusCode.BadRequest) { - _logger.Error(ex, "Proxy Health Check failed"); - return new HealthCheck(GetType(), HealthCheckResult.Error, $"Failed to test proxy: {request.Url}", "#proxy-failed-test"); + _logger.Error("Proxy Health Check failed: {0}", response.StatusCode); + return new HealthCheck(GetType(), HealthCheckResult.Error, $"Failed to test proxy. StatusCode: {response.StatusCode}", "#proxy-failed-test"); } } + catch (Exception ex) + { + _logger.Error(ex, "Proxy Health Check failed"); + return new HealthCheck(GetType(), HealthCheckResult.Error, $"Failed to test proxy: {request.Url}", "#proxy-failed-test"); + } return new HealthCheck(GetType()); } diff --git a/src/NzbDrone.Core/HealthCheck/Checks/RemotePathMappingCheck.cs b/src/NzbDrone.Core/HealthCheck/Checks/RemotePathMappingCheck.cs index b1ebdd451..545df8c10 100644 --- a/src/NzbDrone.Core/HealthCheck/Checks/RemotePathMappingCheck.cs +++ b/src/NzbDrone.Core/HealthCheck/Checks/RemotePathMappingCheck.cs @@ -67,14 +67,13 @@ namespace NzbDrone.Core.HealthCheck.Checks { return new HealthCheck(GetType(), HealthCheckResult.Error, string.Format("Remote download client {0} places downloads in {1} but this is not a valid {2} path. Review your remote path mappings and download client settings.", client.Definition.Name, folder.FullPath, _osInfo.Name), "#bad-remote-path-mapping"); } - else if (_osInfo.IsDocker) + + if (_osInfo.IsDocker) { return new HealthCheck(GetType(), HealthCheckResult.Error, string.Format("You are using docker; download client {0} reported files in {1} but this is not a valid {2} path. Review your remote path mappings and download client settings.", client.Definition.Name, folder.FullPath, _osInfo.Name), "#docker-bad-remote-path-mapping"); } - else - { - return new HealthCheck(GetType(), HealthCheckResult.Error, string.Format("Local download client {0} places downloads in {1} but this is not a valid {2} path. Review your download client settings.", client.Definition.Name, folder.FullPath, _osInfo.Name), "#bad-download-client-settings"); - } + + return new HealthCheck(GetType(), HealthCheckResult.Error, string.Format("Local download client {0} places downloads in {1} but this is not a valid {2} path. Review your download client settings.", client.Definition.Name, folder.FullPath, _osInfo.Name), "#bad-download-client-settings"); } if (!_diskProvider.FolderExists(folder.FullPath)) @@ -83,14 +82,13 @@ namespace NzbDrone.Core.HealthCheck.Checks { return new HealthCheck(GetType(), HealthCheckResult.Error, string.Format("You are using docker; download client {0} places downloads in {1} but this directory does not appear to exist inside the container. Review your remote path mappings and container volume settings.", client.Definition.Name, folder.FullPath), "#docker-bad-remote-path-mapping"); } - else if (!status.IsLocalhost) + + if (!status.IsLocalhost) { return new HealthCheck(GetType(), HealthCheckResult.Error, string.Format("Remote download client {0} places downloads in {1} but this directory does not appear to exist. Likely missing or incorrect remote path mapping.", client.Definition.Name, folder.FullPath), "#bad-remote-path-mapping"); } - else - { - return new HealthCheck(GetType(), HealthCheckResult.Error, string.Format("Download client {0} places downloads in {1} but Sonarr cannot see this directory. You may need to adjust the folder's permissions.", client.Definition.Name, folder.FullPath), "#permissions-error"); - } + + return new HealthCheck(GetType(), HealthCheckResult.Error, string.Format("Download client {0} places downloads in {1} but Sonarr cannot see this directory. You may need to adjust the folder's permissions.", client.Definition.Name, folder.FullPath), "#permissions-error"); } } } @@ -119,10 +117,8 @@ namespace NzbDrone.Core.HealthCheck.Checks return new HealthCheck(GetType()); } - if (typeof(EpisodeImportFailedEvent).IsAssignableFrom(message.GetType())) + if (message is EpisodeImportFailedEvent failureMessage) { - var failureMessage = (EpisodeImportFailedEvent)message; - // if we can see the file exists but the import failed then likely a permissions issue if (failureMessage.EpisodeInfo != null) { @@ -132,12 +128,10 @@ namespace NzbDrone.Core.HealthCheck.Checks { return new HealthCheck(GetType(), HealthCheckResult.Error, string.Format("Sonarr can see but not access downloaded episode {0}. Likely permissions error.", episodePath), "#permissions-error"); } - else - { - // If the file doesn't exist but EpisodeInfo is not null then the message is coming from - // ImportApprovedEpisodes and the file must have been removed part way through processing - return new HealthCheck(GetType(), HealthCheckResult.Error, string.Format("File {0} was removed part way through processing.", episodePath), "#remote-path-file-removed"); - } + + // If the file doesn't exist but EpisodeInfo is not null then the message is coming from + // ImportApprovedEpisodes and the file must have been removed part way through processing + return new HealthCheck(GetType(), HealthCheckResult.Error, string.Format("File {0} was removed part way through processing.", episodePath), "#remote-path-file-removed"); } // If the previous case did not match then the failure occured in DownloadedEpisodeImportService, @@ -168,14 +162,13 @@ namespace NzbDrone.Core.HealthCheck.Checks { return new HealthCheck(GetType(), HealthCheckResult.Error, string.Format("Remote download client {0} reported files in {1} but this is not a valid {2} path. Review your remote path mappings and download client settings.", client.Definition.Name, dlpath, _osInfo.Name), "#bad-remote-path-mapping"); } - else if (_osInfo.IsDocker) + + if (_osInfo.IsDocker) { return new HealthCheck(GetType(), HealthCheckResult.Error, string.Format("You are using docker; download client {0} reported files in {1} but this is not a valid {2} path. Review your remote path mappings and download client settings.", client.Definition.Name, dlpath, _osInfo.Name), "#docker-bad-remote-path-mapping"); } - else - { - return new HealthCheck(GetType(), HealthCheckResult.Error, string.Format("Local download client {0} reported files in {1} but this is not a valid {2} path. Review your download client settings.", client.Definition.Name, dlpath, _osInfo.Name), "#bad-download-client-settings"); - } + + return new HealthCheck(GetType(), HealthCheckResult.Error, string.Format("Local download client {0} reported files in {1} but this is not a valid {2} path. Review your download client settings.", client.Definition.Name, dlpath, _osInfo.Name), "#bad-download-client-settings"); } if (_diskProvider.FolderExists(dlpath)) @@ -188,15 +181,14 @@ namespace NzbDrone.Core.HealthCheck.Checks { return new HealthCheck(GetType(), HealthCheckResult.Error, string.Format("Sonarr can see but not access download directory {0}. Likely permissions error.", client.Definition.Name, dlpath), "#docker-bad-remote-path-mapping"); } - else if (!status.IsLocalhost) + + if (!status.IsLocalhost) { return new HealthCheck(GetType(), HealthCheckResult.Error, string.Format("Remote download client {0} reported files in {1} but this directory does not appear to exist. Likely missing remote path mapping.", client.Definition.Name, dlpath), "#bad-remote-path-mapping"); } - else - { - // path mappings shouldn't be needed locally so probably a permissions issue - return new HealthCheck(GetType(), HealthCheckResult.Error, string.Format("Download client {0} reported files in {1} but Sonarr cannot see this directory. You may need to adjust the folder's permissions.", client.Definition.Name, dlpath), "#permissions-error"); - } + + // path mappings shouldn't be needed locally so probably a permissions issue + return new HealthCheck(GetType(), HealthCheckResult.Error, string.Format("Download client {0} reported files in {1} but Sonarr cannot see this directory. You may need to adjust the folder's permissions.", client.Definition.Name, dlpath), "#permissions-error"); } catch (DownloadClientException ex) { @@ -213,10 +205,8 @@ namespace NzbDrone.Core.HealthCheck.Checks return new HealthCheck(GetType()); } - else - { - return Check(); - } + + return Check(); } } } diff --git a/src/NzbDrone.Core/HealthCheck/Checks/RemovedSeriesCheck.cs b/src/NzbDrone.Core/HealthCheck/Checks/RemovedSeriesCheck.cs index 36c1e7cca..97643b1d3 100644 --- a/src/NzbDrone.Core/HealthCheck/Checks/RemovedSeriesCheck.cs +++ b/src/NzbDrone.Core/HealthCheck/Checks/RemovedSeriesCheck.cs @@ -1,5 +1,4 @@ using System.Linq; -using NLog; using NzbDrone.Common.Extensions; using NzbDrone.Core.Tv; using NzbDrone.Core.Tv.Events; @@ -12,12 +11,10 @@ namespace NzbDrone.Core.HealthCheck.Checks public class RemovedSeriesCheck : HealthCheckBase, ICheckOnCondition, ICheckOnCondition { private readonly ISeriesService _seriesService; - private readonly Logger _logger; - public RemovedSeriesCheck(ISeriesService seriesService, Logger logger) + public RemovedSeriesCheck(ISeriesService seriesService) { _seriesService = seriesService; - _logger = logger; } public override HealthCheck Check() diff --git a/src/NzbDrone.Core/HealthCheck/Checks/RootFolderCheck.cs b/src/NzbDrone.Core/HealthCheck/Checks/RootFolderCheck.cs index 80ff14f61..d735c4fb6 100644 --- a/src/NzbDrone.Core/HealthCheck/Checks/RootFolderCheck.cs +++ b/src/NzbDrone.Core/HealthCheck/Checks/RootFolderCheck.cs @@ -27,11 +27,11 @@ namespace NzbDrone.Core.HealthCheck.Checks public override HealthCheck Check() { var rootFolders = _seriesService.GetAllSeriesPaths() - .Select(s => _rootFolderService.GetBestRootFolderPath(s.Value)) - .Distinct(); + .Select(s => _rootFolderService.GetBestRootFolderPath(s.Value)) + .Distinct(); var missingRootFolders = rootFolders.Where(s => !_diskProvider.FolderExists(s)) - .ToList(); + .ToList(); if (missingRootFolders.Any()) { diff --git a/src/NzbDrone.Core/HealthCheck/Checks/SystemTimeCheck.cs b/src/NzbDrone.Core/HealthCheck/Checks/SystemTimeCheck.cs index 86fe653d7..183c64585 100644 --- a/src/NzbDrone.Core/HealthCheck/Checks/SystemTimeCheck.cs +++ b/src/NzbDrone.Core/HealthCheck/Checks/SystemTimeCheck.cs @@ -22,8 +22,8 @@ namespace NzbDrone.Core.HealthCheck.Checks public override HealthCheck Check() { var request = _cloudRequestBuilder.Create() - .Resource("/time") - .Build(); + .Resource("/time") + .Build(); var response = _client.Execute(request); var result = Json.Deserialize(response.Content); diff --git a/src/NzbDrone.Core/HealthCheck/Checks/UpdateCheck.cs b/src/NzbDrone.Core/HealthCheck/Checks/UpdateCheck.cs index 0bf858846..8f3da9391 100644 --- a/src/NzbDrone.Core/HealthCheck/Checks/UpdateCheck.cs +++ b/src/NzbDrone.Core/HealthCheck/Checks/UpdateCheck.cs @@ -65,12 +65,9 @@ namespace NzbDrone.Core.HealthCheck.Checks } } - if (BuildInfo.BuildDateTime < DateTime.UtcNow.AddDays(-14)) + if (BuildInfo.BuildDateTime < DateTime.UtcNow.AddDays(-14) && _checkUpdateService.AvailableUpdate() != null) { - if (_checkUpdateService.AvailableUpdate() != null) - { - return new HealthCheck(GetType(), HealthCheckResult.Warning, "New update is available"); - } + return new HealthCheck(GetType(), HealthCheckResult.Warning, "New update is available"); } return new HealthCheck(GetType());