Skip to content

Commit

Permalink
New: Optionally use Environment Variables for settings in config.xml
Browse files Browse the repository at this point in the history
  • Loading branch information
sillock1 authored and mynameisbogdan committed May 12, 2024
1 parent 2621acd commit 30d9891
Show file tree
Hide file tree
Showing 10 changed files with 157 additions and 34 deletions.
22 changes: 22 additions & 0 deletions src/NzbDrone.Common.Test/ConfigFileProviderTest.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
using System.Collections.Generic;
using FluentAssertions;
using Microsoft.Extensions.Options;
using Moq;
using NUnit.Framework;
using NzbDrone.Common.Disk;
using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Common.Extensions;
using NzbDrone.Common.Options;
using NzbDrone.Core.Authentication;
using NzbDrone.Core.Configuration;
using NzbDrone.Test.Common;
Expand Down Expand Up @@ -43,6 +45,26 @@ protected void WithMockConfigFile(string configFile)
Mocker.GetMock<IDiskProvider>()
.Setup(v => v.WriteAllText(configFile, It.IsAny<string>()))
.Callback<string, string>((p, t) => _configFileContents = t);

Mocker.GetMock<IOptions<AuthOptions>>()
.Setup(v => v.Value)
.Returns(new AuthOptions());

Mocker.GetMock<IOptions<AppOptions>>()
.Setup(v => v.Value)
.Returns(new AppOptions());

Mocker.GetMock<IOptions<ServerOptions>>()
.Setup(v => v.Value)
.Returns(new ServerOptions());

Mocker.GetMock<IOptions<LogOptions>>()
.Setup(v => v.Value)
.Returns(new LogOptions());

Mocker.GetMock<IOptions<UpdateOptions>>()
.Setup(v => v.Value)
.Returns(new UpdateOptions());
}

[Test]
Expand Down
6 changes: 6 additions & 0 deletions src/NzbDrone.Common.Test/ServiceFactoryFixture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
using NzbDrone.Common.Composition.Extensions;
using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Common.Instrumentation.Extensions;
using NzbDrone.Common.Options;
using NzbDrone.Core.Datastore;
using NzbDrone.Core.Datastore.Extensions;
using NzbDrone.Core.Lifecycle;
Expand All @@ -33,6 +34,11 @@ public void event_handlers_should_be_unique()

container.RegisterInstance(new Mock<IHostLifetime>().Object);
container.RegisterInstance(new Mock<IOptions<PostgresOptions>>().Object);
container.RegisterInstance(new Mock<IOptions<AppOptions>>().Object);
container.RegisterInstance(new Mock<IOptions<AuthOptions>>().Object);
container.RegisterInstance(new Mock<IOptions<ServerOptions>>().Object);
container.RegisterInstance(new Mock<IOptions<LogOptions>>().Object);
container.RegisterInstance(new Mock<IOptions<UpdateOptions>>().Object);

var serviceProvider = container.GetServiceProvider();

Expand Down
8 changes: 8 additions & 0 deletions src/NzbDrone.Common/Options/AppOptions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace NzbDrone.Common.Options;

public class AppOptions
{
public string InstanceName { get; set; }
public string Theme { get; set; }
public bool? LaunchBrowser { get; set; }
}
9 changes: 9 additions & 0 deletions src/NzbDrone.Common/Options/AuthOptions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace NzbDrone.Common.Options;

public class AuthOptions
{
public string ApiKey { get; set; }
public bool? Enabled { get; set; }
public string Method { get; set; }
public string Required { get; set; }
}
14 changes: 14 additions & 0 deletions src/NzbDrone.Common/Options/LogOptions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
namespace NzbDrone.Common.Options;

