New: Health Check warning if series folder is mounted with 'ro' option on linux

Closes #1867
pull/94/head
Kyse 7 years ago committed by Qstick
parent a37be66f34
commit 889b963429

@ -1,4 +1,5 @@
using System.IO; using System.Collections.Generic;
using System.IO;
using NzbDrone.Common.Extensions; using NzbDrone.Common.Extensions;
namespace NzbDrone.Common.Disk namespace NzbDrone.Common.Disk
@ -8,10 +9,11 @@ namespace NzbDrone.Common.Disk
private readonly DriveInfo _driveInfo; private readonly DriveInfo _driveInfo;
private readonly DriveType _driveType; private readonly DriveType _driveType;
public DriveInfoMount(DriveInfo driveInfo, DriveType driveType = DriveType.Unknown) public DriveInfoMount(DriveInfo driveInfo, DriveType driveType = DriveType.Unknown, MountOptions mountOptions = null)
{ {
_driveInfo = driveInfo; _driveInfo = driveInfo;
_driveType = driveType; _driveType = driveType;
MountOptions = mountOptions;
} }
public long AvailableFreeSpace => _driveInfo.AvailableFreeSpace; public long AvailableFreeSpace => _driveInfo.AvailableFreeSpace;
@ -33,6 +35,8 @@ namespace NzbDrone.Common.Disk
public bool IsReady => _driveInfo.IsReady; public bool IsReady => _driveInfo.IsReady;
public MountOptions MountOptions { get; private set; }
public string Name => _driveInfo.Name; public string Name => _driveInfo.Name;
public string RootDirectory => _driveInfo.RootDirectory.FullName; public string RootDirectory => _driveInfo.RootDirectory.FullName;

@ -1,3 +1,4 @@
using System.Collections.Generic;
using System.IO; using System.IO;
namespace NzbDrone.Common.Disk namespace NzbDrone.Common.Disk
@ -8,6 +9,7 @@ namespace NzbDrone.Common.Disk
string DriveFormat { get; } string DriveFormat { get; }
DriveType DriveType { get; } DriveType DriveType { get; }
bool IsReady { get; } bool IsReady { get; }
MountOptions MountOptions { get; }
string Name { get; } string Name { get; }
string RootDirectory { get; } string RootDirectory { get; }
long TotalFreeSpace { get; } long TotalFreeSpace { get; }

@ -0,0 +1,16 @@
using System.Collections.Generic;
namespace NzbDrone.Common.Disk
{
public class MountOptions
{
private readonly Dictionary<string, string> _options;
public MountOptions(Dictionary<string, string> options)
{
_options = options;
}
public bool IsReadOnly => _options.ContainsKey("ro");
}
}

@ -88,6 +88,7 @@
<Compile Include="Disk\FileSystemLookupService.cs" /> <Compile Include="Disk\FileSystemLookupService.cs" />
<Compile Include="Disk\DriveInfoMount.cs" /> <Compile Include="Disk\DriveInfoMount.cs" />
<Compile Include="Disk\IMount.cs" /> <Compile Include="Disk\IMount.cs" />
<Compile Include="Disk\MountOptions.cs" />
<Compile Include="Disk\RelativeFileSystemModel.cs" /> <Compile Include="Disk\RelativeFileSystemModel.cs" />
<Compile Include="Disk\FileSystemModel.cs" /> <Compile Include="Disk\FileSystemModel.cs" />
<Compile Include="Disk\FileSystemResult.cs" /> <Compile Include="Disk\FileSystemResult.cs" />

@ -0,0 +1,36 @@
using System.Linq;
using NzbDrone.Common.Disk;
using NzbDrone.Common.Extensions;
using NzbDrone.Core.Tv;
namespace NzbDrone.Core.HealthCheck.Checks
{
public class MountCheck : HealthCheckBase
{
private readonly IDiskProvider _diskProvider;
private readonly ISeriesService _seriesService;
public MountCheck(IDiskProvider diskProvider, ISeriesService seriesService)
{
_diskProvider = diskProvider;
_seriesService = seriesService;
}
public override HealthCheck Check()
{
// 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.GetAllSeries()
.Select(series => _diskProvider.GetMount(series.Path))
.DistinctBy(m => m.RootDirectory)
.Where(m => m.MountOptions != null && m.MountOptions.IsReadOnly)
.ToList();
if (mounts.Any())
{
return new HealthCheck(GetType(), HealthCheckResult.Error, "Mount containing a series path is mounted read-only: " + string.Join(",", mounts.Select(m => m.Name)), "#series-mount-ro");
}
return new HealthCheck(GetType());
}
}
}

