Minor improvements in health checks

This commit is contained in:
Bogdan 2023-05-14 19:09:19 +03:00 committed by Mark McDowall
parent 86a7f7bd54
commit a22f598b0c
12 changed files with 86 additions and 101 deletions

View File

@ -44,13 +44,11 @@ namespace NzbDrone.Core.HealthCheck.Checks
try try
{ {
var status = client.GetStatus(); 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) 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) catch (DownloadClientException ex)

View File

@ -42,10 +42,10 @@ namespace NzbDrone.Core.HealthCheck.Checks
return new HealthCheck(GetType()); return new HealthCheck(GetType());
} }
var downloadClientIsLocalHost = downloadClients.All(v => v.Status.IsLocalhost);
if (!_configService.IsDefined("EnableCompletedDownloadHandling")) if (!_configService.IsDefined("EnableCompletedDownloadHandling"))
{ {
var downloadClientIsLocalHost = downloadClients.All(v => v.Status.IsLocalhost);
// Migration helper logic // Migration helper logic
if (!downloadClientIsLocalHost) if (!downloadClientIsLocalHost)
{ {

View File

@ -21,12 +21,14 @@ namespace NzbDrone.Core.HealthCheck.Checks
public override HealthCheck Check() public override HealthCheck Check()
{ {
var jackettAllProviders = _providerFactory.All().Where( var jackettAllProviders = _providerFactory.All()
i => i.ConfigContract.Equals("TorznabSettings") && .Where(
((i.Settings as TorznabSettings).BaseUrl.Contains("/torznab/all/api", StringComparison.InvariantCultureIgnoreCase) || i => i.ConfigContract.Equals("TorznabSettings") &&
(i.Settings as TorznabSettings).BaseUrl.Contains("/api/v2.0/indexers/all/results/torznab", StringComparison.InvariantCultureIgnoreCase) || (((TorznabSettings)i.Settings).BaseUrl.Contains("/torznab/all/api", StringComparison.InvariantCultureIgnoreCase) ||
(i.Settings as TorznabSettings).ApiPath.Contains("/torznab/all/api", StringComparison.InvariantCultureIgnoreCase) || ((TorznabSettings)i.Settings).BaseUrl.Contains("/api/v2.0/indexers/all/results/torznab", StringComparison.InvariantCultureIgnoreCase) ||
(i.Settings as TorznabSettings).ApiPath.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()) if (jackettAllProviders.Empty())
{ {

View File

@ -24,13 +24,12 @@ namespace NzbDrone.Core.HealthCheck.Checks
{ {
var enabledProviders = _providerFactory.GetAvailableProviders(); var enabledProviders = _providerFactory.GetAvailableProviders();
var backOffProviders = enabledProviders.Join(_providerStatusService.GetBlockedProviders(), var backOffProviders = enabledProviders.Join(_providerStatusService.GetBlockedProviders(),
i => i.Definition.Id, i => i.Definition.Id,
s => s.ProviderId, s => s.ProviderId,
(i, s) => new { Provider = i, Status = s }) (i, s) => new { Provider = i, Status = s })
.Where(p => p.Status.InitialFailure.HasValue && .Where(p => p.Status.InitialFailure.HasValue &&
p.Status.InitialFailure.Value.Before( p.Status.InitialFailure.Value.Before(DateTime.UtcNow.AddHours(-6)))
DateTime.UtcNow.AddHours(-6))) .ToList();
.ToList();
if (backOffProviders.Empty()) if (backOffProviders.Empty())
{ {

View File

@ -24,13 +24,12 @@ namespace NzbDrone.Core.HealthCheck.Checks
{ {
var enabledProviders = _providerFactory.GetAvailableProviders(); var enabledProviders = _providerFactory.GetAvailableProviders();
var backOffProviders = enabledProviders.Join(_providerStatusService.GetBlockedProviders(), var backOffProviders = enabledProviders.Join(_providerStatusService.GetBlockedProviders(),
i => i.Definition.Id, i => i.Definition.Id,
s => s.ProviderId, s => s.ProviderId,
(i, s) => new { Provider = i, Status = s }) (i, s) => new { Provider = i, Status = s })
.Where(p => p.Status.InitialFailure.HasValue && .Where(p => p.Status.InitialFailure.HasValue &&
p.Status.InitialFailure.Value.After( p.Status.InitialFailure.Value.After(DateTime.UtcNow.AddHours(-6)))
DateTime.UtcNow.AddHours(-6))) .ToList();
.ToList();
if (backOffProviders.Empty()) if (backOffProviders.Empty())
{ {

View File

@ -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. // 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() var mounts = _seriesService.GetAllSeriesPaths()
.Select(s => _diskProvider.GetMount(s.Value)) .Select(s => _diskProvider.GetMount(s.Value))
.Where(m => m != null && m.MountOptions != null && m.MountOptions.IsReadOnly) .Where(m => m is { MountOptions.IsReadOnly: true })
.DistinctBy(m => m.RootDirectory) .DistinctBy(m => m.RootDirectory)
.ToList(); .ToList();
if (mounts.Any()) if (mounts.Any())
{ {

View File

@ -29,35 +29,38 @@ namespace NzbDrone.Core.HealthCheck.Checks
public override HealthCheck Check() public override HealthCheck Check()
{ {
if (_configService.ProxyEnabled) if (!_configService.ProxyEnabled)
{ {
var addresses = Dns.GetHostAddresses(_configService.ProxyHostname); return new HealthCheck(GetType());
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");
}
var request = _cloudRequestBuilder.Create() var addresses = Dns.GetHostAddresses(_configService.ProxyHostname);
.Resource("/ping")
.Build();
try if (!addresses.Any())
{ {
var response = _client.Execute(request); 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 var request = _cloudRequestBuilder.Create()
if (response.StatusCode == HttpStatusCode.BadRequest) .Resource("/ping")
{ .Build();
_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"); try
} {
} var response = _client.Execute(request);
catch (Exception ex)
// We only care about 400 responses, other error codes can be ignored
if (response.StatusCode == HttpStatusCode.BadRequest)
{ {
_logger.Error(ex, "Proxy Health Check failed"); _logger.Error("Proxy Health Check failed: {0}", response.StatusCode);
return new HealthCheck(GetType(), HealthCheckResult.Error, $"Failed to test proxy: {request.Url}", "#proxy-failed-test"); 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()); return new HealthCheck(GetType());
} }

View File

@ -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"); 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"); 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)) 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"); 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"); 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()); 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 we can see the file exists but the import failed then likely a permissions issue
if (failureMessage.EpisodeInfo != null) 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"); 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
// 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
// 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");
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, // 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"); 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"); 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)) 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"); 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"); 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
// 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");
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) catch (DownloadClientException ex)
{ {
@ -213,10 +205,8 @@ namespace NzbDrone.Core.HealthCheck.Checks
return new HealthCheck(GetType()); return new HealthCheck(GetType());
} }
else
{ return Check();
return Check();
}
} }
} }
} }

View File

@ -1,5 +1,4 @@
using System.Linq; using System.Linq;
using NLog;
using NzbDrone.Common.Extensions; using NzbDrone.Common.Extensions;
using NzbDrone.Core.Tv; using NzbDrone.Core.Tv;
using NzbDrone.Core.Tv.Events; using NzbDrone.Core.Tv.Events;
@ -12,12 +11,10 @@ namespace NzbDrone.Core.HealthCheck.Checks
public class RemovedSeriesCheck : HealthCheckBase, ICheckOnCondition<SeriesUpdatedEvent>, ICheckOnCondition<SeriesDeletedEvent> public class RemovedSeriesCheck : HealthCheckBase, ICheckOnCondition<SeriesUpdatedEvent>, ICheckOnCondition<SeriesDeletedEvent>
{ {
private readonly ISeriesService _seriesService; private readonly ISeriesService _seriesService;
private readonly Logger _logger;
public RemovedSeriesCheck(ISeriesService seriesService, Logger logger) public RemovedSeriesCheck(ISeriesService seriesService)
{ {
_seriesService = seriesService; _seriesService = seriesService;
_logger = logger;
} }
public override HealthCheck Check() public override HealthCheck Check()

View File

@ -27,11 +27,11 @@ namespace NzbDrone.Core.HealthCheck.Checks
public override HealthCheck Check() public override HealthCheck Check()
{ {
var rootFolders = _seriesService.GetAllSeriesPaths() var rootFolders = _seriesService.GetAllSeriesPaths()
.Select(s => _rootFolderService.GetBestRootFolderPath(s.Value)) .Select(s => _rootFolderService.GetBestRootFolderPath(s.Value))
.Distinct(); .Distinct();
var missingRootFolders = rootFolders.Where(s => !_diskProvider.FolderExists(s)) var missingRootFolders = rootFolders.Where(s => !_diskProvider.FolderExists(s))
.ToList(); .ToList();
if (missingRootFolders.Any()) if (missingRootFolders.Any())
{ {

View File

@ -22,8 +22,8 @@ namespace NzbDrone.Core.HealthCheck.Checks
public override HealthCheck Check() public override HealthCheck Check()
{ {
var request = _cloudRequestBuilder.Create() var request = _cloudRequestBuilder.Create()
.Resource("/time") .Resource("/time")
.Build(); .Build();
var response = _client.Execute(request); var response = _client.Execute(request);
var result = Json.Deserialize<ServiceTimeResponse>(response.Content); var result = Json.Deserialize<ServiceTimeResponse>(response.Content);

View File

@ -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()); return new HealthCheck(GetType());