public class LogOptions
{
public string Level { get; set; }
public bool? FilterSentryEvents { get; set; }
public int? Rotate { get; set; }
public bool? Sql { get; set; }
public string ConsoleLevel { get; set; }
public bool? AnalyticsEnabled { get; set; }
public string SyslogServer { get; set; }
public int? SyslogPort { get; set; }
public string SyslogLevel { get; set; }
}
12 changes: 12 additions & 0 deletions src/NzbDrone.Common/Options/ServerOptions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
namespace NzbDrone.Common.Options;

public class ServerOptions
{
public string UrlBase { get; set; }
public string BindAddress { get; set; }
public int? Port { get; set; }
public bool? EnableSsl { get; set; }
public int? SslPort { get; set; }
public string SslCertPath { get; set; }
public string SslCertPassword { get; set; }
}
9 changes: 9 additions & 0 deletions src/NzbDrone.Common/Options/UpdateOptions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace NzbDrone.Common.Options;

public class UpdateOptions
{
public string Mechanism { get; set; }
public bool? Automatically { get; set; }
public string ScriptPath { get; set; }
public string Branch { get; set; }
}
82 changes: 54 additions & 28 deletions src/NzbDrone.Core/Configuration/ConfigFileProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
using NzbDrone.Common.Disk;
using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Common.Extensions;
using NzbDrone.Common.Options;
using NzbDrone.Core.Authentication;
using NzbDrone.Core.Configuration.Events;
using NzbDrone.Core.Datastore;
Expand Down Expand Up @@ -70,6 +71,11 @@ public class ConfigFileProvider : IConfigFileProvider
private readonly IDiskProvider _diskProvider;
private readonly ICached<string> _cache;
private readonly PostgresOptions _postgresOptions;
private readonly AuthOptions _authOptions;
private readonly AppOptions _appOptions;
private readonly ServerOptions _serverOptions;
private readonly UpdateOptions _updateOptions;
private readonly LogOptions _logOptions;

private readonly string _configFile;

Expand All @@ -79,13 +85,23 @@ public class ConfigFileProvider : IConfigFileProvider
ICacheManager cacheManager,
IEventAggregator eventAggregator,
IDiskProvider diskProvider,
IOptions<PostgresOptions> postgresOptions)
IOptions<PostgresOptions> postgresOptions,
IOptions<AuthOptions> authOptions,
IOptions<AppOptions> appOptions,
IOptions<ServerOptions> serverOptions,
IOptions<UpdateOptions> updateOptions,
IOptions<LogOptions> logOptions)
{
_cache = cacheManager.GetCache<string>(GetType());
_eventAggregator = eventAggregator;
_diskProvider = diskProvider;
_configFile = appFolderInfo.GetConfigPath();
_postgresOptions = postgresOptions.Value;
_authOptions = authOptions.Value;
_appOptions = appOptions.Value;
_serverOptions = serverOptions.Value;
_updateOptions = updateOptions.Value;
_logOptions = logOptions.Value;
}

public Dictionary<string, object> GetConfigDictionary()
Expand Down Expand Up @@ -141,7 +157,7 @@ public string BindAddress
{
const string defaultValue = "*";

var bindAddress = GetValue("BindAddress", defaultValue);
var bindAddress = _serverOptions.BindAddress ?? GetValue("BindAddress", defaultValue);
if (string.IsNullOrWhiteSpace(bindAddress))
{
return defaultValue;
Expand All @@ -151,19 +167,19 @@ public string BindAddress
}
}

public int Port => GetValueInt("Port", 8686);
public int Port => _serverOptions.Port ?? GetValueInt("Port", 8686);

public int SslPort => GetValueInt("SslPort", 6868);
public int SslPort => _serverOptions.SslPort ?? GetValueInt("SslPort", 6868);

public bool EnableSsl => GetValueBoolean("EnableSsl", false);
public bool EnableSsl => _serverOptions.EnableSsl ?? GetValueBoolean("EnableSsl", false);

public bool LaunchBrowser => GetValueBoolean("LaunchBrowser", true);
public bool LaunchBrowser => _appOptions.LaunchBrowser ?? GetValueBoolean("LaunchBrowser", true);