@ -572,6 +572,8 @@
<Compile Include="HealthCheck\CheckHealthCommand.cs" /> <Compile Include="HealthCheck\CheckHealthCommand.cs" />
<Compile Include="HealthCheck\Checks\AppDataLocationCheck.cs" /> <Compile Include="HealthCheck\Checks\AppDataLocationCheck.cs" />
<Compile Include="HealthCheck\Checks\DownloadClientCheck.cs" /> <Compile Include="HealthCheck\Checks\DownloadClientCheck.cs" />
<Compile Include="HealthCheck\Checks\MountCheck.cs" />
<Compile Include="HealthCheck\Checks\DroneFactoryCheck.cs" />
<Compile Include="HealthCheck\Checks\ImportMechanismCheck.cs" /> <Compile Include="HealthCheck\Checks\ImportMechanismCheck.cs" />
<Compile Include="HealthCheck\Checks\IndexerRssCheck.cs" /> <Compile Include="HealthCheck\Checks\IndexerRssCheck.cs" />
<Compile Include="HealthCheck\Checks\IndexerStatusCheck.cs" /> <Compile Include="HealthCheck\Checks\IndexerStatusCheck.cs" />

@ -86,11 +86,14 @@ namespace NzbDrone.Mono.Disk
public override List<IMount> GetMounts() public override List<IMount> GetMounts()
{ {
return GetDriveInfoMounts().Select(d => new DriveInfoMount(d, FindDriveType.Find(d.DriveFormat))) return _procMountProvider.GetMounts()
.Where(d => d.DriveType == DriveType.Fixed || d.DriveType == DriveType.Network || d.DriveType == DriveType.Removable) .Concat(GetDriveInfoMounts()
.Concat(_procMountProvider.GetMounts()) .Select(d => new DriveInfoMount(d, FindDriveType.Find(d.DriveFormat)))
.DistinctBy(v => v.RootDirectory) .Where(d => d.DriveType == DriveType.Fixed ||
.ToList(); d.DriveType == DriveType.Network || d.DriveType ==
DriveType.Removable))
.DistinctBy(v => v.RootDirectory)
.ToList();
} }
public override long? GetTotalSize(string path) public override long? GetTotalSize(string path)

@ -1,4 +1,4 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using Mono.Unix; using Mono.Unix;
using NzbDrone.Common.Disk; using NzbDrone.Common.Disk;
@ -10,12 +10,13 @@ namespace NzbDrone.Mono.Disk
{ {
private readonly UnixDriveInfo _unixDriveInfo; private readonly UnixDriveInfo _unixDriveInfo;
public ProcMount(DriveType driveType, string name, string mount, string type, Dictionary<string, string> options) public ProcMount(DriveType driveType, string name, string mount, string type, MountOptions mountOptions)
{ {
DriveType = driveType; DriveType = driveType;
Name = name; Name = name;
RootDirectory = mount; RootDirectory = mount;
DriveFormat = type; DriveFormat = type;
MountOptions = mountOptions;
_unixDriveInfo = new UnixDriveInfo(mount); _unixDriveInfo = new UnixDriveInfo(mount);
} }
@ -28,6 +29,8 @@ namespace NzbDrone.Mono.Disk
public bool IsReady => _unixDriveInfo.IsReady; public bool IsReady => _unixDriveInfo.IsReady;
public MountOptions MountOptions { get; private set; }
public string Name { get; private set; } public string Name { get; private set; }
public string RootDirectory { get; private set; } public string RootDirectory { get; private set; }

@ -130,7 +130,7 @@ namespace NzbDrone.Mono.Disk
driveType = DriveType.Network; driveType = DriveType.Network;
} }
return new ProcMount(driveType, name, mount, type, options); return new ProcMount(driveType, name, mount, type, new MountOptions(options));
} }
private Dictionary<string, string> ParseOptions(string options) private Dictionary<string, string> ParseOptions(string options)

Loading…
Cancel
Save