From 6bb65d39f24ea881ce727997ad07b1a952da7696 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Fri, 16 Aug 2024 11:43:07 -0400 Subject: [PATCH] Reload configuration after successfully running the setup wizard --- src/Tgstation.Server.Host/ServerFactory.cs | 13 +++++++--- .../Setup/IPostSetupServices.cs | 5 ++++ .../Setup/IPostSetupServices{TLoggerType}.cs | 16 ------------- .../Setup/PostSetupServices.cs | 16 ++++--------- .../Setup/SetupApplication.cs | 2 +- .../Setup/SetupWizard.cs | 10 ++++++++ .../Setup/TestSetupWizard.cs | 24 +++++++++++-------- .../TestServerFactory.cs | 8 ++++--- 8 files changed, 50 insertions(+), 44 deletions(-) delete mode 100644 src/Tgstation.Server.Host/Setup/IPostSetupServices{TLoggerType}.cs diff --git a/src/Tgstation.Server.Host/ServerFactory.cs b/src/Tgstation.Server.Host/ServerFactory.cs index f92298da10..5306221a60 100644 --- a/src/Tgstation.Server.Host/ServerFactory.cs +++ b/src/Tgstation.Server.Host/ServerFactory.cs @@ -125,15 +125,22 @@ namespace Tgstation.Server.Host var setupWizardHostBuilder = CreateDefaultBuilder() .UseSetupApplication(assemblyInformationProvider, IOManager); - IPostSetupServices postSetupServices; + IPostSetupServices postSetupServices; using (var setupHost = setupWizardHostBuilder.Build()) { - postSetupServices = setupHost.Services.GetRequiredService>(); + ILogger logger = setupHost.Services.GetRequiredService>(); + postSetupServices = setupHost.Services.GetRequiredService(); await setupHost.RunAsync(cancellationToken); if (postSetupServices.GeneralConfiguration.SetupWizardMode == SetupWizardMode.Only) { - postSetupServices.Logger.LogInformation("Shutting down due to only running setup wizard."); + logger.LogInformation("Shutting down due to only running setup wizard."); + return null; + } + + if (postSetupServices.ReloadRequired) + { + logger.LogInformation("TGS must restart to reload the updated configuration."); return null; } } diff --git a/src/Tgstation.Server.Host/Setup/IPostSetupServices.cs b/src/Tgstation.Server.Host/Setup/IPostSetupServices.cs index 21264d9277..7f3dba9565 100644 --- a/src/Tgstation.Server.Host/Setup/IPostSetupServices.cs +++ b/src/Tgstation.Server.Host/Setup/IPostSetupServices.cs @@ -42,5 +42,10 @@ namespace Tgstation.Server.Host.Setup /// The . /// IPlatformIdentifier PlatformIdentifier { get; } + + /// + /// If an application reload to get updated configuration values is required. + /// + bool ReloadRequired { get; set; } } } diff --git a/src/Tgstation.Server.Host/Setup/IPostSetupServices{TLoggerType}.cs b/src/Tgstation.Server.Host/Setup/IPostSetupServices{TLoggerType}.cs deleted file mode 100644 index f36d9526e7..0000000000 --- a/src/Tgstation.Server.Host/Setup/IPostSetupServices{TLoggerType}.cs +++ /dev/null @@ -1,16 +0,0 @@ -using Microsoft.Extensions.Logging; - -namespace Tgstation.Server.Host.Setup -{ - /// - /// with a . - /// - /// The category for . - interface IPostSetupServices : IPostSetupServices - { - /// - /// The . - /// - ILogger Logger { get; } - } -} diff --git a/src/Tgstation.Server.Host/Setup/PostSetupServices.cs b/src/Tgstation.Server.Host/Setup/PostSetupServices.cs index c1ace340ec..9180c22c7a 100644 --- a/src/Tgstation.Server.Host/Setup/PostSetupServices.cs +++ b/src/Tgstation.Server.Host/Setup/PostSetupServices.cs @@ -1,6 +1,5 @@ using System; -using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Tgstation.Server.Host.Configuration; @@ -9,14 +8,11 @@ using Tgstation.Server.Host.System; namespace Tgstation.Server.Host.Setup { /// - sealed class PostSetupServices : IPostSetupServices + sealed class PostSetupServices : IPostSetupServices { /// public IPlatformIdentifier PlatformIdentifier { get; } - /// - public ILogger Logger { get; } - /// public GeneralConfiguration GeneralConfiguration => generalConfigurationOptions.Value; @@ -35,6 +31,9 @@ namespace Tgstation.Server.Host.Setup /// public ElasticsearchConfiguration ElasticsearchConfiguration => elasticsearchConfigurationOptions.Value; + /// + public bool ReloadRequired { get; set; } + /// /// Backing for . /// @@ -66,10 +65,9 @@ namespace Tgstation.Server.Host.Setup readonly IOptions internalConfigurationOptions; /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// The value of . - /// The used to create . /// The containing the value of . /// The containing the value of . /// The containing the value of . @@ -78,7 +76,6 @@ namespace Tgstation.Server.Host.Setup /// The containing the value of . public PostSetupServices( IPlatformIdentifier platformIdentifier, - ILoggerFactory loggerFactory, IOptions generalConfigurationOptions, IOptions databaseConfigurationOptions, IOptions securityConfigurationOptions, @@ -87,9 +84,6 @@ namespace Tgstation.Server.Host.Setup IOptions internalConfigurationOptions) { PlatformIdentifier = platformIdentifier ?? throw new ArgumentNullException(nameof(platformIdentifier)); - ArgumentNullException.ThrowIfNull(loggerFactory); - - Logger = loggerFactory.CreateLogger(); this.generalConfigurationOptions = generalConfigurationOptions ?? throw new ArgumentNullException(nameof(generalConfigurationOptions)); this.databaseConfigurationOptions = databaseConfigurationOptions ?? throw new ArgumentNullException(nameof(databaseConfigurationOptions)); this.securityConfigurationOptions = securityConfigurationOptions ?? throw new ArgumentNullException(nameof(securityConfigurationOptions)); diff --git a/src/Tgstation.Server.Host/Setup/SetupApplication.cs b/src/Tgstation.Server.Host/Setup/SetupApplication.cs index 56c590ce7d..744aabd8c0 100644 --- a/src/Tgstation.Server.Host/Setup/SetupApplication.cs +++ b/src/Tgstation.Server.Host/Setup/SetupApplication.cs @@ -72,7 +72,7 @@ namespace Tgstation.Server.Host.Setup /// The to configure. protected virtual void ConfigureHostedService(IServiceCollection services) { - services.AddSingleton(typeof(IPostSetupServices<>), typeof(PostSetupServices<>)); + services.AddSingleton(); services.AddSingleton(); } } diff --git a/src/Tgstation.Server.Host/Setup/SetupWizard.cs b/src/Tgstation.Server.Host/Setup/SetupWizard.cs index 04cc54a3bf..36d0bf3111 100644 --- a/src/Tgstation.Server.Host/Setup/SetupWizard.cs +++ b/src/Tgstation.Server.Host/Setup/SetupWizard.cs @@ -76,6 +76,11 @@ namespace Tgstation.Server.Host.Setup /// readonly IHostApplicationLifetime applicationLifetime; + /// + /// The for the . + /// + readonly IPostSetupServices postSetupServices; + /// /// The for the . /// @@ -97,6 +102,7 @@ namespace Tgstation.Server.Host.Setup /// The value of . /// The value of . /// The value of . + /// The value of . /// The containing the value of . /// The containing the value of . public SetupWizard( @@ -108,6 +114,7 @@ namespace Tgstation.Server.Host.Setup IPlatformIdentifier platformIdentifier, IAsyncDelayer asyncDelayer, IHostApplicationLifetime applicationLifetime, + IPostSetupServices postSetupServices, IOptions generalConfigurationOptions, IOptions internalConfigurationOptions) { @@ -119,6 +126,7 @@ namespace Tgstation.Server.Host.Setup this.platformIdentifier = platformIdentifier ?? throw new ArgumentNullException(nameof(platformIdentifier)); this.asyncDelayer = asyncDelayer ?? throw new ArgumentNullException(nameof(asyncDelayer)); this.applicationLifetime = applicationLifetime ?? throw new ArgumentNullException(nameof(applicationLifetime)); + this.postSetupServices = postSetupServices ?? throw new ArgumentNullException(nameof(postSetupServices)); generalConfiguration = generalConfigurationOptions?.Value ?? throw new ArgumentNullException(nameof(generalConfigurationOptions)); internalConfiguration = internalConfigurationOptions?.Value ?? throw new ArgumentNullException(nameof(internalConfigurationOptions)); @@ -1014,6 +1022,8 @@ namespace Tgstation.Server.Host.Setup userConfigFileName, configBytes, cancellationToken); + + postSetupServices.ReloadRequired = true; } catch (Exception e) when (e is not OperationCanceledException) { diff --git a/tests/Tgstation.Server.Host.Tests/Setup/TestSetupWizard.cs b/tests/Tgstation.Server.Host.Tests/Setup/TestSetupWizard.cs index 823036a10b..1aa3576277 100644 --- a/tests/Tgstation.Server.Host.Tests/Setup/TestSetupWizard.cs +++ b/tests/Tgstation.Server.Host.Tests/Setup/TestSetupWizard.cs @@ -27,25 +27,27 @@ namespace Tgstation.Server.Host.Setup.Tests [TestMethod] public void TestConstructionThrows() { - Assert.ThrowsException(() => new SetupWizard(null, null, null, null, null, null, null, null, null, null)); + Assert.ThrowsException(() => new SetupWizard(null, null, null, null, null, null, null, null, null, null, null)); var mockIOManager = new Mock(); - Assert.ThrowsException(() => new SetupWizard(mockIOManager.Object, null, null, null, null, null, null, null, null, null)); + Assert.ThrowsException(() => new SetupWizard(mockIOManager.Object, null, null, null, null, null, null, null, null, null, null)); var mockConsole = new Mock(); - Assert.ThrowsException(() => new SetupWizard(mockIOManager.Object, mockConsole.Object, null, null, null, null, null, null, null, null)); + Assert.ThrowsException(() => new SetupWizard(mockIOManager.Object, mockConsole.Object, null, null, null, null, null, null, null, null, null)); var mockHostingEnvironment = new Mock(); - Assert.ThrowsException(() => new SetupWizard(mockIOManager.Object, mockConsole.Object, mockHostingEnvironment.Object, null, null, null, null, null, null, null)); + Assert.ThrowsException(() => new SetupWizard(mockIOManager.Object, mockConsole.Object, mockHostingEnvironment.Object, null, null, null, null, null, null, null, null)); var mockAssemblyInfoProvider = new Mock(); - Assert.ThrowsException(() => new SetupWizard(mockIOManager.Object, mockConsole.Object, mockHostingEnvironment.Object, mockAssemblyInfoProvider.Object, null, null, null, null, null, null)); + Assert.ThrowsException(() => new SetupWizard(mockIOManager.Object, mockConsole.Object, mockHostingEnvironment.Object, mockAssemblyInfoProvider.Object, null, null, null, null, null, null, null)); var mockDBConnectionFactory = new Mock(); - Assert.ThrowsException(() => new SetupWizard(mockIOManager.Object, mockConsole.Object, mockHostingEnvironment.Object, mockAssemblyInfoProvider.Object, mockDBConnectionFactory.Object, null, null, null, null, null)); + Assert.ThrowsException(() => new SetupWizard(mockIOManager.Object, mockConsole.Object, mockHostingEnvironment.Object, mockAssemblyInfoProvider.Object, mockDBConnectionFactory.Object, null, null, null, null, null, null)); var mockPlatformIdentifier = new Mock(); - Assert.ThrowsException(() => new SetupWizard(mockIOManager.Object, mockConsole.Object, mockHostingEnvironment.Object, mockAssemblyInfoProvider.Object, mockDBConnectionFactory.Object, mockPlatformIdentifier.Object, null, null, null, null)); + Assert.ThrowsException(() => new SetupWizard(mockIOManager.Object, mockConsole.Object, mockHostingEnvironment.Object, mockAssemblyInfoProvider.Object, mockDBConnectionFactory.Object, mockPlatformIdentifier.Object, null, null, null, null, null)); var mockAsyncDelayer = new Mock(); - Assert.ThrowsException(() => new SetupWizard(mockIOManager.Object, mockConsole.Object, mockHostingEnvironment.Object, mockAssemblyInfoProvider.Object, mockDBConnectionFactory.Object, mockPlatformIdentifier.Object, mockAsyncDelayer.Object, null, null, null)); + Assert.ThrowsException(() => new SetupWizard(mockIOManager.Object, mockConsole.Object, mockHostingEnvironment.Object, mockAssemblyInfoProvider.Object, mockDBConnectionFactory.Object, mockPlatformIdentifier.Object, mockAsyncDelayer.Object, null, null, null, null)); var mockLifetime = new Mock(); - Assert.ThrowsException(() => new SetupWizard(mockIOManager.Object, mockConsole.Object, mockHostingEnvironment.Object, mockAssemblyInfoProvider.Object, mockDBConnectionFactory.Object, mockPlatformIdentifier.Object, mockAsyncDelayer.Object, mockLifetime.Object, null, null)); + Assert.ThrowsException(() => new SetupWizard(mockIOManager.Object, mockConsole.Object, mockHostingEnvironment.Object, mockAssemblyInfoProvider.Object, mockDBConnectionFactory.Object, mockPlatformIdentifier.Object, mockAsyncDelayer.Object, mockLifetime.Object, null, null, null)); + var mockServices = new Mock(); + Assert.ThrowsException(() => new SetupWizard(mockIOManager.Object, mockConsole.Object, mockHostingEnvironment.Object, mockAssemblyInfoProvider.Object, mockDBConnectionFactory.Object, mockPlatformIdentifier.Object, mockAsyncDelayer.Object, mockLifetime.Object, mockServices.Object, null, null)); var mockGeneralConfigurationOptions = Options.Create(new GeneralConfiguration()); - Assert.ThrowsException(() => new SetupWizard(mockIOManager.Object, mockConsole.Object, mockHostingEnvironment.Object, mockAssemblyInfoProvider.Object, mockDBConnectionFactory.Object, mockPlatformIdentifier.Object, mockAsyncDelayer.Object, mockLifetime.Object, mockGeneralConfigurationOptions, null)); + Assert.ThrowsException(() => new SetupWizard(mockIOManager.Object, mockConsole.Object, mockHostingEnvironment.Object, mockAssemblyInfoProvider.Object, mockDBConnectionFactory.Object, mockPlatformIdentifier.Object, mockAsyncDelayer.Object, mockLifetime.Object, mockServices.Object, mockGeneralConfigurationOptions, null)); } [TestMethod] @@ -61,6 +63,7 @@ namespace Tgstation.Server.Host.Setup.Tests var mockInternalConfigurationOptions = new Mock>(); var mockPlatformIdentifier = new Mock(); var mockAsyncDelayer = new Mock(); + var mockServices = new Mock(); var testGeneralConfig = new GeneralConfiguration { @@ -83,6 +86,7 @@ namespace Tgstation.Server.Host.Setup.Tests mockPlatformIdentifier.Object, mockAsyncDelayer.Object, mockLifetime.Object, + mockServices.Object, mockGeneralConfigurationOptions.Object, mockInternalConfigurationOptions.Object); diff --git a/tests/Tgstation.Server.Host.Tests/TestServerFactory.cs b/tests/Tgstation.Server.Host.Tests/TestServerFactory.cs index c8c83fc594..9a96a8332f 100644 --- a/tests/Tgstation.Server.Host.Tests/TestServerFactory.cs +++ b/tests/Tgstation.Server.Host.Tests/TestServerFactory.cs @@ -15,8 +15,10 @@ namespace Tgstation.Server.Host.Tests [TestClass] public sealed class TestServerFactory { + static readonly string[] cliArgs = ["General:SetupWizardMode=Never"]; + [TestMethod] - public void TestContructor() + public void TestConstructor() { Assert.ThrowsException(() => new ServerFactory(null, null)); IAssemblyInformationProvider assemblyInformationProvider = Mock.Of(); @@ -31,7 +33,7 @@ namespace Tgstation.Server.Host.Tests var factory = Application.CreateDefaultServerFactory(); await Assert.ThrowsExceptionAsync(() => factory.CreateServer(null, null, default).AsTask()); - var result = await factory.CreateServer(new[] { "General:SetupWizardMode=Never" }, null, default); + var result = await factory.CreateServer(cliArgs, null, default); Assert.IsNotNull(result); } @@ -43,7 +45,7 @@ namespace Tgstation.Server.Host.Tests await Assert.ThrowsExceptionAsync(() => factory.CreateServer(null, null, default).AsTask()); await Assert.ThrowsExceptionAsync(() => factory.CreateServer(null, Path, default).AsTask()); - var result = await factory.CreateServer(new[] { "General:SetupWizardMode=Never" }, Path, default); + var result = await factory.CreateServer(cliArgs, Path, default); Assert.IsNotNull(result); } }