diff --git a/src/NzbDrone.Core.Test/Framework/DbTest.cs b/src/NzbDrone.Core.Test/Framework/DbTest.cs index fba791b15..a27510a67 100644 --- a/src/NzbDrone.Core.Test/Framework/DbTest.cs +++ b/src/NzbDrone.Core.Test/Framework/DbTest.cs @@ -9,6 +9,7 @@ using Npgsql; using NUnit.Framework; using NzbDrone.Common.Extensions; +using NzbDrone.Common.Options; using NzbDrone.Core.Configuration; using NzbDrone.Core.Datastore; using NzbDrone.Core.Datastore.Migration.Framework; @@ -179,6 +180,7 @@ protected void SetupContainer() // Set up remaining container services Mocker.SetConstant(Options.Create(postgresOptions)); + Mocker.GetMock>().Setup(v => v.Value).Returns(new LogOptions()); Mocker.SetConstant(Mocker.Resolve()); Mocker.SetConstant(Mocker.Resolve()); Mocker.SetConstant(Mocker.Resolve()); diff --git a/src/NzbDrone.Core/Configuration/ConfigFileProvider.cs b/src/NzbDrone.Core/Configuration/ConfigFileProvider.cs index 37efddf9c..415e20576 100644 --- a/src/NzbDrone.Core/Configuration/ConfigFileProvider.cs +++ b/src/NzbDrone.Core/Configuration/ConfigFileProvider.cs @@ -66,6 +66,8 @@ public interface IConfigFileProvider : IHandleAsync, string PostgresPassword { get; } string PostgresMainDb { get; } string PostgresLogDb { get; } + string PostgresMainDbConnectionString { get; } + string PostgresLogDbConnectionString { get; } bool TrustCgnatIpAddresses { get; } } @@ -252,6 +254,8 @@ public AuthenticationType AuthenticationMethod public string PostgresMainDb => _postgresOptions?.MainDb ?? GetValue("PostgresMainDb", "sonarr-main", persist: false); public string PostgresLogDb => _postgresOptions?.LogDb ?? GetValue("PostgresLogDb", "sonarr-log", persist: false); public int PostgresPort => (_postgresOptions?.Port ?? 0) != 0 ? _postgresOptions.Port : GetValueInt("PostgresPort", 5432, persist: false); + public string PostgresMainDbConnectionString => _postgresOptions?.MainDbConnectionString ?? GetValue("PostgresMainDbConnectionString", string.Empty, persist: false); + public string PostgresLogDbConnectionString => _postgresOptions?.LogDbConnectionString ?? GetValue("PostgresLogDbConnectionString", string.Empty, persist: false); public bool LogDbEnabled => _logOptions.DbEnabled ?? GetValueBoolean("LogDbEnabled", true, persist: false); public bool LogSql => _logOptions.Sql ?? GetValueBoolean("LogSql", false, persist: false); public int LogRotate => _logOptions.Rotate ?? GetValueInt("LogRotate", 50, persist: false); diff --git a/src/NzbDrone.Core/Datastore/ConnectionStringFactory.cs b/src/NzbDrone.Core/Datastore/ConnectionStringFactory.cs index 19c938737..881b9c1d3 100644 --- a/src/NzbDrone.Core/Datastore/ConnectionStringFactory.cs +++ b/src/NzbDrone.Core/Datastore/ConnectionStringFactory.cs @@ -2,6 +2,7 @@ using System.Data.SQLite; using Npgsql; using NzbDrone.Common.EnvironmentInfo; +using NzbDrone.Common.Exceptions; using NzbDrone.Common.Extensions; using NzbDrone.Core.Configuration; @@ -22,11 +23,25 @@ public ConnectionStringFactory(IAppFolderInfo appFolderInfo, IConfigFileProvider { _configFileProvider = configFileProvider; - MainDbConnection = _configFileProvider.PostgresHost.IsNotNullOrWhiteSpace() ? GetPostgresConnectionString(_configFileProvider.PostgresMainDb) : - GetConnectionString(appFolderInfo.GetDatabase()); + var connectionStringType = GetConnectionStringType(); - LogDbConnection = _configFileProvider.PostgresHost.IsNotNullOrWhiteSpace() ? GetPostgresConnectionString(_configFileProvider.PostgresLogDb) : - GetConnectionString(appFolderInfo.GetLogDatabase()); + switch (connectionStringType) + { + case ConnectionStringType.PostgreSqlVars: + MainDbConnection = GetPostgresConnectionString(_configFileProvider.PostgresMainDb); + LogDbConnection = GetPostgresConnectionString(_configFileProvider.PostgresLogDb); + break; + case ConnectionStringType.PostgreSqlConnectionString: + MainDbConnection = GetPostgresConnectionInfoFromConnectionString(_configFileProvider.PostgresMainDbConnectionString); + LogDbConnection = GetPostgresConnectionInfoFromConnectionString(_configFileProvider.PostgresLogDbConnectionString); + break; + case ConnectionStringType.Sqlite: + MainDbConnection = GetConnectionString(appFolderInfo.GetDatabase()); + LogDbConnection = GetConnectionString(appFolderInfo.GetLogDatabase()); + break; + default: + throw new SonarrStartupException("Unable to determine database connection string for type {0}.", connectionStringType.ToString()); + } } public DatabaseConnectionInfo MainDbConnection { get; private set; } @@ -74,5 +89,55 @@ private DatabaseConnectionInfo GetPostgresConnectionString(string dbName) return new DatabaseConnectionInfo(DatabaseType.PostgreSQL, connectionBuilder.ConnectionString); } + + private DatabaseConnectionInfo GetPostgresConnectionInfoFromConnectionString(string connectionString) + { + var connectionBuilder = new NpgsqlConnectionStringBuilder(connectionString) + { + Enlist = false + }; + + return new DatabaseConnectionInfo(DatabaseType.PostgreSQL, connectionBuilder.ConnectionString); + } + + private ConnectionStringType GetConnectionStringType() + { + var isMainDBConnectionStringSet = !_configFileProvider.PostgresMainDbConnectionString.IsNullOrWhiteSpace(); + var isLogDBConnectionStringSet = !_configFileProvider.PostgresLogDbConnectionString.IsNullOrWhiteSpace(); + var isHostSet = !_configFileProvider.PostgresHost.IsNullOrWhiteSpace(); + + if (!isHostSet && !isMainDBConnectionStringSet && !isLogDBConnectionStringSet) + { + // No Postgres settings are set, so nothing to validate + return ConnectionStringType.Sqlite; + } + + if (_configFileProvider.LogDbEnabled) + { + if (!isMainDBConnectionStringSet && isLogDBConnectionStringSet) + { + throw new SonarrStartupException("Postgres MainDbConnectionString is set but LogDbConnectionString is not. Both must be set or neither."); + } + + if (isLogDBConnectionStringSet && !isMainDBConnectionStringSet) + { + throw new SonarrStartupException("Postgres LogDbConnectionString is set but MainDbConnectionString is not. Both must be set or neither."); + } + } + + if (isMainDBConnectionStringSet && _configFileProvider.PostgresHost.IsNotNullOrWhiteSpace()) + { + throw new SonarrStartupException($"Either both Postgres connection strings must be set, or the other Postgres settings must be set, but not both."); + } + + return isMainDBConnectionStringSet ? ConnectionStringType.PostgreSqlConnectionString : ConnectionStringType.PostgreSqlVars; + } + + private enum ConnectionStringType + { + Sqlite, + PostgreSqlVars, + PostgreSqlConnectionString + } } } diff --git a/src/NzbDrone.Core/Datastore/PostgresOptions.cs b/src/NzbDrone.Core/Datastore/PostgresOptions.cs index e478bdb0e..30dd10a4d 100644 --- a/src/NzbDrone.Core/Datastore/PostgresOptions.cs +++ b/src/NzbDrone.Core/Datastore/PostgresOptions.cs @@ -10,6 +10,8 @@ public class PostgresOptions public string Password { get; set; } public string MainDb { get; set; } public string LogDb { get; set; } + public string MainDbConnectionString { get; set; } + public string LogDbConnectionString { get; set; } public static PostgresOptions GetOptions() {