public string ApiKey
{
get
{
var apiKey = GetValue("ApiKey", GenerateApiKey());
var apiKey = _authOptions.ApiKey ?? GetValue("ApiKey", GenerateApiKey());

if (apiKey.IsNullOrWhiteSpace())
{
Expand All @@ -179,45 +195,52 @@ public AuthenticationType AuthenticationMethod
{
get
{
var enabled = GetValueBoolean("AuthenticationEnabled", false, false);
var enabled = _authOptions.Enabled ?? GetValueBoolean("AuthenticationEnabled", false, false);

if (enabled)
{
SetValue("AuthenticationMethod", AuthenticationType.Basic);
return AuthenticationType.Basic;
}

return GetValueEnum("AuthenticationMethod", AuthenticationType.None);
return Enum.TryParse<AuthenticationType>(_authOptions.Method, out var enumValue)
? enumValue
: GetValueEnum("AuthenticationMethod", AuthenticationType.None);
}
}

public AuthenticationRequiredType AuthenticationRequired => GetValueEnum("AuthenticationRequired", AuthenticationRequiredType.Enabled);
public AuthenticationRequiredType AuthenticationRequired =>
Enum.TryParse<AuthenticationRequiredType>(_authOptions.Required, out var enumValue)
? enumValue
: GetValueEnum("AuthenticationRequired", AuthenticationRequiredType.Enabled);

public bool AnalyticsEnabled => GetValueBoolean("AnalyticsEnabled", true, persist: false);
public bool AnalyticsEnabled => _logOptions.AnalyticsEnabled ?? GetValueBoolean("AnalyticsEnabled", true, persist: false);

public string Branch => GetValue("Branch", "master").ToLowerInvariant();
public string Branch => _updateOptions.Branch ?? GetValue("Branch", "master").ToLowerInvariant();

public string LogLevel => GetValue("LogLevel", "info");
public string ConsoleLogLevel => GetValue("ConsoleLogLevel", string.Empty, persist: false);
public string LogLevel => _logOptions.Level ?? GetValue("LogLevel", "info").ToLowerInvariant();
public string ConsoleLogLevel => _logOptions.ConsoleLevel ?? GetValue("ConsoleLogLevel", string.Empty, persist: false);

public string Theme => _appOptions.Theme ?? GetValue("Theme", "auto", persist: false);

public string Theme => GetValue("Theme", "auto", persist: false);
public string PostgresHost => _postgresOptions?.Host ?? GetValue("PostgresHost", string.Empty, persist: false);
public string PostgresUser => _postgresOptions?.User ?? GetValue("PostgresUser", string.Empty, persist: false);
public string PostgresPassword => _postgresOptions?.Password ?? GetValue("PostgresPassword", string.Empty, persist: false);
public string PostgresMainDb => _postgresOptions?.MainDb ?? GetValue("PostgresMainDb", "lidarr-main", persist: false);
public string PostgresLogDb => _postgresOptions?.LogDb ?? GetValue("PostgresLogDb", "lidarr-log", persist: false);
public int PostgresPort => (_postgresOptions?.Port ?? 0) != 0 ? _postgresOptions.Port : GetValueInt("PostgresPort", 5432, persist: false);
public bool LogSql => GetValueBoolean("LogSql", false, persist: false);
public int LogRotate => GetValueInt("LogRotate", 50, persist: false);
public bool FilterSentryEvents => GetValueBoolean("FilterSentryEvents", true, persist: false);
public string SslCertPath => GetValue("SslCertPath", "");
public string SslCertPassword => GetValue("SslCertPassword", "");

public bool LogSql => _logOptions.Sql ?? GetValueBoolean("LogSql", false, persist: false);
public int LogRotate => _logOptions.Rotate ?? GetValueInt("LogRotate", 50, persist: false);
public bool FilterSentryEvents => _logOptions.FilterSentryEvents ?? GetValueBoolean("FilterSentryEvents", true, persist: false);
public string SslCertPath => _serverOptions.SslCertPath ?? GetValue("SslCertPath", "");
public string SslCertPassword => _serverOptions.SslCertPassword ?? GetValue("SslCertPassword", "");

public string UrlBase
{
get
{
var urlBase = GetValue("UrlBase", "").Trim('/');
var urlBase = _serverOptions.UrlBase ?? GetValue("UrlBase", "").Trim('/');

if (urlBase.IsNullOrWhiteSpace())
{
Expand All @@ -229,19 +252,22 @@ public string UrlBase
}

public string UiFolder => BuildInfo.IsDebug ? Path.Combine("..", "UI") : "UI";
public string InstanceName => GetValue("InstanceName", BuildInfo.AppName);
public string InstanceName => _appOptions.InstanceName ?? GetValue("InstanceName", BuildInfo.AppName);

public bool UpdateAutomatically => GetValueBoolean("UpdateAutomatically", false, false);
public bool UpdateAutomatically => _updateOptions.Automatically ?? GetValueBoolean("UpdateAutomatically", false, false);

public UpdateMechanism UpdateMechanism => GetValueEnum("UpdateMechanism", UpdateMechanism.BuiltIn, false);
public UpdateMechanism UpdateMechanism =>
Enum.TryParse<UpdateMechanism>(_updateOptions.Mechanism, out var enumValue)
? enumValue
: GetValueEnum("UpdateMechanism", UpdateMechanism.BuiltIn, false);

public string UpdateScriptPath => GetValue("UpdateScriptPath", "", false);
public string UpdateScriptPath => _updateOptions.ScriptPath ?? GetValue("UpdateScriptPath", "", false);

public string SyslogServer => GetValue("SyslogServer", "", persist: false);
public string SyslogServer => _logOptions.SyslogServer ?? GetValue("SyslogServer", "", persist: false);

public int SyslogPort => GetValueInt("SyslogPort", 514, persist: false);
public int SyslogPort => _logOptions.SyslogPort ?? GetValueInt("SyslogPort", 514, persist: false);

public string SyslogLevel => GetValue("SyslogLevel", LogLevel, false).ToLowerInvariant();
public string SyslogLevel => _logOptions.SyslogLevel ?? GetValue("SyslogLevel", LogLevel, persist: false).ToLowerInvariant();

public int GetValueInt(string key, int defaultValue, bool persist = true)
{
Expand Down
6 changes: 6 additions & 0 deletions src/NzbDrone.Host.Test/ContainerFixture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
using NzbDrone.Common.Composition.Extensions;
using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Common.Instrumentation.Extensions;
using NzbDrone.Common.Options;
using NzbDrone.Core.Datastore;
using NzbDrone.Core.Datastore.Extensions;
using NzbDrone.Core.Download;
Expand Down Expand Up @@ -46,6 +47,11 @@ public void SetUp()
container.RegisterInstance<IHostLifetime>(new Mock<IHostLifetime>().Object);
container.RegisterInstance<IBroadcastSignalRMessage>(new Mock<IBroadcastSignalRMessage>().Object);
container.RegisterInstance<IOptions<PostgresOptions>>(new Mock<IOptions<PostgresOptions>>().Object);
container.RegisterInstance<IOptions<AuthOptions>>(new Mock<IOptions<AuthOptions>>().Object);
container.RegisterInstance<IOptions<AppOptions>>(new Mock<IOptions<AppOptions>>().Object);
container.RegisterInstance<IOptions<ServerOptions>>(new Mock<IOptions<ServerOptions>>().Object);
container.RegisterInstance<IOptions<UpdateOptions>>(new Mock<IOptions<UpdateOptions>>().Object);
container.RegisterInstance<IOptions<LogOptions>>(new Mock<IOptions<LogOptions>>().Object);

_container = container.GetServiceProvider();
}
Expand Down
23 changes: 17 additions & 6 deletions src/NzbDrone.Host/Bootstrap.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
using NzbDrone.Common.Extensions;
using NzbDrone.Common.Instrumentation;
using NzbDrone.Common.Instrumentation.Extensions;
using NzbDrone.Common.Options;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Datastore.Extensions;
using PostgresOptions = NzbDrone.Core.Datastore.PostgresOptions;
Expand Down Expand Up @@ -97,6 +98,11 @@ public static void Start(string[] args, Action<IHostBuilder> trayCallback = null
.ConfigureServices(services =>
{
services.Configure<PostgresOptions>(config.GetSection("Lidarr:Postgres"));
services.Configure<AppOptions>(config.GetSection("Lidarr:App"));
services.Configure<AuthOptions>(config.GetSection("Lidarr:Auth"));
services.Configure<ServerOptions>(config.GetSection("Lidarr:Server"));
services.Configure<LogOptions>(config.GetSection("Lidarr:Log"));
services.Configure<UpdateOptions>(config.GetSection("Lidarr:Update"));
}).Build();

break;
Expand Down Expand Up @@ -127,12 +133,12 @@ public static IHostBuilder CreateConsoleHostBuilder(string[] args, StartupContex
{
var config = GetConfiguration(context);

var bindAddress = config.GetValue(nameof(ConfigFileProvider.BindAddress), "*");
var port = config.GetValue(nameof(ConfigFileProvider.Port), 8686);
var sslPort = config.GetValue(nameof(ConfigFileProvider.SslPort), 6868);
var enableSsl = config.GetValue(nameof(ConfigFileProvider.EnableSsl), false);
var sslCertPath = config.GetValue<string>(nameof(ConfigFileProvider.SslCertPath));
var sslCertPassword = config.GetValue<string>(nameof(ConfigFileProvider.SslCertPassword));
var bindAddress = config.GetValue<string>($"Lidarr:Server:{nameof(ServerOptions.BindAddress)}") ?? config.GetValue(nameof(ConfigFileProvider.BindAddress), "*");
var port = config.GetValue<int?>($"Lidarr:Server:{nameof(ServerOptions.Port)}") ?? config.GetValue(nameof(ConfigFileProvider.Port), 8686);
var sslPort = config.GetValue<int?>($"Lidarr:Server:{nameof(ServerOptions.SslPort)}") ?? config.GetValue(nameof(ConfigFileProvider.SslPort), 6868);
var enableSsl = config.GetValue<bool?>($"Lidarr:Server:{nameof(ServerOptions.EnableSsl)}") ?? config.GetValue(nameof(ConfigFileProvider.EnableSsl), false);
var sslCertPath = config.GetValue<string>($"Lidarr:Server:{nameof(ServerOptions.SslCertPath)}") ?? config.GetValue<string>(nameof(ConfigFileProvider.SslCertPath));
var sslCertPassword = config.GetValue<string>($"Lidarr:Server:{nameof(ServerOptions.SslCertPassword)}") ?? config.GetValue<string>(nameof(ConfigFileProvider.SslCertPassword));

var urls = new List<string> { BuildUrl("http", bindAddress, port) };

Expand All @@ -154,6 +160,11 @@ public static IHostBuilder CreateConsoleHostBuilder(string[] args, StartupContex
.ConfigureServices(services =>
{
services.Configure<PostgresOptions>(config.GetSection("Lidarr:Postgres"));
services.Configure<AppOptions>(config.GetSection("Lidarr:App"));
services.Configure<AuthOptions>(config.GetSection("Lidarr:Auth"));
services.Configure<ServerOptions>(config.GetSection("Lidarr:Server"));
services.Configure<LogOptions>(config.GetSection("Lidarr:Log"));
services.Configure<UpdateOptions>(config.GetSection("Lidarr:Update"));
})
.ConfigureWebHost(builder =>
{
Expand Down

0 comments on commit 30d9891

Please sign in to comment.