diff --git a/src/Tgstation.Server.Host/Components/Byond/WindowsByondInstaller.cs b/src/Tgstation.Server.Host/Components/Byond/WindowsByondInstaller.cs
index a17aa4eece..99ac434050 100644
--- a/src/Tgstation.Server.Host/Components/Byond/WindowsByondInstaller.cs
+++ b/src/Tgstation.Server.Host/Components/Byond/WindowsByondInstaller.cs
@@ -21,7 +21,7 @@ namespace Tgstation.Server.Host.Components.Byond
///
/// Directory to byond installation configuration
///
- const string ByondConfigDir = "byond/config";
+ const string ByondConfigDir = "byond/cfg";
///
/// BYOND's DreamDaemon config file
///
diff --git a/src/Tgstation.Server.Host/Components/InstanceFactory.cs b/src/Tgstation.Server.Host/Components/InstanceFactory.cs
index 0b5ddc9107..11c9b9a197 100644
--- a/src/Tgstation.Server.Host/Components/InstanceFactory.cs
+++ b/src/Tgstation.Server.Host/Components/InstanceFactory.cs
@@ -84,6 +84,11 @@ namespace Tgstation.Server.Host.Components
///
readonly IPostWriteHandler postWriteHandler;
+ ///
+ /// The for the
+ ///
+ readonly IWatchdogFactory watchdogFactory;
+
///
/// Construct an
///
@@ -100,7 +105,8 @@ namespace Tgstation.Server.Host.Components
/// The value of
/// The value of
/// The value of
- public InstanceFactory(IIOManager ioManager, IDatabaseContextFactory databaseContextFactory, IApplication application, ILoggerFactory loggerFactory, IByondTopicSender byondTopicSender, IServerControl serverUpdater, ICryptographySuite cryptographySuite, ISynchronousIOManager synchronousIOManager, ISymlinkFactory symlinkFactory, IByondInstaller byondInstaller, IProviderFactory providerFactory, IProcessExecutor processExecutor, IPostWriteHandler postWriteHandler)
+ /// The value of
+ public InstanceFactory(IIOManager ioManager, IDatabaseContextFactory databaseContextFactory, IApplication application, ILoggerFactory loggerFactory, IByondTopicSender byondTopicSender, IServerControl serverUpdater, ICryptographySuite cryptographySuite, ISynchronousIOManager synchronousIOManager, ISymlinkFactory symlinkFactory, IByondInstaller byondInstaller, IProviderFactory providerFactory, IProcessExecutor processExecutor, IPostWriteHandler postWriteHandler, IWatchdogFactory watchdogFactory)
{
this.ioManager = ioManager ?? throw new ArgumentNullException(nameof(ioManager));
this.databaseContextFactory = databaseContextFactory ?? throw new ArgumentNullException(nameof(databaseContextFactory));
@@ -115,6 +121,7 @@ namespace Tgstation.Server.Host.Components
this.providerFactory = providerFactory ?? throw new ArgumentNullException(nameof(providerFactory));
this.processExecutor = processExecutor ?? throw new ArgumentNullException(nameof(processExecutor));
this.postWriteHandler = postWriteHandler ?? throw new ArgumentNullException(nameof(postWriteHandler));
+ this.watchdogFactory = watchdogFactory ?? throw new ArgumentNullException(nameof(watchdogFactory));
}
///
@@ -148,8 +155,7 @@ namespace Tgstation.Server.Host.Components
{
var sessionControllerFactory = new SessionControllerFactory(processExecutor, byond, byondTopicSender, cryptographySuite, application, gameIoManager, chat, loggerFactory, metadata.CloneMetadata());
var reattachInfoHandler = new ReattachInfoHandler(databaseContextFactory, dmbFactory, loggerFactory.CreateLogger(), metadata.CloneMetadata());
- var watchdogFactory = new WatchdogFactory(chat, sessionControllerFactory, serverUpdater, loggerFactory, reattachInfoHandler, databaseContextFactory, byondTopicSender, eventConsumer, metadata.CloneMetadata());
- var watchdog = watchdogFactory.CreateWatchdog(dmbFactory, metadata.DreamDaemonSettings);
+ var watchdog = watchdogFactory.CreateWatchdog(chat, dmbFactory, reattachInfoHandler, configuration, sessionControllerFactory, metadata.CloneMetadata(), metadata.DreamDaemonSettings);
eventConsumer.SetWatchdog(watchdog);
commandFactory.SetWatchdog(watchdog);
try
diff --git a/src/Tgstation.Server.Host/Components/Watchdog/IWatchdogFactory.cs b/src/Tgstation.Server.Host/Components/Watchdog/IWatchdogFactory.cs
index 68717edc9c..7c4091e959 100644
--- a/src/Tgstation.Server.Host/Components/Watchdog/IWatchdogFactory.cs
+++ b/src/Tgstation.Server.Host/Components/Watchdog/IWatchdogFactory.cs
@@ -1,4 +1,5 @@
using Tgstation.Server.Api.Models.Internal;
+using Tgstation.Server.Host.Components.Chat;
using Tgstation.Server.Host.Components.Compiler;
namespace Tgstation.Server.Host.Components.Watchdog
@@ -11,9 +12,14 @@ namespace Tgstation.Server.Host.Components.Watchdog
///
/// Creates a
///
+ /// The for the
/// The for the with
+ /// The for the
+ /// The for the
+ /// The for the
+ /// The for the
/// The initial for the
/// A new
- IWatchdog CreateWatchdog(IDmbFactory dmbFactory, DreamDaemonSettings settings);
+ IWatchdog CreateWatchdog(IChat chat, IDmbFactory dmbFactory, IReattachInfoHandler reattachInfoHandler, IEventConsumer eventConsumer, ISessionControllerFactory sessionControllerFactory, Api.Models.Instance instance, DreamDaemonSettings settings);
}
}
diff --git a/src/Tgstation.Server.Host/Components/Watchdog/Watchdog.cs b/src/Tgstation.Server.Host/Components/Watchdog/Watchdog.cs
index e0f82236a9..6ce7108c42 100644
--- a/src/Tgstation.Server.Host/Components/Watchdog/Watchdog.cs
+++ b/src/Tgstation.Server.Host/Components/Watchdog/Watchdog.cs
@@ -10,6 +10,7 @@ using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Tgstation.Server.Api.Models.Internal;
+using Tgstation.Server.Api.Rights;
using Tgstation.Server.Host.Components.Chat;
using Tgstation.Server.Host.Components.Compiler;
using Tgstation.Server.Host.Components.Interop;
@@ -86,6 +87,11 @@ namespace Tgstation.Server.Host.Components.Watchdog
///
readonly IEventConsumer eventConsumer;
+ ///
+ /// The for the
+ ///
+ readonly IJobManager jobManager;
+
///
/// The for the
///
@@ -141,11 +147,12 @@ namespace Tgstation.Server.Host.Components.Watchdog
/// The value of
/// The value of
/// The value of
+ /// The value of
+ /// The value of
/// The initial value of
/// The value of
/// The value of
- /// The value of
- public Watchdog(IChat chat, ISessionControllerFactory sessionControllerFactory, IDmbFactory dmbFactory, IServerControl serverUpdater, ILogger logger, IReattachInfoHandler reattachInfoHandler, IDatabaseContextFactory databaseContextFactory, IByondTopicSender byondTopicSender, IEventConsumer eventConsumer, DreamDaemonLaunchParameters initialLaunchParameters, Api.Models.Instance instance, bool autoStart)
+ public Watchdog(IChat chat, ISessionControllerFactory sessionControllerFactory, IDmbFactory dmbFactory, IServerControl serverUpdater, ILogger logger, IReattachInfoHandler reattachInfoHandler, IDatabaseContextFactory databaseContextFactory, IByondTopicSender byondTopicSender, IEventConsumer eventConsumer, IJobManager jobManager, DreamDaemonLaunchParameters initialLaunchParameters, Api.Models.Instance instance, bool autoStart)
{
this.chat = chat ?? throw new ArgumentNullException(nameof(chat));
this.sessionControllerFactory = sessionControllerFactory ?? throw new ArgumentNullException(nameof(sessionControllerFactory));
@@ -155,6 +162,7 @@ namespace Tgstation.Server.Host.Components.Watchdog
this.databaseContextFactory = databaseContextFactory ?? throw new ArgumentNullException(nameof(databaseContextFactory));
this.byondTopicSender = byondTopicSender ?? throw new ArgumentNullException(nameof(byondTopicSender));
this.eventConsumer = eventConsumer ?? throw new ArgumentNullException(nameof(eventConsumer));
+ this.jobManager = jobManager ?? throw new ArgumentNullException(nameof(jobManager));
this.instance = instance ?? throw new ArgumentNullException(nameof(instance));
this.autoStart = autoStart;
@@ -642,7 +650,7 @@ namespace Tgstation.Server.Host.Components.Watchdog
throw new InvalidOperationException("Entered LaunchNoLock with one or more of the servers not being null!");
var reattachInfo = doReattach ? await reattachInfoHandler.Load(cancellationToken).ConfigureAwait(false) : null;
- var doesntNeedNewDmb = doReattach && reattachInfo.Alpha != null && reattachInfo.Bravo != null;
+ var doesntNeedNewDmb = doReattach && reattachInfo?.Alpha != null && reattachInfo?.Bravo != null;
var dmbToUse = doesntNeedNewDmb ? null : dmbFactory.LockNextDmb(2);
try
@@ -697,7 +705,7 @@ namespace Tgstation.Server.Host.Components.Watchdog
cancellationToken.ThrowIfCancellationRequested();
//both servers are now running, alpha is the active server, huzzah
- AlphaIsActive = doReattach ? reattachInfo.AlphaIsActive : true;
+ AlphaIsActive = doReattach ? reattachInfo?.AlphaIsActive ?? true : true;
LastLaunchResult = alphaLrt.Result;
logger.LogInformation("Launched servers successfully");
Running = true;
@@ -789,8 +797,24 @@ namespace Tgstation.Server.Host.Components.Watchdog
///
public async Task StartAsync(CancellationToken cancellationToken)
{
- if (autoStart)
- await LaunchNoLock(true, true, true, cancellationToken).ConfigureAwait(false);
+ if (!autoStart)
+ return;
+
+ var job = new Models.Job
+ {
+ StartedBy = new Models.User
+ {
+ Id = 1 //just use admin for this cause whatever
+ },
+ Instance = new Models.Instance
+ {
+ Id = instance.Id
+ },
+ Description = "Instance startup watchdog launch",
+ CancelRight = (ulong)DreamDaemonRights.Shutdown,
+ CancelRightsType = RightsType.DreamDaemon
+ };
+ await jobManager.RegisterOperation(job, (j, serviceProvider, progressFunction, ct) => Launch(ct), cancellationToken).ConfigureAwait(false);
}
///
diff --git a/src/Tgstation.Server.Host/Components/Watchdog/WatchdogFactory.cs b/src/Tgstation.Server.Host/Components/Watchdog/WatchdogFactory.cs
index 65b0452042..b200d8f93b 100644
--- a/src/Tgstation.Server.Host/Components/Watchdog/WatchdogFactory.cs
+++ b/src/Tgstation.Server.Host/Components/Watchdog/WatchdogFactory.cs
@@ -11,16 +11,6 @@ namespace Tgstation.Server.Host.Components.Watchdog
///
sealed class WatchdogFactory : IWatchdogFactory
{
- ///
- /// The for the
- ///
- readonly IChat chat;
-
- ///
- /// The for the
- ///
- readonly ISessionControllerFactory sessionControllerFactory;
-
///
/// The for the
///
@@ -31,11 +21,6 @@ namespace Tgstation.Server.Host.Components.Watchdog
///
readonly ILoggerFactory loggerFactory;
- ///
- /// The for the
- ///
- readonly IReattachInfoHandler reattachInfoHandler;
-
///
/// The for the
///
@@ -47,42 +32,28 @@ namespace Tgstation.Server.Host.Components.Watchdog
readonly IByondTopicSender byondTopicSender;
///
- /// The for the
+ /// The for the
///
- readonly IEventConsumer eventConsumer;
-
- ///
- /// The for the
- ///
- readonly Api.Models.Instance instance;
-
+ readonly IJobManager jobManager;
///
/// Construct a
///
- /// The value of
- /// The value of
/// The value of
/// The value of
- /// The value of
/// The value of
/// The value of
- /// The value of
- /// The value of
- public WatchdogFactory(IChat chat, ISessionControllerFactory sessionControllerFactory, IServerControl serverUpdater, ILoggerFactory loggerFactory, IReattachInfoHandler reattachInfoHandler, IDatabaseContextFactory databaseContextFactory, IByondTopicSender byondTopicSender, IEventConsumer eventConsumer, Api.Models.Instance instance)
+ /// The value of
+ public WatchdogFactory(IServerControl serverUpdater, ILoggerFactory loggerFactory, IDatabaseContextFactory databaseContextFactory, IByondTopicSender byondTopicSender, IJobManager jobManager)
{
- this.chat = chat ?? throw new ArgumentNullException(nameof(chat));
- this.sessionControllerFactory = sessionControllerFactory ?? throw new ArgumentNullException(nameof(sessionControllerFactory));
this.serverUpdater = serverUpdater ?? throw new ArgumentNullException(nameof(serverUpdater));
this.loggerFactory = loggerFactory ?? throw new ArgumentNullException(nameof(loggerFactory));
- this.reattachInfoHandler = reattachInfoHandler ?? throw new ArgumentNullException(nameof(reattachInfoHandler));
this.databaseContextFactory = databaseContextFactory ?? throw new ArgumentNullException(nameof(databaseContextFactory));
this.byondTopicSender = byondTopicSender ?? throw new ArgumentNullException(nameof(byondTopicSender));
- this.eventConsumer = eventConsumer ?? throw new ArgumentNullException(nameof(eventConsumer));
- this.instance = instance ?? throw new ArgumentNullException(nameof(instance));
+ this.jobManager = jobManager ?? throw new ArgumentNullException(nameof(jobManager));
}
///
- public IWatchdog CreateWatchdog(IDmbFactory dmbFactory, DreamDaemonSettings settings) => new Watchdog(chat, sessionControllerFactory, dmbFactory, serverUpdater, loggerFactory.CreateLogger(), reattachInfoHandler, databaseContextFactory, byondTopicSender, eventConsumer, settings, instance, settings.AutoStart.Value);
+ public IWatchdog CreateWatchdog(IChat chat, IDmbFactory dmbFactory, IReattachInfoHandler reattachInfoHandler, IEventConsumer eventConsumer, ISessionControllerFactory sessionControllerFactory, Api.Models.Instance instance, DreamDaemonSettings settings) => new Watchdog(chat, sessionControllerFactory, dmbFactory, serverUpdater, loggerFactory.CreateLogger(), reattachInfoHandler, databaseContextFactory, byondTopicSender, eventConsumer, jobManager, settings, instance, settings.AutoStart.Value);
}
}
diff --git a/src/Tgstation.Server.Host/Controllers/DreamDaemonController.cs b/src/Tgstation.Server.Host/Controllers/DreamDaemonController.cs
index 59dfd9016b..1100022216 100644
--- a/src/Tgstation.Server.Host/Controllers/DreamDaemonController.cs
+++ b/src/Tgstation.Server.Host/Controllers/DreamDaemonController.cs
@@ -71,7 +71,7 @@ namespace Tgstation.Server.Host.Controllers
{
var result = await instance.Watchdog.Launch(innerCt).ConfigureAwait(false);
if (result == null)
- throw new InvalidOperationException("Watchdog already running!");
+ throw new JobException("Watchdog already running!");
},
cancellationToken).ConfigureAwait(false);
return Accepted(job.ToApi());
diff --git a/src/Tgstation.Server.Host/Controllers/RepositoryController.cs b/src/Tgstation.Server.Host/Controllers/RepositoryController.cs
index 721e8b6bd7..1d1d26b4e8 100644
--- a/src/Tgstation.Server.Host/Controllers/RepositoryController.cs
+++ b/src/Tgstation.Server.Host/Controllers/RepositoryController.cs
@@ -287,6 +287,12 @@ namespace Tgstation.Server.Host.Controllers
if (model.NewTestMerges?.Any(x => model.NewTestMerges.Any(y => x != y && x.Number == y.Number)) == true)
return BadRequest(new ErrorMessage { Message = "Cannot test merge the same PR twice in one job!" });
+ if (model.CommitterName?.Length == 0)
+ return BadRequest(new ErrorMessage { Message = "Cannot set empty committer name!" });
+
+ if (model.CommitterEmail?.Length == 0)
+ return BadRequest(new ErrorMessage { Message = "Cannot set empty committer e=mail!" });
+
var newTestMerges = model.NewTestMerges != null && model.NewTestMerges.Count > 0;
var userRights = (RepositoryRights)AuthenticationContext.GetRight(RightsType.Repository);
if (newTestMerges && !userRights.HasFlag(RepositoryRights.MergePullRequest))
diff --git a/src/Tgstation.Server.Host/Core/Application.cs b/src/Tgstation.Server.Host/Core/Application.cs
index a397f43b17..ea72e0aba3 100644
--- a/src/Tgstation.Server.Host/Core/Application.cs
+++ b/src/Tgstation.Server.Host/Core/Application.cs
@@ -3,13 +3,13 @@ using Cyberboss.AspNetCore.AsyncInitializer;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
-using Microsoft.AspNetCore.Hosting.Server.Features;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Primitives;
using Microsoft.IdentityModel.Tokens;
using Newtonsoft.Json;
using System;
@@ -22,6 +22,7 @@ using Tgstation.Server.Host.Components;
using Tgstation.Server.Host.Components.Byond;
using Tgstation.Server.Host.Components.Chat;
using Tgstation.Server.Host.Components.StaticFiles;
+using Tgstation.Server.Host.Components.Watchdog;
using Tgstation.Server.Host.Configuration;
using Tgstation.Server.Host.Controllers;
using Tgstation.Server.Host.IO;
@@ -200,8 +201,9 @@ namespace Tgstation.Server.Host.Core
SendTimeout = 5000
});
- services.AddSingleton();
- services.AddSingleton(x => x.GetRequiredService());
+ services.AddSingleton();
+ services.AddSingleton();
+
services.AddSingleton();
services.AddSingleton(x => x.GetRequiredService());
services.AddSingleton(x => x.GetRequiredService());
@@ -221,7 +223,8 @@ namespace Tgstation.Server.Host.Core
///
/// The to configure
/// The for the
- public void Configure(IApplicationBuilder applicationBuilder, ILogger logger)
+ /// The for the application
+ public void Configure(IApplicationBuilder applicationBuilder, ILogger logger, IServerControl serverControl)
{
if (applicationBuilder == null)
throw new ArgumentNullException(nameof(applicationBuilder));
@@ -229,6 +232,9 @@ namespace Tgstation.Server.Host.Core
throw new ArgumentNullException(nameof(logger));
logger.LogInformation(VersionString);
+
+ //attempt to restart the server if the configuration changes
+ ChangeToken.OnChange(configuration.GetReloadToken, () => serverControl.Restart());
applicationBuilder.UseDeveloperExceptionPage(); //it is not worth it to limit this, you should only ever get it if you're an authorized user
diff --git a/tests/Tgstation.Server.CommandLine.Tests/Tgstation.Server.CommandLine.Tests.csproj b/tests/Tgstation.Server.CommandLine.Tests/Tgstation.Server.CommandLine.Tests.csproj
deleted file mode 100644
index 43a487525f..0000000000
--- a/tests/Tgstation.Server.CommandLine.Tests/Tgstation.Server.CommandLine.Tests.csproj
+++ /dev/null
@@ -1,20 +0,0 @@
-
-
-
- netcoreapp2.0
-
- false
- latest
-
-
-
-
-
-
-
-
-
-
-
-
-