diff --git a/build/Version.props b/build/Version.props index 75afbdc50b..dab9fba25d 100644 --- a/build/Version.props +++ b/build/Version.props @@ -3,11 +3,11 @@ - 5.6.0 + 5.7.0 4.4.0 - 9.8.1 - 10.2.0 - 11.2.1 + 9.9.0 + 10.3.0 + 11.3.0 6.1.0 5.4.0 1.2.1 diff --git a/src/Tgstation.Server.Api/Models/Internal/DreamDaemonLaunchParameters.cs b/src/Tgstation.Server.Api/Models/Internal/DreamDaemonLaunchParameters.cs index 4890b211a1..7693ecf961 100644 --- a/src/Tgstation.Server.Api/Models/Internal/DreamDaemonLaunchParameters.cs +++ b/src/Tgstation.Server.Api/Models/Internal/DreamDaemonLaunchParameters.cs @@ -84,6 +84,13 @@ namespace Tgstation.Server.Api.Models.Internal [StringLength(Limits.MaximumStringLength)] public string? AdditionalParameters { get; set; } + /// + /// If process output/error text should be logged. + /// + [Required] + [ResponseOptions] + public bool? LogOutput { get; set; } + /// /// Check if we match a given set of . is excluded. /// @@ -100,7 +107,8 @@ namespace Tgstation.Server.Api.Models.Internal && Port == otherParameters.Port && TopicRequestTimeout == otherParameters.TopicRequestTimeout && AdditionalParameters == otherParameters.AdditionalParameters - && StartProfiler == otherParameters.StartProfiler; // We intentionally don't check StartupTimeout, heartbeat seconds, or heartbeat dump as they don't matter in terms of the watchdog + && StartProfiler == otherParameters.StartProfiler + && LogOutput == otherParameters.LogOutput; // We intentionally don't check StartupTimeout, heartbeat seconds, or heartbeat dump as they don't matter in terms of the watchdog } } } diff --git a/src/Tgstation.Server.Api/Rights/DreamDaemonRights.cs b/src/Tgstation.Server.Api/Rights/DreamDaemonRights.cs index 5fc6b54394..a89f20d9e0 100644 --- a/src/Tgstation.Server.Api/Rights/DreamDaemonRights.cs +++ b/src/Tgstation.Server.Api/Rights/DreamDaemonRights.cs @@ -102,5 +102,10 @@ namespace Tgstation.Server.Api.Rights /// User can change /// SetProfiler = 131072, + + /// + /// User can change + /// + SetLogOutput = 262144, } } diff --git a/src/Tgstation.Server.Host/Components/Byond/WindowsByondInstaller.cs b/src/Tgstation.Server.Host/Components/Byond/WindowsByondInstaller.cs index 03d6b9389f..76d47e26f6 100644 --- a/src/Tgstation.Server.Host/Components/Byond/WindowsByondInstaller.cs +++ b/src/Tgstation.Server.Host/Components/Byond/WindowsByondInstaller.cs @@ -187,7 +187,7 @@ namespace Tgstation.Server.Host.Components.Byond try { // noShellExecute because we aren't doing runas shennanigans - using var directXInstaller = processExecutor.LaunchProcess( + await using var directXInstaller = await processExecutor.LaunchProcess( IOManager.ConcatPath(rbdx, "DXSETUP.exe"), rbdx, "/silent", @@ -228,13 +228,12 @@ namespace Tgstation.Server.Host.Components.Byond Logger.LogInformation("Adding Windows Firewall exception for {path}...", dreamDaemonPath); try { - using var netshProcess = processExecutor.LaunchProcess( + await using var netshProcess = await processExecutor.LaunchProcess( "netsh.exe", IOManager.ResolvePath(), $"advfirewall firewall add rule name=\"TGS DreamDaemon\" program=\"{dreamDaemonPath}\" protocol=tcp dir=in enable=yes action=allow", - true, - true, - true); + readStandardHandles: true, + noShellExecute: true); int exitCode; using (cancellationToken.Register(() => netshProcess.Terminate())) diff --git a/src/Tgstation.Server.Host/Components/Deployment/DreamMaker.cs b/src/Tgstation.Server.Host/Components/Deployment/DreamMaker.cs index ff50fdcc81..3bcd99775e 100644 --- a/src/Tgstation.Server.Host/Components/Deployment/DreamMaker.cs +++ b/src/Tgstation.Server.Host/Components/Deployment/DreamMaker.cs @@ -235,6 +235,7 @@ namespace Tgstation.Server.Host.Components.Deployment .Select(x => new Models.DreamDaemonSettings { StartupTimeout = x.StartupTimeout, + LogOutput = x.LogOutput, }) .FirstOrDefaultAsync(cancellationToken) ; @@ -325,7 +326,7 @@ namespace Tgstation.Server.Host.Components.Deployment compileJob = await Compile( revInfo, dreamMakerSettings, - ddSettings.StartupTimeout.Value, + ddSettings, repo, remoteDeploymentManager, progressReporter, @@ -462,7 +463,7 @@ namespace Tgstation.Server.Host.Components.Deployment /// /// The . /// The . - /// The API validation timeout. + /// The . /// The . /// The . /// The to report progress of the operation. @@ -473,7 +474,7 @@ namespace Tgstation.Server.Host.Components.Deployment async Task Compile( Models.RevisionInformation revisionInformation, Api.Models.Internal.DreamMakerSettings dreamMakerSettings, - uint apiValidateTimeout, + DreamDaemonLaunchParameters launchParameters, IRepository repository, IRemoteDeploymentManager remoteDeploymentManager, JobProgressReporter progressReporter, @@ -525,10 +526,10 @@ namespace Tgstation.Server.Host.Components.Deployment await RunCompileJob( job, dreamMakerSettings, + launchParameters, byondLock, repository, remoteDeploymentManager, - apiValidateTimeout, combinedTokenSource.Token) ; } @@ -559,19 +560,19 @@ namespace Tgstation.Server.Host.Components.Deployment /// /// The to run and populate. /// The to use. + /// The to use. /// The to use. /// The to use. /// The to use. - /// The timeout for validating the DMAPI. /// The for the operation. /// A representing the running operation. async Task RunCompileJob( Models.CompileJob job, Api.Models.Internal.DreamMakerSettings dreamMakerSettings, + DreamDaemonLaunchParameters launchParameters, IByondExecutableLock byondLock, IRepository repository, IRemoteDeploymentManager remoteDeploymentManager, - uint apiValidateTimeout, CancellationToken cancellationToken) { var outputDirectory = job.DirectoryName.ToString(); @@ -655,14 +656,14 @@ namespace Tgstation.Server.Host.Components.Deployment currentStage = "Validating DMAPI"; await VerifyApi( - apiValidateTimeout, + launchParameters.StartupTimeout.Value, dreamMakerSettings.ApiValidationSecurityLevel.Value, job, byondLock, dreamMakerSettings.ApiValidationPort.Value, dreamMakerSettings.RequireDMApiValidation.Value, - cancellationToken) - ; + launchParameters.LogOutput.Value, + cancellationToken); } catch (JobException) { @@ -769,6 +770,7 @@ namespace Tgstation.Server.Host.Components.Deployment /// The current . /// The port to use for API validation. /// If the API validation is required to complete the deployment. + /// If output should be logged to the DreamDaemon Diagnostics folder. /// The for the operation. /// A representing the running operation. async Task VerifyApi( @@ -778,6 +780,7 @@ namespace Tgstation.Server.Host.Components.Deployment IByondExecutableLock byondLock, ushort portToUse, bool requireValidate, + bool logOutput, CancellationToken cancellationToken) { logger.LogTrace("Verifying {0}DMAPI...", requireValidate ? "required " : String.Empty); @@ -791,6 +794,7 @@ namespace Tgstation.Server.Host.Components.Deployment TopicRequestTimeout = 0, // not used HeartbeatSeconds = 0, // not used StartProfiler = false, + LogOutput = logOutput, }; job.MinimumSecurityLevel = securityLevel; // needed for the TempDmbProvider @@ -854,14 +858,13 @@ namespace Tgstation.Server.Host.Components.Deployment /// A representing the running operation. async Task RunDreamMaker(string dreamMakerPath, Models.CompileJob job, CancellationToken cancellationToken) { - using var dm = processExecutor.LaunchProcess( + await using var dm = await processExecutor.LaunchProcess( dreamMakerPath, ioManager.ResolvePath( job.DirectoryName.ToString()), $"-clean {job.DmeName}.{DmeExtension}", - true, - true, - true); + readStandardHandles: true, + noShellExecute: true); if (sessionConfiguration.LowPriorityDeploymentProcesses) dm.AdjustPriority(false); diff --git a/src/Tgstation.Server.Host/Components/InstanceFactory.cs b/src/Tgstation.Server.Host/Components/InstanceFactory.cs index 1bb8121c9d..b1d9764321 100644 --- a/src/Tgstation.Server.Host/Components/InstanceFactory.cs +++ b/src/Tgstation.Server.Host/Components/InstanceFactory.cs @@ -271,6 +271,7 @@ namespace Tgstation.Server.Host.Components cryptographySuite, assemblyInformationProvider, gameIoManager, + diagnosticsIOManager, chatManager, networkPromptReaper, platformIdentifier, @@ -308,10 +309,11 @@ namespace Tgstation.Server.Host.Components remoteDeploymentManagerFactory, metadata, metadata.DreamDaemonSettings); - eventConsumer.SetWatchdog(watchdog); - commandFactory.SetWatchdog(watchdog); try { + eventConsumer.SetWatchdog(watchdog); + commandFactory.SetWatchdog(watchdog); + Instance instance = null; var dreamMaker = new DreamMaker( byond, diff --git a/src/Tgstation.Server.Host/Components/Session/SessionController.cs b/src/Tgstation.Server.Host/Components/Session/SessionController.cs index 21bdc758e2..37a0a6ac64 100644 --- a/src/Tgstation.Server.Host/Components/Session/SessionController.cs +++ b/src/Tgstation.Server.Host/Components/Session/SessionController.cs @@ -275,7 +275,7 @@ namespace Tgstation.Server.Host.Components.Session byondLock.Dispose(); } - process.Dispose(); + await process.DisposeAsync(); bridgeRegistration?.Dispose(); ReattachInformation.Dmb?.Dispose(); // will be null when released chatTrackingContext.Dispose(); @@ -656,8 +656,8 @@ namespace Tgstation.Server.Host.Components.Session var result = new LaunchResult { - ExitCode = process.Lifetime.IsCompleted ? (int?)await process.Lifetime : null, - StartupTime = startupTask.IsCompleted ? (TimeSpan?)(DateTimeOffset.UtcNow - startTime) : null, + ExitCode = process.Lifetime.IsCompleted ? await process.Lifetime : null, + StartupTime = startupTask.IsCompleted ? (DateTimeOffset.UtcNow - startTime) : null, }; logger.LogTrace("Launch result: {0}", result); diff --git a/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs b/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs index e938adeb17..8b95c3dc05 100644 --- a/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs +++ b/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs @@ -6,6 +6,8 @@ using System.Text; using System.Threading; using System.Threading.Tasks; +using Byond.TopicSender; + using Microsoft.Extensions.Logging; using Tgstation.Server.Api; @@ -30,6 +32,11 @@ namespace Tgstation.Server.Host.Components.Session /// sealed class SessionControllerFactory : ISessionControllerFactory { + /// + /// Path in Diagnostics folder to DreamDaemon logs. + /// + const string DreamDaemonLogsPath = "DreamDaemonLogs"; + /// /// The for the . /// @@ -56,9 +63,14 @@ namespace Tgstation.Server.Host.Components.Session readonly IAssemblyInformationProvider assemblyInformationProvider; /// - /// The for the . + /// The for the Game directory. /// - readonly IIOManager ioManager; + readonly IIOManager gameIOManager; + + /// + /// The for the Diagnostics directory. + /// + readonly IIOManager diagnosticsIOManager; /// /// The for the . @@ -168,7 +180,8 @@ namespace Tgstation.Server.Host.Components.Session /// 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 . @@ -184,7 +197,8 @@ namespace Tgstation.Server.Host.Components.Session ITopicClientFactory topicClientFactory, ICryptographySuite cryptographySuite, IAssemblyInformationProvider assemblyInformationProvider, - IIOManager ioManager, + IIOManager gameIOManager, + IIOManager diagnosticsIOManager, IChatManager chat, INetworkPromptReaper networkPromptReaper, IPlatformIdentifier platformIdentifier, @@ -201,7 +215,8 @@ namespace Tgstation.Server.Host.Components.Session this.topicClientFactory = topicClientFactory ?? throw new ArgumentNullException(nameof(topicClientFactory)); this.cryptographySuite = cryptographySuite ?? throw new ArgumentNullException(nameof(cryptographySuite)); this.assemblyInformationProvider = assemblyInformationProvider ?? throw new ArgumentNullException(nameof(assemblyInformationProvider)); - this.ioManager = ioManager ?? throw new ArgumentNullException(nameof(ioManager)); + this.gameIOManager = gameIOManager ?? throw new ArgumentNullException(nameof(gameIOManager)); + this.diagnosticsIOManager = diagnosticsIOManager ?? throw new ArgumentNullException(nameof(diagnosticsIOManager)); this.chat = chat ?? throw new ArgumentNullException(nameof(chat)); this.networkPromptReaper = networkPromptReaper ?? throw new ArgumentNullException(nameof(networkPromptReaper)); this.platformIdentifier = platformIdentifier ?? throw new ArgumentNullException(nameof(platformIdentifier)); @@ -215,7 +230,6 @@ namespace Tgstation.Server.Host.Components.Session } /// -#pragma warning disable CA1506 // TODO: Decomplexify public async Task LaunchNew( IDmbProvider dmbProvider, IByondExecutableLock currentByondLock, @@ -248,125 +262,65 @@ namespace Tgstation.Server.Host.Components.Session throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture, "Invalid DreamDaemonSecurity value: {0}", dmbProvider.CompileJob.MinimumSecurityLevel)); } - var chatTrackingContext = chat.CreateTrackingContext(); + // get the byond lock + var byondLock = currentByondLock ?? await byond.UseExecutables(Version.Parse(dmbProvider.CompileJob.ByondVersion), cancellationToken); try { - // get the byond lock - var byondLock = currentByondLock ?? await byond.UseExecutables(Version.Parse(dmbProvider.CompileJob.ByondVersion), cancellationToken); + logger.LogDebug( + "Launching session with CompileJob {compileJobId}...", + dmbProvider.CompileJob.Id); + + if (launchParameters.SecurityLevel == DreamDaemonSecurity.Trusted) + await byondLock.TrustDmbPath(gameIOManager.ConcatPath(dmbProvider.Directory, dmbProvider.DmbName), cancellationToken); + + PortBindTest(launchParameters.Port.Value); + await CheckPagerIsNotRunning(cancellationToken); + + string outputFilePath = null; + if (launchParameters.LogOutput.Value) + { + await diagnosticsIOManager.CreateDirectory(DreamDaemonLogsPath, cancellationToken); + var now = DateTimeOffset.UtcNow; + outputFilePath = diagnosticsIOManager.ResolvePath( + diagnosticsIOManager.ConcatPath( + DreamDaemonLogsPath, + $"dd-utc-{DateTimeOffset.UtcNow.ToString("yyyy-MM-dd-HH-mm-ss", CultureInfo.InvariantCulture)}{(apiValidate ? "-dmapi" : String.Empty)}.log")); + + logger.LogInformation("Logging DreamDaemon output to {path}...", outputFilePath); + } + else if (!byondLock.SupportsCli) + outputFilePath = gameIOManager.ConcatPath(dmbProvider.Directory, $"{Guid.NewGuid()}.dd.log"); + + var accessIdentifier = cryptographySuite.GetSecureString(); + + var byondTopicSender = topicClientFactory.CreateTopicClient( + TimeSpan.FromMilliseconds( + launchParameters.TopicRequestTimeout.Value)); + + if (!apiValidate && dmbProvider.CompileJob.DMApiVersion == null) + logger.LogDebug("Session will have no DMAPI support!"); + + // launch dd + var process = await CreateDreamDaemonProcess( + dmbProvider, + byondTopicSender, + byondLock, + launchParameters, + accessIdentifier, + outputFilePath, + apiValidate, + cancellationToken); + try { - logger.LogDebug( - "Launching session with CompileJob {0}...", - dmbProvider.CompileJob.Id); - - if (launchParameters.SecurityLevel == DreamDaemonSecurity.Trusted) - await byondLock.TrustDmbPath(ioManager.ConcatPath(dmbProvider.Directory, dmbProvider.DmbName), cancellationToken); - - PortBindTest(launchParameters.Port.Value); - await CheckPagerIsNotRunning(cancellationToken); - - var accessIdentifier = cryptographySuite.GetSecureString(); - - var byondTopicSender = topicClientFactory.CreateTopicClient( - TimeSpan.FromMilliseconds( - launchParameters.TopicRequestTimeout.Value)); - - // set command line options - // more sanitization here cause it uses the same scheme - var parameters = $"{DMApiConstants.ParamApiVersion}={byondTopicSender.SanitizeString(DMApiConstants.InteropVersion.Semver().ToString())}&{byondTopicSender.SanitizeString(DMApiConstants.ParamServerPort)}={serverPortProvider.HttpApiPort}&{byondTopicSender.SanitizeString(DMApiConstants.ParamAccessIdentifier)}={byondTopicSender.SanitizeString(accessIdentifier)}"; - - if (!String.IsNullOrEmpty(launchParameters.AdditionalParameters)) - parameters = $"{parameters}&{launchParameters.AdditionalParameters}"; - - // important to run on all ports to allow port changing - Guid? logFileGuid = null; - var arguments = String.Format( - CultureInfo.InvariantCulture, - "{0} -port {1} -ports 1-65535 {2}-close -verbose -{3} -{4}{5}{6} -params \"{7}\"", - dmbProvider.DmbName, - launchParameters.Port.Value, - launchParameters.AllowWebClient.Value ? "-webclient " : String.Empty, - SecurityWord(launchParameters.SecurityLevel.Value), - VisibilityWord(launchParameters.Visibility.Value), - !byondLock.SupportsCli - ? $" -logself -log {logFileGuid = Guid.NewGuid()}" - : !platformIdentifier.IsWindows // Just use stdout on if CLI is supported - ? " -logself" - : String.Empty, // Windows doesn't output anything to dd.exe if -logself is set? - launchParameters.StartProfiler.Value - ? " -profile" - : String.Empty, - parameters); - - if (!apiValidate && dmbProvider.CompileJob.DMApiVersion == null) - logger.LogDebug("Session will have no DMAPI support!"); - - // launch dd - var process = processExecutor.LaunchProcess( - byondLock.DreamDaemonPath, - dmbProvider.Directory, - arguments, - byondLock.SupportsCli, - byondLock.SupportsCli, - byondLock.SupportsCli); - - var cliSupported = byondLock.SupportsCli; - async Task GetDDOutput() - { - // DCT x2: None available - if (cliSupported) - return await process.GetCombinedOutput(default); - - var logFilePath = ioManager.ConcatPath(dmbProvider.Directory, logFileGuid.ToString()); - try - { - var dreamDaemonLogBytes = await ioManager.ReadAllBytes( - logFilePath, - default) - ; - - return Encoding.UTF8.GetString(dreamDaemonLogBytes); - } - finally - { - try - { - // DCT: No token available - await ioManager.DeleteFile(logFilePath, default); - } - catch (Exception ex) - { - logger.LogWarning(ex, "Failed to delete DreamDaemon log file {0}!", logFilePath); - } - } - } - - // Log DD output - async Task PostLifetime() - { - try - { - var ddOutput = await GetDDOutput(); - logger.LogTrace( - "DreamDaemon Output:{0}{1}", - Environment.NewLine, - ddOutput); - } - catch (Exception ex) - { - logger.LogWarning(ex, "Error reading DreamDaemon output!"); - } - } + var chatTrackingContext = chat.CreateTrackingContext(); try { - networkPromptReaper.RegisterProcess(process); - var runtimeInformation = CreateRuntimeInformation( dmbProvider, chatTrackingContext, - launchParameters.SecurityLevel.Value, - launchParameters.Visibility.Value, + launchParameters, apiValidate); var reattachInformation = new ReattachInformation( @@ -387,56 +341,38 @@ namespace Tgstation.Server.Host.Components.Session chat, assemblyInformationProvider, loggerFactory.CreateLogger(), - PostLifetime, + () => !launchParameters.LogOutput.Value + ? LogDDOutput(process, outputFilePath, byondLock.SupportsCli, default) // DCT: None available + : Task.CompletedTask, launchParameters.StartupTimeout, false, apiValidate); - if (apiValidate) - { - if (sessionConfiguration.HighPriorityLiveDreamDaemon) - process.AdjustPriority(true); - } - else if (sessionConfiguration.LowPriorityDeploymentProcesses) - process.AdjustPriority(false); - - // If this isnt a staging DD (From a Deployment), fire off an event - if (!apiValidate) - await eventConsumer.HandleEvent( - EventType.DreamDaemonLaunch, - new List - { - process.Id.ToString(CultureInfo.InvariantCulture), - }, - cancellationToken) - ; - return sessionController; } catch { - using (process) - { - process.Terminate(); - await process.Lifetime; - throw; - } + chatTrackingContext.Dispose(); + throw; } } catch { - if (currentByondLock == null) - byondLock.Dispose(); - throw; + await using (process) + { + process.Terminate(); + await process.Lifetime; + throw; + } } } catch { - chatTrackingContext.Dispose(); + if (currentByondLock == null) + byondLock.Dispose(); throw; } } -#pragma warning restore CA1506 /// public async Task Reattach( @@ -448,30 +384,30 @@ namespace Tgstation.Server.Host.Components.Session logger.LogTrace("Begin session reattach..."); var byondTopicSender = topicClientFactory.CreateTopicClient(reattachInformation.TopicRequestTimeout); - var chatTrackingContext = chat.CreateTrackingContext(); + var byondLock = await byond.UseExecutables(Version.Parse(reattachInformation.Dmb.CompileJob.ByondVersion), cancellationToken); + try { - var byondLock = await byond.UseExecutables(Version.Parse(reattachInformation.Dmb.CompileJob.ByondVersion), cancellationToken); + logger.LogDebug( + "Attaching to session PID: {0}, CompileJob: {1}...", + reattachInformation.ProcessId, + reattachInformation.Dmb.CompileJob.Id); + + var process = processExecutor.GetProcess(reattachInformation.ProcessId); + if (process == null) + return null; try { - logger.LogDebug( - "Attaching to session PID: {0}, CompileJob: {1}...", - reattachInformation.ProcessId, - reattachInformation.Dmb.CompileJob.Id); - - var process = processExecutor.GetProcess(reattachInformation.ProcessId); - if (process == null) - return null; + networkPromptReaper.RegisterProcess(process); + var chatTrackingContext = chat.CreateTrackingContext(); try { - networkPromptReaper.RegisterProcess(process); var runtimeInformation = CreateRuntimeInformation( reattachInformation.Dmb, chatTrackingContext, null, - null, false); reattachInformation.SetRuntimeInformation(runtimeInformation); @@ -497,19 +433,160 @@ namespace Tgstation.Server.Host.Components.Session return controller; } - finally + catch { - process?.Dispose(); + chatTrackingContext.Dispose(); + throw; } } - finally + catch { - byondLock?.Dispose(); + await process.DisposeAsync(); + throw; } } - finally + catch { - chatTrackingContext?.Dispose(); + byondLock.Dispose(); + throw; + } + } + + /// + /// Creates the DreamDaemon . + /// + /// The . + /// The to use for sanitization. + /// The . + /// The . + /// The secure string to use for the session. + /// The path to log DreamDaemon output to. + /// If we are only validating the DMAPI then exiting. + /// The for the operation. + /// A resulting in the DreamDaemon . + async Task CreateDreamDaemonProcess( + IDmbProvider dmbProvider, + ITopicClient byondTopicSender, + IByondExecutableLock byondLock, + DreamDaemonLaunchParameters launchParameters, + string accessIdentifier, + string logFilePath, + bool apiValidate, + CancellationToken cancellationToken) + { + // set command line options + // more sanitization here cause it uses the same scheme + var parameters = $"{DMApiConstants.ParamApiVersion}={byondTopicSender.SanitizeString(DMApiConstants.InteropVersion.Semver().ToString())}&{byondTopicSender.SanitizeString(DMApiConstants.ParamServerPort)}={serverPortProvider.HttpApiPort}&{byondTopicSender.SanitizeString(DMApiConstants.ParamAccessIdentifier)}={byondTopicSender.SanitizeString(accessIdentifier)}"; + + if (!String.IsNullOrEmpty(launchParameters.AdditionalParameters)) + parameters = $"{parameters}&{launchParameters.AdditionalParameters}"; + + // important to run on all ports to allow port changing + var arguments = String.Format( + CultureInfo.InvariantCulture, + "{0} -port {1} -ports 1-65535 {2}-close -verbose -{3} -{4}{5}{6} -params \"{7}\"", + dmbProvider.DmbName, + launchParameters.Port.Value, + launchParameters.AllowWebClient.Value ? "-webclient " : String.Empty, + SecurityWord(launchParameters.SecurityLevel.Value), + VisibilityWord(launchParameters.Visibility.Value), + !byondLock.SupportsCli + ? $" -logself -log {logFilePath}" + : !platformIdentifier.IsWindows // Just use stdout on if CLI is supported + ? " -logself" + : String.Empty, // Windows doesn't output anything to dd.exe if -logself is set? + launchParameters.StartProfiler.Value + ? " -profile" + : String.Empty, + parameters); + + var process = await processExecutor.LaunchProcess( + byondLock.DreamDaemonPath, + dmbProvider.Directory, + arguments, + logFilePath, + byondLock.SupportsCli, + true); + + try + { + if (apiValidate) + { + if (sessionConfiguration.HighPriorityLiveDreamDaemon) + process.AdjustPriority(true); + } + else if (sessionConfiguration.LowPriorityDeploymentProcesses) + process.AdjustPriority(false); + + networkPromptReaper.RegisterProcess(process); + + // If this isnt a staging DD (From a Deployment), fire off an event + if (!apiValidate) + await eventConsumer.HandleEvent( + EventType.DreamDaemonLaunch, + new List + { + process.Id.ToString(CultureInfo.InvariantCulture), + }, + cancellationToken); + + return process; + } + catch + { + await using (process) + { + process.Terminate(); + await process.Lifetime; + throw; + } + } + } + + /// + /// Attempts to log DreamDaemon output. + /// + /// The DreamDaemon . + /// The path to the DreamDaemon log file. Will be deleted. + /// If DreamDaemon was launched with CLI capabilities. + /// The for the operation. + /// A representing the running operation. + async Task LogDDOutput(IProcess process, string outputFilePath, bool cliSupported, CancellationToken cancellationToken) + { + try + { + string ddOutput; + if (cliSupported) + ddOutput = await process.GetCombinedOutput(cancellationToken); + else + try + { + var dreamDaemonLogBytes = await gameIOManager.ReadAllBytes( + outputFilePath, + cancellationToken); + + ddOutput = Encoding.UTF8.GetString(dreamDaemonLogBytes); + } + finally + { + try + { + await gameIOManager.DeleteFile(outputFilePath, cancellationToken); + } + catch (Exception ex) + { + logger.LogWarning(ex, "Failed to delete DreamDaemon log file {outputFilePath}!", outputFilePath); + } + } + + logger.LogTrace( + "DreamDaemon Output:{newLine}{output}", + Environment.NewLine, + ddOutput); + } + catch (Exception ex) + { + logger.LogWarning(ex, "Error reading DreamDaemon output!"); } } @@ -518,23 +595,21 @@ namespace Tgstation.Server.Host.Components.Session /// /// The . /// The . - /// The level if any. - /// The if any. + /// The if any. /// The value of . /// A new class. RuntimeInformation CreateRuntimeInformation( IDmbProvider dmbProvider, IChatTrackingContext chatTrackingContext, - DreamDaemonSecurity? securityLevel, - DreamDaemonVisibility? visibility, + DreamDaemonLaunchParameters launchParameters, bool apiValidateOnly) => new RuntimeInformation( chatTrackingContext, dmbProvider, assemblyInformationProvider.Version, instance.Name, - securityLevel, - visibility, + launchParameters?.SecurityLevel, + launchParameters?.Visibility, serverPortProvider.HttpApiPort, apiValidateOnly); @@ -548,12 +623,12 @@ namespace Tgstation.Server.Host.Components.Session if (!platformIdentifier.IsWindows) return; - using var otherProcess = processExecutor.GetProcessByName("byond"); + await using var otherProcess = processExecutor.GetProcessByName("byond"); if (otherProcess == null) return; var otherUsernameTask = otherProcess.GetExecutingUsername(cancellationToken); - using var ourProcess = processExecutor.GetCurrentProcess(); + await using var ourProcess = processExecutor.GetCurrentProcess(); var ourUserName = await ourProcess.GetExecutingUsername(cancellationToken); var otherUserName = await otherUsernameTask; diff --git a/src/Tgstation.Server.Host/Components/Session/SessionPersistor.cs b/src/Tgstation.Server.Host/Components/Session/SessionPersistor.cs index d51bf8da5c..c6701c4ef0 100644 --- a/src/Tgstation.Server.Host/Components/Session/SessionPersistor.cs +++ b/src/Tgstation.Server.Host/Components/Session/SessionPersistor.cs @@ -99,7 +99,7 @@ namespace Tgstation.Server.Host.Components.Session { try { - using var process = processExecutor.GetProcess(reattachInfo.ProcessId); + await using var process = processExecutor.GetProcess(reattachInfo.ProcessId); if (process != null) { if (reattachInfo == result) diff --git a/src/Tgstation.Server.Host/Components/StaticFiles/Configuration.cs b/src/Tgstation.Server.Host/Components/StaticFiles/Configuration.cs index 7b84ce8ebf..9ed5959137 100644 --- a/src/Tgstation.Server.Host/Components/StaticFiles/Configuration.cs +++ b/src/Tgstation.Server.Host/Components/StaticFiles/Configuration.cs @@ -562,7 +562,7 @@ namespace Tgstation.Server.Host.Components.StaticFiles foreach (var scriptFile in scriptFiles) { logger.LogTrace("Running event script {scriptFile}...", scriptFile); - using (var script = processExecutor.LaunchProcess( + await using (var script = await processExecutor.LaunchProcess( ioManager.ConcatPath(resolvedScriptsDir, scriptFile), resolvedScriptsDir, String.Join( @@ -576,9 +576,8 @@ namespace Tgstation.Server.Host.Components.StaticFiles return $"\"{arg}\""; })), - true, - true, - true)) + readStandardHandles: true, + noShellExecute: true)) using (cancellationToken.Register(() => script.Terminate())) { var exitCode = await script.Lifetime; diff --git a/src/Tgstation.Server.Host/Controllers/DreamDaemonController.cs b/src/Tgstation.Server.Host/Controllers/DreamDaemonController.cs index 60abece7b8..c4af8f06d1 100644 --- a/src/Tgstation.Server.Host/Controllers/DreamDaemonController.cs +++ b/src/Tgstation.Server.Host/Controllers/DreamDaemonController.cs @@ -150,7 +150,8 @@ namespace Tgstation.Server.Host.Controllers | DreamDaemonRights.SetTopicTimeout | DreamDaemonRights.SetAdditionalParameters | DreamDaemonRights.SetVisibility - | DreamDaemonRights.SetProfiler)] + | DreamDaemonRights.SetProfiler + | DreamDaemonRights.SetLogOutput)] [ProducesResponseType(typeof(DreamDaemonResponse), 200)] [ProducesResponseType(typeof(ErrorMessageResponse), 410)] #pragma warning disable CA1502 // TODO: Decomplexify @@ -224,7 +225,8 @@ namespace Tgstation.Server.Host.Controllers || CheckModified(x => x.DumpOnHeartbeatRestart, DreamDaemonRights.CreateDump) || CheckModified(x => x.TopicRequestTimeout, DreamDaemonRights.SetTopicTimeout) || CheckModified(x => x.AdditionalParameters, DreamDaemonRights.SetAdditionalParameters) - || CheckModified(x => x.StartProfiler, DreamDaemonRights.SetProfiler)) + || CheckModified(x => x.StartProfiler, DreamDaemonRights.SetProfiler) + || CheckModified(x => x.LogOutput, DreamDaemonRights.SetLogOutput)) return Forbid(); await DatabaseContext.Save(cancellationToken); @@ -365,6 +367,7 @@ namespace Tgstation.Server.Host.Controllers result.TopicRequestTimeout = settings.TopicRequestTimeout.Value; result.AdditionalParameters = settings.AdditionalParameters; result.StartProfiler = settings.StartProfiler; + result.LogOutput = settings.LogOutput; } if (revision) diff --git a/src/Tgstation.Server.Host/Controllers/InstanceController.cs b/src/Tgstation.Server.Host/Controllers/InstanceController.cs index b10390820b..359ed590fe 100644 --- a/src/Tgstation.Server.Host/Controllers/InstanceController.cs +++ b/src/Tgstation.Server.Host/Controllers/InstanceController.cs @@ -725,6 +725,7 @@ namespace Tgstation.Server.Host.Controllers TopicRequestTimeout = generalConfiguration.ByondTopicTimeout, AdditionalParameters = String.Empty, StartProfiler = false, + LogOutput = false, }, DreamMakerSettings = new DreamMakerSettings { diff --git a/src/Tgstation.Server.Host/Database/DatabaseContext.cs b/src/Tgstation.Server.Host/Database/DatabaseContext.cs index 93a68f8c8c..b7a197143d 100644 --- a/src/Tgstation.Server.Host/Database/DatabaseContext.cs +++ b/src/Tgstation.Server.Host/Database/DatabaseContext.cs @@ -379,22 +379,22 @@ namespace Tgstation.Server.Host.Database /// /// Used by unit tests to remind us to setup the correct MSSQL migration downgrades. /// - internal static readonly Type MSLatestMigration = typeof(MSAddProfiler); + internal static readonly Type MSLatestMigration = typeof(MSAddDreamDaemonLogOutput); /// /// Used by unit tests to remind us to setup the correct MYSQL migration downgrades. /// - internal static readonly Type MYLatestMigration = typeof(MYAddProfiler); + internal static readonly Type MYLatestMigration = typeof(MYAddDreamDaemonLogOutput); /// /// Used by unit tests to remind us to setup the correct PostgresSQL migration downgrades. /// - internal static readonly Type PGLatestMigration = typeof(PGAddProfiler); + internal static readonly Type PGLatestMigration = typeof(PGAddDreamDaemonLogOutput); /// /// Used by unit tests to remind us to setup the correct SQLite migration downgrades. /// - internal static readonly Type SLLatestMigration = typeof(SLAddProfiler); + internal static readonly Type SLLatestMigration = typeof(SLAddDreamDaemonLogOutput); /// #pragma warning disable CA1502 // Cyclomatic complexity @@ -425,6 +425,15 @@ namespace Tgstation.Server.Host.Database string BadDatabaseType() => throw new ArgumentException($"Invalid DatabaseType: {currentDatabaseType}", nameof(currentDatabaseType)); + if (targetVersion < new Version(5, 7, 0)) + targetMigration = currentDatabaseType switch + { + DatabaseType.MySql => nameof(MYAddProfiler), + DatabaseType.PostgresSql => nameof(PGAddProfiler), + DatabaseType.SqlServer => nameof(MSAddProfiler), + DatabaseType.Sqlite => nameof(SLAddProfiler), + _ => BadDatabaseType(), + }; if (targetVersion < new Version(4, 19, 0)) targetMigration = currentDatabaseType switch { diff --git a/src/Tgstation.Server.Host/Database/Migrations/20230331220749_MSAddDreamDaemonLogOutput.Designer.cs b/src/Tgstation.Server.Host/Database/Migrations/20230331220749_MSAddDreamDaemonLogOutput.Designer.cs new file mode 100644 index 0000000000..02be0acad1 --- /dev/null +++ b/src/Tgstation.Server.Host/Database/Migrations/20230331220749_MSAddDreamDaemonLogOutput.Designer.cs @@ -0,0 +1,1054 @@ +// +using System; + +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Tgstation.Server.Host.Database.Migrations +{ + [DbContext(typeof(SqlServerDatabaseContext))] + [Migration("20230331220749_MSAddDreamDaemonLogOutput")] + partial class MSAddDreamDaemonLogOutput + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "6.0.15") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder, 1L, 1); + + modelBuilder.Entity("Tgstation.Server.Host.Models.ChatBot", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("ChannelLimit") + .HasColumnType("int"); + + b.Property("ConnectionString") + .IsRequired() + .HasMaxLength(10000) + .HasColumnType("nvarchar(max)"); + + b.Property("Enabled") + .HasColumnType("bit"); + + b.Property("InstanceId") + .HasColumnType("bigint"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("Provider") + .HasColumnType("int"); + + b.Property("ReconnectionInterval") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("InstanceId", "Name") + .IsUnique(); + + b.ToTable("ChatBots"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.ChatChannel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("ChatSettingsId") + .HasColumnType("bigint"); + + b.Property("DiscordChannelId") + .HasColumnType("decimal(20,0)"); + + b.Property("IrcChannel") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("IsAdminChannel") + .IsRequired() + .HasColumnType("bit"); + + b.Property("IsUpdatesChannel") + .IsRequired() + .HasColumnType("bit"); + + b.Property("IsWatchdogChannel") + .IsRequired() + .HasColumnType("bit"); + + b.Property("Tag") + .HasMaxLength(10000) + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("ChatSettingsId", "DiscordChannelId") + .IsUnique() + .HasFilter("[DiscordChannelId] IS NOT NULL"); + + b.HasIndex("ChatSettingsId", "IrcChannel") + .IsUnique() + .HasFilter("[IrcChannel] IS NOT NULL"); + + b.ToTable("ChatChannels"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.CompileJob", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("ByondVersion") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("DMApiMajorVersion") + .HasColumnType("int"); + + b.Property("DMApiMinorVersion") + .HasColumnType("int"); + + b.Property("DMApiPatchVersion") + .HasColumnType("int"); + + b.Property("DirectoryName") + .IsRequired() + .HasColumnType("uniqueidentifier"); + + b.Property("DmeName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("GitHubDeploymentId") + .HasColumnType("int"); + + b.Property("GitHubRepoId") + .HasColumnType("bigint"); + + b.Property("JobId") + .HasColumnType("bigint"); + + b.Property("MinimumSecurityLevel") + .HasColumnType("int"); + + b.Property("Output") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("RepositoryOrigin") + .HasColumnType("nvarchar(max)"); + + b.Property("RevisionInformationId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("DirectoryName"); + + b.HasIndex("JobId") + .IsUnique(); + + b.HasIndex("RevisionInformationId"); + + b.ToTable("CompileJobs"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.DreamDaemonSettings", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("AdditionalParameters") + .IsRequired() + .HasMaxLength(10000) + .HasColumnType("nvarchar(max)"); + + b.Property("AllowWebClient") + .IsRequired() + .HasColumnType("bit"); + + b.Property("AutoStart") + .IsRequired() + .HasColumnType("bit"); + + b.Property("DumpOnHeartbeatRestart") + .IsRequired() + .HasColumnType("bit"); + + b.Property("HeartbeatSeconds") + .HasColumnType("bigint"); + + b.Property("InstanceId") + .HasColumnType("bigint"); + + b.Property("LogOutput") + .IsRequired() + .HasColumnType("bit"); + + b.Property("Port") + .HasColumnType("int"); + + b.Property("SecurityLevel") + .HasColumnType("int"); + + b.Property("StartProfiler") + .IsRequired() + .HasColumnType("bit"); + + b.Property("StartupTimeout") + .HasColumnType("bigint"); + + b.Property("TopicRequestTimeout") + .HasColumnType("bigint"); + + b.Property("Visibility") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("InstanceId") + .IsUnique(); + + b.ToTable("DreamDaemonSettings"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.DreamMakerSettings", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("ApiValidationPort") + .HasColumnType("int"); + + b.Property("ApiValidationSecurityLevel") + .HasColumnType("int"); + + b.Property("InstanceId") + .HasColumnType("bigint"); + + b.Property("ProjectName") + .HasMaxLength(10000) + .HasColumnType("nvarchar(max)"); + + b.Property("RequireDMApiValidation") + .IsRequired() + .HasColumnType("bit"); + + b.Property("Timeout") + .IsRequired() + .HasColumnType("time"); + + b.HasKey("Id"); + + b.HasIndex("InstanceId") + .IsUnique(); + + b.ToTable("DreamMakerSettings"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.Instance", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("AutoUpdateInterval") + .HasColumnType("bigint"); + + b.Property("ChatBotLimit") + .HasColumnType("int"); + + b.Property("ConfigurationType") + .HasColumnType("int"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("Online") + .IsRequired() + .HasColumnType("bit"); + + b.Property("Path") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("SwarmIdentifer") + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("Path", "SwarmIdentifer") + .IsUnique() + .HasFilter("[SwarmIdentifer] IS NOT NULL"); + + b.ToTable("Instances"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.InstancePermissionSet", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("ByondRights") + .HasColumnType("decimal(20,0)"); + + b.Property("ChatBotRights") + .HasColumnType("decimal(20,0)"); + + b.Property("ConfigurationRights") + .HasColumnType("decimal(20,0)"); + + b.Property("DreamDaemonRights") + .HasColumnType("decimal(20,0)"); + + b.Property("DreamMakerRights") + .HasColumnType("decimal(20,0)"); + + b.Property("InstanceId") + .HasColumnType("bigint"); + + b.Property("InstancePermissionSetRights") + .HasColumnType("decimal(20,0)"); + + b.Property("PermissionSetId") + .HasColumnType("bigint"); + + b.Property("RepositoryRights") + .HasColumnType("decimal(20,0)"); + + b.HasKey("Id"); + + b.HasIndex("InstanceId"); + + b.HasIndex("PermissionSetId", "InstanceId") + .IsUnique(); + + b.ToTable("InstancePermissionSets"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.Job", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("CancelRight") + .HasColumnType("decimal(20,0)"); + + b.Property("CancelRightsType") + .HasColumnType("decimal(20,0)"); + + b.Property("Cancelled") + .IsRequired() + .HasColumnType("bit"); + + b.Property("CancelledById") + .HasColumnType("bigint"); + + b.Property("Description") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ErrorCode") + .HasColumnType("bigint"); + + b.Property("ExceptionDetails") + .HasColumnType("nvarchar(max)"); + + b.Property("InstanceId") + .HasColumnType("bigint"); + + b.Property("StartedAt") + .IsRequired() + .HasColumnType("datetimeoffset"); + + b.Property("StartedById") + .HasColumnType("bigint"); + + b.Property("StoppedAt") + .HasColumnType("datetimeoffset"); + + b.HasKey("Id"); + + b.HasIndex("CancelledById"); + + b.HasIndex("InstanceId"); + + b.HasIndex("StartedById"); + + b.ToTable("Jobs"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.OAuthConnection", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("ExternalUserId") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("Provider") + .HasColumnType("int"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.HasIndex("Provider", "ExternalUserId") + .IsUnique(); + + b.ToTable("OAuthConnections"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.PermissionSet", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("AdministrationRights") + .HasColumnType("decimal(20,0)"); + + b.Property("GroupId") + .HasColumnType("bigint"); + + b.Property("InstanceManagerRights") + .HasColumnType("decimal(20,0)"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("GroupId") + .IsUnique() + .HasFilter("[GroupId] IS NOT NULL"); + + b.HasIndex("UserId") + .IsUnique() + .HasFilter("[UserId] IS NOT NULL"); + + b.ToTable("PermissionSets"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.ReattachInformation", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("AccessIdentifier") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("CompileJobId") + .HasColumnType("bigint"); + + b.Property("LaunchSecurityLevel") + .HasColumnType("int"); + + b.Property("LaunchVisibility") + .HasColumnType("int"); + + b.Property("Port") + .HasColumnType("int"); + + b.Property("ProcessId") + .HasColumnType("int"); + + b.Property("RebootState") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("CompileJobId"); + + b.ToTable("ReattachInformations"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.RepositorySettings", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("AccessToken") + .HasMaxLength(10000) + .HasColumnType("nvarchar(max)"); + + b.Property("AccessUser") + .HasMaxLength(10000) + .HasColumnType("nvarchar(max)"); + + b.Property("AutoUpdatesKeepTestMerges") + .IsRequired() + .HasColumnType("bit"); + + b.Property("AutoUpdatesSynchronize") + .IsRequired() + .HasColumnType("bit"); + + b.Property("CommitterEmail") + .IsRequired() + .HasMaxLength(10000) + .HasColumnType("nvarchar(max)"); + + b.Property("CommitterName") + .IsRequired() + .HasMaxLength(10000) + .HasColumnType("nvarchar(max)"); + + b.Property("CreateGitHubDeployments") + .IsRequired() + .HasColumnType("bit"); + + b.Property("InstanceId") + .HasColumnType("bigint"); + + b.Property("PostTestMergeComment") + .IsRequired() + .HasColumnType("bit"); + + b.Property("PushTestMergeCommits") + .IsRequired() + .HasColumnType("bit"); + + b.Property("ShowTestMergeCommitters") + .IsRequired() + .HasColumnType("bit"); + + b.Property("UpdateSubmodules") + .IsRequired() + .HasColumnType("bit"); + + b.HasKey("Id"); + + b.HasIndex("InstanceId") + .IsUnique(); + + b.ToTable("RepositorySettings"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.RevInfoTestMerge", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("RevisionInformationId") + .HasColumnType("bigint"); + + b.Property("TestMergeId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("RevisionInformationId"); + + b.HasIndex("TestMergeId"); + + b.ToTable("RevInfoTestMerges"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.RevisionInformation", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("CommitSha") + .IsRequired() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)"); + + b.Property("InstanceId") + .HasColumnType("bigint"); + + b.Property("OriginCommitSha") + .IsRequired() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)"); + + b.Property("Timestamp") + .HasColumnType("datetimeoffset"); + + b.HasKey("Id"); + + b.HasIndex("InstanceId", "CommitSha") + .IsUnique(); + + b.ToTable("RevisionInformations"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.TestMerge", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("Author") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("BodyAtMerge") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Comment") + .HasMaxLength(10000) + .HasColumnType("nvarchar(max)"); + + b.Property("MergedAt") + .HasColumnType("datetimeoffset"); + + b.Property("MergedById") + .HasColumnType("bigint"); + + b.Property("Number") + .HasColumnType("int"); + + b.Property("PrimaryRevisionInformationId") + .IsRequired() + .HasColumnType("bigint"); + + b.Property("TargetCommitSha") + .IsRequired() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)"); + + b.Property("TitleAtMerge") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Url") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("MergedById"); + + b.HasIndex("PrimaryRevisionInformationId") + .IsUnique(); + + b.ToTable("TestMerges"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("CanonicalName") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("CreatedAt") + .IsRequired() + .HasColumnType("datetimeoffset"); + + b.Property("CreatedById") + .HasColumnType("bigint"); + + b.Property("Enabled") + .IsRequired() + .HasColumnType("bit"); + + b.Property("GroupId") + .HasColumnType("bigint"); + + b.Property("LastPasswordUpdate") + .HasColumnType("datetimeoffset"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("PasswordHash") + .HasColumnType("nvarchar(max)"); + + b.Property("SystemIdentifier") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.HasKey("Id"); + + b.HasIndex("CanonicalName") + .IsUnique(); + + b.HasIndex("CreatedById"); + + b.HasIndex("GroupId"); + + b.HasIndex("SystemIdentifier") + .IsUnique() + .HasFilter("[SystemIdentifier] IS NOT NULL"); + + b.ToTable("Users"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.UserGroup", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + + b.Property("Name") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Groups"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.ChatBot", b => + { + b.HasOne("Tgstation.Server.Host.Models.Instance", "Instance") + .WithMany("ChatSettings") + .HasForeignKey("InstanceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Instance"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.ChatChannel", b => + { + b.HasOne("Tgstation.Server.Host.Models.ChatBot", "ChatSettings") + .WithMany("Channels") + .HasForeignKey("ChatSettingsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ChatSettings"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.CompileJob", b => + { + b.HasOne("Tgstation.Server.Host.Models.Job", "Job") + .WithOne() + .HasForeignKey("Tgstation.Server.Host.Models.CompileJob", "JobId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Tgstation.Server.Host.Models.RevisionInformation", "RevisionInformation") + .WithMany("CompileJobs") + .HasForeignKey("RevisionInformationId") + .OnDelete(DeleteBehavior.ClientNoAction) + .IsRequired(); + + b.Navigation("Job"); + + b.Navigation("RevisionInformation"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.DreamDaemonSettings", b => + { + b.HasOne("Tgstation.Server.Host.Models.Instance", "Instance") + .WithOne("DreamDaemonSettings") + .HasForeignKey("Tgstation.Server.Host.Models.DreamDaemonSettings", "InstanceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Instance"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.DreamMakerSettings", b => + { + b.HasOne("Tgstation.Server.Host.Models.Instance", "Instance") + .WithOne("DreamMakerSettings") + .HasForeignKey("Tgstation.Server.Host.Models.DreamMakerSettings", "InstanceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Instance"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.InstancePermissionSet", b => + { + b.HasOne("Tgstation.Server.Host.Models.Instance", "Instance") + .WithMany("InstancePermissionSets") + .HasForeignKey("InstanceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Tgstation.Server.Host.Models.PermissionSet", "PermissionSet") + .WithMany("InstancePermissionSets") + .HasForeignKey("PermissionSetId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Instance"); + + b.Navigation("PermissionSet"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.Job", b => + { + b.HasOne("Tgstation.Server.Host.Models.User", "CancelledBy") + .WithMany() + .HasForeignKey("CancelledById"); + + b.HasOne("Tgstation.Server.Host.Models.Instance", "Instance") + .WithMany("Jobs") + .HasForeignKey("InstanceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Tgstation.Server.Host.Models.User", "StartedBy") + .WithMany() + .HasForeignKey("StartedById") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CancelledBy"); + + b.Navigation("Instance"); + + b.Navigation("StartedBy"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.OAuthConnection", b => + { + b.HasOne("Tgstation.Server.Host.Models.User", "User") + .WithMany("OAuthConnections") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.PermissionSet", b => + { + b.HasOne("Tgstation.Server.Host.Models.UserGroup", "Group") + .WithOne("PermissionSet") + .HasForeignKey("Tgstation.Server.Host.Models.PermissionSet", "GroupId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("Tgstation.Server.Host.Models.User", "User") + .WithOne("PermissionSet") + .HasForeignKey("Tgstation.Server.Host.Models.PermissionSet", "UserId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("Group"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.ReattachInformation", b => + { + b.HasOne("Tgstation.Server.Host.Models.CompileJob", "CompileJob") + .WithMany() + .HasForeignKey("CompileJobId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CompileJob"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.RepositorySettings", b => + { + b.HasOne("Tgstation.Server.Host.Models.Instance", "Instance") + .WithOne("RepositorySettings") + .HasForeignKey("Tgstation.Server.Host.Models.RepositorySettings", "InstanceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Instance"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.RevInfoTestMerge", b => + { + b.HasOne("Tgstation.Server.Host.Models.RevisionInformation", "RevisionInformation") + .WithMany("ActiveTestMerges") + .HasForeignKey("RevisionInformationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Tgstation.Server.Host.Models.TestMerge", "TestMerge") + .WithMany("RevisonInformations") + .HasForeignKey("TestMergeId") + .OnDelete(DeleteBehavior.ClientNoAction) + .IsRequired(); + + b.Navigation("RevisionInformation"); + + b.Navigation("TestMerge"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.RevisionInformation", b => + { + b.HasOne("Tgstation.Server.Host.Models.Instance", "Instance") + .WithMany("RevisionInformations") + .HasForeignKey("InstanceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Instance"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.TestMerge", b => + { + b.HasOne("Tgstation.Server.Host.Models.User", "MergedBy") + .WithMany("TestMerges") + .HasForeignKey("MergedById") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("Tgstation.Server.Host.Models.RevisionInformation", "PrimaryRevisionInformation") + .WithOne("PrimaryTestMerge") + .HasForeignKey("Tgstation.Server.Host.Models.TestMerge", "PrimaryRevisionInformationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("MergedBy"); + + b.Navigation("PrimaryRevisionInformation"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.User", b => + { + b.HasOne("Tgstation.Server.Host.Models.User", "CreatedBy") + .WithMany("CreatedUsers") + .HasForeignKey("CreatedById"); + + b.HasOne("Tgstation.Server.Host.Models.UserGroup", "Group") + .WithMany("Users") + .HasForeignKey("GroupId"); + + b.Navigation("CreatedBy"); + + b.Navigation("Group"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.ChatBot", b => + { + b.Navigation("Channels"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.Instance", b => + { + b.Navigation("ChatSettings"); + + b.Navigation("DreamDaemonSettings"); + + b.Navigation("DreamMakerSettings"); + + b.Navigation("InstancePermissionSets"); + + b.Navigation("Jobs"); + + b.Navigation("RepositorySettings"); + + b.Navigation("RevisionInformations"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.PermissionSet", b => + { + b.Navigation("InstancePermissionSets"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.RevisionInformation", b => + { + b.Navigation("ActiveTestMerges"); + + b.Navigation("CompileJobs"); + + b.Navigation("PrimaryTestMerge"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.TestMerge", b => + { + b.Navigation("RevisonInformations"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.User", b => + { + b.Navigation("CreatedUsers"); + + b.Navigation("OAuthConnections"); + + b.Navigation("PermissionSet"); + + b.Navigation("TestMerges"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.UserGroup", b => + { + b.Navigation("PermissionSet") + .IsRequired(); + + b.Navigation("Users"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/Tgstation.Server.Host/Database/Migrations/20230331220749_MSAddDreamDaemonLogOutput.cs b/src/Tgstation.Server.Host/Database/Migrations/20230331220749_MSAddDreamDaemonLogOutput.cs new file mode 100644 index 0000000000..366ac06457 --- /dev/null +++ b/src/Tgstation.Server.Host/Database/Migrations/20230331220749_MSAddDreamDaemonLogOutput.cs @@ -0,0 +1,39 @@ +using System; + +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Tgstation.Server.Host.Database.Migrations +{ + /// + /// Adds the DreamDaemon LogOutput column for MSSQL. + /// + public partial class MSAddDreamDaemonLogOutput : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + if (migrationBuilder == null) + throw new ArgumentNullException(nameof(migrationBuilder)); + + migrationBuilder.AddColumn( + name: "LogOutput", + table: "DreamDaemonSettings", + type: "bit", + nullable: false, + defaultValue: false); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + if (migrationBuilder == null) + throw new ArgumentNullException(nameof(migrationBuilder)); + + migrationBuilder.DropColumn( + name: "LogOutput", + table: "DreamDaemonSettings"); + } + } +} diff --git a/src/Tgstation.Server.Host/Database/Migrations/20230331220938_MYAddDreamDaemonLogOutput.Designer.cs b/src/Tgstation.Server.Host/Database/Migrations/20230331220938_MYAddDreamDaemonLogOutput.Designer.cs new file mode 100644 index 0000000000..b75b7d978c --- /dev/null +++ b/src/Tgstation.Server.Host/Database/Migrations/20230331220938_MYAddDreamDaemonLogOutput.Designer.cs @@ -0,0 +1,1021 @@ +// +using System; + +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Tgstation.Server.Host.Database.Migrations +{ + [DbContext(typeof(MySqlDatabaseContext))] + [Migration("20230331220938_MYAddDreamDaemonLogOutput")] + partial class MYAddDreamDaemonLogOutput + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "6.0.15") + .HasAnnotation("Relational:MaxIdentifierLength", 64); + + modelBuilder.Entity("Tgstation.Server.Host.Models.ChatBot", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + b.Property("ChannelLimit") + .IsRequired() + .HasColumnType("smallint unsigned"); + + b.Property("ConnectionString") + .IsRequired() + .HasMaxLength(10000) + .HasColumnType("varchar(10000)"); + + b.Property("Enabled") + .HasColumnType("tinyint(1)"); + + b.Property("InstanceId") + .HasColumnType("bigint"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("varchar(100)"); + + b.Property("Provider") + .HasColumnType("int"); + + b.Property("ReconnectionInterval") + .IsRequired() + .HasColumnType("int unsigned"); + + b.HasKey("Id"); + + b.HasIndex("InstanceId", "Name") + .IsUnique(); + + b.ToTable("ChatBots"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.ChatChannel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + b.Property("ChatSettingsId") + .HasColumnType("bigint"); + + b.Property("DiscordChannelId") + .HasColumnType("bigint unsigned"); + + b.Property("IrcChannel") + .HasMaxLength(100) + .HasColumnType("varchar(100)"); + + b.Property("IsAdminChannel") + .IsRequired() + .HasColumnType("tinyint(1)"); + + b.Property("IsUpdatesChannel") + .IsRequired() + .HasColumnType("tinyint(1)"); + + b.Property("IsWatchdogChannel") + .IsRequired() + .HasColumnType("tinyint(1)"); + + b.Property("Tag") + .HasMaxLength(10000) + .HasColumnType("varchar(10000)"); + + b.HasKey("Id"); + + b.HasIndex("ChatSettingsId", "DiscordChannelId") + .IsUnique(); + + b.HasIndex("ChatSettingsId", "IrcChannel") + .IsUnique(); + + b.ToTable("ChatChannels"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.CompileJob", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + b.Property("ByondVersion") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("DMApiMajorVersion") + .HasColumnType("int"); + + b.Property("DMApiMinorVersion") + .HasColumnType("int"); + + b.Property("DMApiPatchVersion") + .HasColumnType("int"); + + b.Property("DirectoryName") + .IsRequired() + .HasColumnType("char(36)"); + + b.Property("DmeName") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("GitHubDeploymentId") + .HasColumnType("int"); + + b.Property("GitHubRepoId") + .HasColumnType("bigint"); + + b.Property("JobId") + .HasColumnType("bigint"); + + b.Property("MinimumSecurityLevel") + .HasColumnType("int"); + + b.Property("Output") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("RepositoryOrigin") + .HasColumnType("longtext"); + + b.Property("RevisionInformationId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("DirectoryName"); + + b.HasIndex("JobId") + .IsUnique(); + + b.HasIndex("RevisionInformationId"); + + b.ToTable("CompileJobs"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.DreamDaemonSettings", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + b.Property("AdditionalParameters") + .IsRequired() + .HasMaxLength(10000) + .HasColumnType("varchar(10000)"); + + b.Property("AllowWebClient") + .IsRequired() + .HasColumnType("tinyint(1)"); + + b.Property("AutoStart") + .IsRequired() + .HasColumnType("tinyint(1)"); + + b.Property("DumpOnHeartbeatRestart") + .IsRequired() + .HasColumnType("tinyint(1)"); + + b.Property("HeartbeatSeconds") + .IsRequired() + .HasColumnType("int unsigned"); + + b.Property("InstanceId") + .HasColumnType("bigint"); + + b.Property("LogOutput") + .IsRequired() + .HasColumnType("tinyint(1)"); + + b.Property("Port") + .IsRequired() + .HasColumnType("smallint unsigned"); + + b.Property("SecurityLevel") + .HasColumnType("int"); + + b.Property("StartProfiler") + .IsRequired() + .HasColumnType("tinyint(1)"); + + b.Property("StartupTimeout") + .IsRequired() + .HasColumnType("int unsigned"); + + b.Property("TopicRequestTimeout") + .IsRequired() + .HasColumnType("int unsigned"); + + b.Property("Visibility") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("InstanceId") + .IsUnique(); + + b.ToTable("DreamDaemonSettings"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.DreamMakerSettings", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + b.Property("ApiValidationPort") + .IsRequired() + .HasColumnType("smallint unsigned"); + + b.Property("ApiValidationSecurityLevel") + .HasColumnType("int"); + + b.Property("InstanceId") + .HasColumnType("bigint"); + + b.Property("ProjectName") + .HasMaxLength(10000) + .HasColumnType("varchar(10000)"); + + b.Property("RequireDMApiValidation") + .IsRequired() + .HasColumnType("tinyint(1)"); + + b.Property("Timeout") + .IsRequired() + .HasColumnType("time(6)"); + + b.HasKey("Id"); + + b.HasIndex("InstanceId") + .IsUnique(); + + b.ToTable("DreamMakerSettings"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.Instance", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + b.Property("AutoUpdateInterval") + .IsRequired() + .HasColumnType("int unsigned"); + + b.Property("ChatBotLimit") + .IsRequired() + .HasColumnType("smallint unsigned"); + + b.Property("ConfigurationType") + .HasColumnType("int"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("varchar(100)"); + + b.Property("Online") + .IsRequired() + .HasColumnType("tinyint(1)"); + + b.Property("Path") + .IsRequired() + .HasColumnType("varchar(255)"); + + b.Property("SwarmIdentifer") + .HasColumnType("varchar(255)"); + + b.HasKey("Id"); + + b.HasIndex("Path", "SwarmIdentifer") + .IsUnique(); + + b.ToTable("Instances"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.InstancePermissionSet", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + b.Property("ByondRights") + .HasColumnType("bigint unsigned"); + + b.Property("ChatBotRights") + .HasColumnType("bigint unsigned"); + + b.Property("ConfigurationRights") + .HasColumnType("bigint unsigned"); + + b.Property("DreamDaemonRights") + .HasColumnType("bigint unsigned"); + + b.Property("DreamMakerRights") + .HasColumnType("bigint unsigned"); + + b.Property("InstanceId") + .HasColumnType("bigint"); + + b.Property("InstancePermissionSetRights") + .HasColumnType("bigint unsigned"); + + b.Property("PermissionSetId") + .HasColumnType("bigint"); + + b.Property("RepositoryRights") + .HasColumnType("bigint unsigned"); + + b.HasKey("Id"); + + b.HasIndex("InstanceId"); + + b.HasIndex("PermissionSetId", "InstanceId") + .IsUnique(); + + b.ToTable("InstancePermissionSets"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.Job", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + b.Property("CancelRight") + .HasColumnType("bigint unsigned"); + + b.Property("CancelRightsType") + .HasColumnType("bigint unsigned"); + + b.Property("Cancelled") + .IsRequired() + .HasColumnType("tinyint(1)"); + + b.Property("CancelledById") + .HasColumnType("bigint"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("ErrorCode") + .HasColumnType("int unsigned"); + + b.Property("ExceptionDetails") + .HasColumnType("longtext"); + + b.Property("InstanceId") + .HasColumnType("bigint"); + + b.Property("StartedAt") + .IsRequired() + .HasColumnType("datetime(6)"); + + b.Property("StartedById") + .HasColumnType("bigint"); + + b.Property("StoppedAt") + .HasColumnType("datetime(6)"); + + b.HasKey("Id"); + + b.HasIndex("CancelledById"); + + b.HasIndex("InstanceId"); + + b.HasIndex("StartedById"); + + b.ToTable("Jobs"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.OAuthConnection", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + b.Property("ExternalUserId") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("varchar(100)"); + + b.Property("Provider") + .HasColumnType("int"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.HasIndex("Provider", "ExternalUserId") + .IsUnique(); + + b.ToTable("OAuthConnections"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.PermissionSet", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + b.Property("AdministrationRights") + .HasColumnType("bigint unsigned"); + + b.Property("GroupId") + .HasColumnType("bigint"); + + b.Property("InstanceManagerRights") + .HasColumnType("bigint unsigned"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("GroupId") + .IsUnique(); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("PermissionSets"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.ReattachInformation", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + b.Property("AccessIdentifier") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("CompileJobId") + .HasColumnType("bigint"); + + b.Property("LaunchSecurityLevel") + .HasColumnType("int"); + + b.Property("LaunchVisibility") + .HasColumnType("int"); + + b.Property("Port") + .HasColumnType("smallint unsigned"); + + b.Property("ProcessId") + .HasColumnType("int"); + + b.Property("RebootState") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("CompileJobId"); + + b.ToTable("ReattachInformations"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.RepositorySettings", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + b.Property("AccessToken") + .HasMaxLength(10000) + .HasColumnType("varchar(10000)"); + + b.Property("AccessUser") + .HasMaxLength(10000) + .HasColumnType("varchar(10000)"); + + b.Property("AutoUpdatesKeepTestMerges") + .IsRequired() + .HasColumnType("tinyint(1)"); + + b.Property("AutoUpdatesSynchronize") + .IsRequired() + .HasColumnType("tinyint(1)"); + + b.Property("CommitterEmail") + .IsRequired() + .HasMaxLength(10000) + .HasColumnType("varchar(10000)"); + + b.Property("CommitterName") + .IsRequired() + .HasMaxLength(10000) + .HasColumnType("varchar(10000)"); + + b.Property("CreateGitHubDeployments") + .IsRequired() + .HasColumnType("tinyint(1)"); + + b.Property("InstanceId") + .HasColumnType("bigint"); + + b.Property("PostTestMergeComment") + .IsRequired() + .HasColumnType("tinyint(1)"); + + b.Property("PushTestMergeCommits") + .IsRequired() + .HasColumnType("tinyint(1)"); + + b.Property("ShowTestMergeCommitters") + .IsRequired() + .HasColumnType("tinyint(1)"); + + b.Property("UpdateSubmodules") + .IsRequired() + .HasColumnType("tinyint(1)"); + + b.HasKey("Id"); + + b.HasIndex("InstanceId") + .IsUnique(); + + b.ToTable("RepositorySettings"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.RevInfoTestMerge", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + b.Property("RevisionInformationId") + .HasColumnType("bigint"); + + b.Property("TestMergeId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("RevisionInformationId"); + + b.HasIndex("TestMergeId"); + + b.ToTable("RevInfoTestMerges"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.RevisionInformation", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + b.Property("CommitSha") + .IsRequired() + .HasMaxLength(40) + .HasColumnType("varchar(40)"); + + b.Property("InstanceId") + .HasColumnType("bigint"); + + b.Property("OriginCommitSha") + .IsRequired() + .HasMaxLength(40) + .HasColumnType("varchar(40)"); + + b.Property("Timestamp") + .HasColumnType("datetime(6)"); + + b.HasKey("Id"); + + b.HasIndex("InstanceId", "CommitSha") + .IsUnique(); + + b.ToTable("RevisionInformations"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.TestMerge", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + b.Property("Author") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("BodyAtMerge") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Comment") + .HasMaxLength(10000) + .HasColumnType("varchar(10000)"); + + b.Property("MergedAt") + .HasColumnType("datetime(6)"); + + b.Property("MergedById") + .HasColumnType("bigint"); + + b.Property("Number") + .HasColumnType("int"); + + b.Property("PrimaryRevisionInformationId") + .IsRequired() + .HasColumnType("bigint"); + + b.Property("TargetCommitSha") + .IsRequired() + .HasMaxLength(40) + .HasColumnType("varchar(40)"); + + b.Property("TitleAtMerge") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Url") + .IsRequired() + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.HasIndex("MergedById"); + + b.HasIndex("PrimaryRevisionInformationId") + .IsUnique(); + + b.ToTable("TestMerges"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + b.Property("CanonicalName") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("varchar(100)"); + + b.Property("CreatedAt") + .IsRequired() + .HasColumnType("datetime(6)"); + + b.Property("CreatedById") + .HasColumnType("bigint"); + + b.Property("Enabled") + .IsRequired() + .HasColumnType("tinyint(1)"); + + b.Property("GroupId") + .HasColumnType("bigint"); + + b.Property("LastPasswordUpdate") + .HasColumnType("datetime(6)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("varchar(100)"); + + b.Property("PasswordHash") + .HasColumnType("longtext"); + + b.Property("SystemIdentifier") + .HasMaxLength(100) + .HasColumnType("varchar(100)"); + + b.HasKey("Id"); + + b.HasIndex("CanonicalName") + .IsUnique(); + + b.HasIndex("CreatedById"); + + b.HasIndex("GroupId"); + + b.HasIndex("SystemIdentifier") + .IsUnique(); + + b.ToTable("Users"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.UserGroup", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("varchar(100)"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Groups"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.ChatBot", b => + { + b.HasOne("Tgstation.Server.Host.Models.Instance", "Instance") + .WithMany("ChatSettings") + .HasForeignKey("InstanceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Instance"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.ChatChannel", b => + { + b.HasOne("Tgstation.Server.Host.Models.ChatBot", "ChatSettings") + .WithMany("Channels") + .HasForeignKey("ChatSettingsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ChatSettings"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.CompileJob", b => + { + b.HasOne("Tgstation.Server.Host.Models.Job", "Job") + .WithOne() + .HasForeignKey("Tgstation.Server.Host.Models.CompileJob", "JobId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Tgstation.Server.Host.Models.RevisionInformation", "RevisionInformation") + .WithMany("CompileJobs") + .HasForeignKey("RevisionInformationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Job"); + + b.Navigation("RevisionInformation"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.DreamDaemonSettings", b => + { + b.HasOne("Tgstation.Server.Host.Models.Instance", "Instance") + .WithOne("DreamDaemonSettings") + .HasForeignKey("Tgstation.Server.Host.Models.DreamDaemonSettings", "InstanceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Instance"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.DreamMakerSettings", b => + { + b.HasOne("Tgstation.Server.Host.Models.Instance", "Instance") + .WithOne("DreamMakerSettings") + .HasForeignKey("Tgstation.Server.Host.Models.DreamMakerSettings", "InstanceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Instance"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.InstancePermissionSet", b => + { + b.HasOne("Tgstation.Server.Host.Models.Instance", "Instance") + .WithMany("InstancePermissionSets") + .HasForeignKey("InstanceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Tgstation.Server.Host.Models.PermissionSet", "PermissionSet") + .WithMany("InstancePermissionSets") + .HasForeignKey("PermissionSetId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Instance"); + + b.Navigation("PermissionSet"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.Job", b => + { + b.HasOne("Tgstation.Server.Host.Models.User", "CancelledBy") + .WithMany() + .HasForeignKey("CancelledById"); + + b.HasOne("Tgstation.Server.Host.Models.Instance", "Instance") + .WithMany("Jobs") + .HasForeignKey("InstanceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Tgstation.Server.Host.Models.User", "StartedBy") + .WithMany() + .HasForeignKey("StartedById") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CancelledBy"); + + b.Navigation("Instance"); + + b.Navigation("StartedBy"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.OAuthConnection", b => + { + b.HasOne("Tgstation.Server.Host.Models.User", "User") + .WithMany("OAuthConnections") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.PermissionSet", b => + { + b.HasOne("Tgstation.Server.Host.Models.UserGroup", "Group") + .WithOne("PermissionSet") + .HasForeignKey("Tgstation.Server.Host.Models.PermissionSet", "GroupId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("Tgstation.Server.Host.Models.User", "User") + .WithOne("PermissionSet") + .HasForeignKey("Tgstation.Server.Host.Models.PermissionSet", "UserId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("Group"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.ReattachInformation", b => + { + b.HasOne("Tgstation.Server.Host.Models.CompileJob", "CompileJob") + .WithMany() + .HasForeignKey("CompileJobId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CompileJob"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.RepositorySettings", b => + { + b.HasOne("Tgstation.Server.Host.Models.Instance", "Instance") + .WithOne("RepositorySettings") + .HasForeignKey("Tgstation.Server.Host.Models.RepositorySettings", "InstanceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Instance"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.RevInfoTestMerge", b => + { + b.HasOne("Tgstation.Server.Host.Models.RevisionInformation", "RevisionInformation") + .WithMany("ActiveTestMerges") + .HasForeignKey("RevisionInformationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Tgstation.Server.Host.Models.TestMerge", "TestMerge") + .WithMany("RevisonInformations") + .HasForeignKey("TestMergeId") + .OnDelete(DeleteBehavior.ClientNoAction) + .IsRequired(); + + b.Navigation("RevisionInformation"); + + b.Navigation("TestMerge"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.RevisionInformation", b => + { + b.HasOne("Tgstation.Server.Host.Models.Instance", "Instance") + .WithMany("RevisionInformations") + .HasForeignKey("InstanceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Instance"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.TestMerge", b => + { + b.HasOne("Tgstation.Server.Host.Models.User", "MergedBy") + .WithMany("TestMerges") + .HasForeignKey("MergedById") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("Tgstation.Server.Host.Models.RevisionInformation", "PrimaryRevisionInformation") + .WithOne("PrimaryTestMerge") + .HasForeignKey("Tgstation.Server.Host.Models.TestMerge", "PrimaryRevisionInformationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("MergedBy"); + + b.Navigation("PrimaryRevisionInformation"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.User", b => + { + b.HasOne("Tgstation.Server.Host.Models.User", "CreatedBy") + .WithMany("CreatedUsers") + .HasForeignKey("CreatedById"); + + b.HasOne("Tgstation.Server.Host.Models.UserGroup", "Group") + .WithMany("Users") + .HasForeignKey("GroupId"); + + b.Navigation("CreatedBy"); + + b.Navigation("Group"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.ChatBot", b => + { + b.Navigation("Channels"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.Instance", b => + { + b.Navigation("ChatSettings"); + + b.Navigation("DreamDaemonSettings"); + + b.Navigation("DreamMakerSettings"); + + b.Navigation("InstancePermissionSets"); + + b.Navigation("Jobs"); + + b.Navigation("RepositorySettings"); + + b.Navigation("RevisionInformations"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.PermissionSet", b => + { + b.Navigation("InstancePermissionSets"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.RevisionInformation", b => + { + b.Navigation("ActiveTestMerges"); + + b.Navigation("CompileJobs"); + + b.Navigation("PrimaryTestMerge"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.TestMerge", b => + { + b.Navigation("RevisonInformations"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.User", b => + { + b.Navigation("CreatedUsers"); + + b.Navigation("OAuthConnections"); + + b.Navigation("PermissionSet"); + + b.Navigation("TestMerges"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.UserGroup", b => + { + b.Navigation("PermissionSet") + .IsRequired(); + + b.Navigation("Users"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/Tgstation.Server.Host/Database/Migrations/20230331220938_MYAddDreamDaemonLogOutput.cs b/src/Tgstation.Server.Host/Database/Migrations/20230331220938_MYAddDreamDaemonLogOutput.cs new file mode 100644 index 0000000000..c1739b2ede --- /dev/null +++ b/src/Tgstation.Server.Host/Database/Migrations/20230331220938_MYAddDreamDaemonLogOutput.cs @@ -0,0 +1,388 @@ +using System; + +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Tgstation.Server.Host.Database.Migrations +{ + /// + /// Adds the DreamDaemon LogOutput column for MYSQL. Also corrects string column annotations. + /// + public partial class MYAddDreamDaemonLogOutput : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + if (migrationBuilder == null) + throw new ArgumentNullException(nameof(migrationBuilder)); + + migrationBuilder.AlterColumn( + name: "Comment", + table: "TestMerges", + type: "varchar(10000)", + maxLength: 10000, + nullable: true, + oldClrType: typeof(string), + oldType: "longtext CHARACTER SET utf8mb4", + oldMaxLength: 10000, + oldNullable: true) + .Annotation("MySql:CharSet", "utf8mb4") + .OldAnnotation("MySql:CharSet", "utf8mb4"); + + migrationBuilder.AlterColumn( + name: "CommitterName", + table: "RepositorySettings", + type: "varchar(10000)", + maxLength: 10000, + nullable: false, + oldClrType: typeof(string), + oldType: "longtext CHARACTER SET utf8mb4", + oldMaxLength: 10000) + .Annotation("MySql:CharSet", "utf8mb4") + .OldAnnotation("MySql:CharSet", "utf8mb4"); + + migrationBuilder.AlterColumn( + name: "CommitterEmail", + table: "RepositorySettings", + type: "varchar(10000)", + maxLength: 10000, + nullable: false, + oldClrType: typeof(string), + oldType: "longtext CHARACTER SET utf8mb4", + oldMaxLength: 10000) + .Annotation("MySql:CharSet", "utf8mb4") + .OldAnnotation("MySql:CharSet", "utf8mb4"); + + migrationBuilder.AlterColumn( + name: "AccessUser", + table: "RepositorySettings", + type: "varchar(10000)", + maxLength: 10000, + nullable: true, + oldClrType: typeof(string), + oldType: "longtext CHARACTER SET utf8mb4", + oldMaxLength: 10000, + oldNullable: true) + .Annotation("MySql:CharSet", "utf8mb4") + .OldAnnotation("MySql:CharSet", "utf8mb4"); + + migrationBuilder.AlterColumn( + name: "AccessToken", + table: "RepositorySettings", + type: "varchar(10000)", + maxLength: 10000, + nullable: true, + oldClrType: typeof(string), + oldType: "longtext CHARACTER SET utf8mb4", + oldMaxLength: 10000, + oldNullable: true) + .Annotation("MySql:CharSet", "utf8mb4") + .OldAnnotation("MySql:CharSet", "utf8mb4"); + + migrationBuilder.AlterColumn( + name: "ProjectName", + table: "DreamMakerSettings", + type: "varchar(10000)", + maxLength: 10000, + nullable: true, + oldClrType: typeof(string), + oldType: "longtext CHARACTER SET utf8mb4", + oldMaxLength: 10000, + oldNullable: true) + .Annotation("MySql:CharSet", "utf8mb4") + .OldAnnotation("MySql:CharSet", "utf8mb4"); + + migrationBuilder.AlterColumn( + name: "AdditionalParameters", + table: "DreamDaemonSettings", + type: "varchar(10000)", + maxLength: 10000, + nullable: false, + oldClrType: typeof(string), + oldType: "longtext CHARACTER SET utf8mb4", + oldMaxLength: 10000) + .Annotation("MySql:CharSet", "utf8mb4") + .OldAnnotation("MySql:CharSet", "utf8mb4"); + + migrationBuilder.AddColumn( + name: "LogOutput", + table: "DreamDaemonSettings", + type: "tinyint(1)", + nullable: false, + defaultValue: false); + + migrationBuilder.AlterColumn( + name: "Tag", + table: "ChatChannels", + type: "varchar(10000)", + maxLength: 10000, + nullable: true, + oldClrType: typeof(string), + oldType: "longtext CHARACTER SET utf8mb4", + oldMaxLength: 10000, + oldNullable: true) + .Annotation("MySql:CharSet", "utf8mb4") + .OldAnnotation("MySql:CharSet", "utf8mb4"); + + migrationBuilder.AlterColumn( + name: "ConnectionString", + table: "ChatBots", + type: "varchar(10000)", + maxLength: 10000, + nullable: false, + oldClrType: typeof(string), + oldType: "longtext CHARACTER SET utf8mb4", + oldMaxLength: 10000) + .Annotation("MySql:CharSet", "utf8mb4") + .OldAnnotation("MySql:CharSet", "utf8mb4"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + if (migrationBuilder == null) + throw new ArgumentNullException(nameof(migrationBuilder)); + + migrationBuilder.DropColumn( + name: "LogOutput", + table: "DreamDaemonSettings"); + + migrationBuilder.AlterColumn( + name: "PasswordHash", + table: "Users", + type: "longtext CHARACTER SET utf8mb4", + nullable: true, + oldClrType: typeof(string), + oldType: "longtext", + oldNullable: true) + .Annotation("MySql:CharSet", "utf8mb4") + .OldAnnotation("MySql:CharSet", "utf8mb4"); + + migrationBuilder.AlterColumn( + name: "Url", + table: "TestMerges", + type: "longtext CHARACTER SET utf8mb4", + nullable: false, + oldClrType: typeof(string), + oldType: "longtext") + .Annotation("MySql:CharSet", "utf8mb4") + .OldAnnotation("MySql:CharSet", "utf8mb4"); + + migrationBuilder.AlterColumn( + name: "TitleAtMerge", + table: "TestMerges", + type: "longtext CHARACTER SET utf8mb4", + nullable: false, + oldClrType: typeof(string), + oldType: "longtext") + .Annotation("MySql:CharSet", "utf8mb4") + .OldAnnotation("MySql:CharSet", "utf8mb4"); + + migrationBuilder.AlterColumn( + name: "Comment", + table: "TestMerges", + type: "longtext CHARACTER SET utf8mb4", + maxLength: 10000, + nullable: true, + oldClrType: typeof(string), + oldType: "varchar(10000)", + oldMaxLength: 10000, + oldNullable: true) + .Annotation("MySql:CharSet", "utf8mb4") + .OldAnnotation("MySql:CharSet", "utf8mb4"); + + migrationBuilder.AlterColumn( + name: "BodyAtMerge", + table: "TestMerges", + type: "longtext CHARACTER SET utf8mb4", + nullable: false, + oldClrType: typeof(string), + oldType: "longtext") + .Annotation("MySql:CharSet", "utf8mb4") + .OldAnnotation("MySql:CharSet", "utf8mb4"); + + migrationBuilder.AlterColumn( + name: "Author", + table: "TestMerges", + type: "longtext CHARACTER SET utf8mb4", + nullable: false, + oldClrType: typeof(string), + oldType: "longtext") + .Annotation("MySql:CharSet", "utf8mb4") + .OldAnnotation("MySql:CharSet", "utf8mb4"); + + migrationBuilder.AlterColumn( + name: "CommitterName", + table: "RepositorySettings", + type: "longtext CHARACTER SET utf8mb4", + maxLength: 10000, + nullable: false, + oldClrType: typeof(string), + oldType: "varchar(10000)", + oldMaxLength: 10000) + .Annotation("MySql:CharSet", "utf8mb4") + .OldAnnotation("MySql:CharSet", "utf8mb4"); + + migrationBuilder.AlterColumn( + name: "CommitterEmail", + table: "RepositorySettings", + type: "longtext CHARACTER SET utf8mb4", + maxLength: 10000, + nullable: false, + oldClrType: typeof(string), + oldType: "varchar(10000)", + oldMaxLength: 10000) + .Annotation("MySql:CharSet", "utf8mb4") + .OldAnnotation("MySql:CharSet", "utf8mb4"); + + migrationBuilder.AlterColumn( + name: "AccessUser", + table: "RepositorySettings", + type: "longtext CHARACTER SET utf8mb4", + maxLength: 10000, + nullable: true, + oldClrType: typeof(string), + oldType: "varchar(10000)", + oldMaxLength: 10000, + oldNullable: true) + .Annotation("MySql:CharSet", "utf8mb4") + .OldAnnotation("MySql:CharSet", "utf8mb4"); + + migrationBuilder.AlterColumn( + name: "AccessToken", + table: "RepositorySettings", + type: "longtext CHARACTER SET utf8mb4", + maxLength: 10000, + nullable: true, + oldClrType: typeof(string), + oldType: "varchar(10000)", + oldMaxLength: 10000, + oldNullable: true) + .Annotation("MySql:CharSet", "utf8mb4") + .OldAnnotation("MySql:CharSet", "utf8mb4"); + + migrationBuilder.AlterColumn( + name: "AccessIdentifier", + table: "ReattachInformations", + type: "longtext CHARACTER SET utf8mb4", + nullable: false, + oldClrType: typeof(string), + oldType: "longtext") + .Annotation("MySql:CharSet", "utf8mb4") + .OldAnnotation("MySql:CharSet", "utf8mb4"); + + migrationBuilder.AlterColumn( + name: "ExceptionDetails", + table: "Jobs", + type: "longtext CHARACTER SET utf8mb4", + nullable: true, + oldClrType: typeof(string), + oldType: "longtext", + oldNullable: true) + .Annotation("MySql:CharSet", "utf8mb4") + .OldAnnotation("MySql:CharSet", "utf8mb4"); + + migrationBuilder.AlterColumn( + name: "Description", + table: "Jobs", + type: "longtext CHARACTER SET utf8mb4", + nullable: false, + oldClrType: typeof(string), + oldType: "longtext") + .Annotation("MySql:CharSet", "utf8mb4") + .OldAnnotation("MySql:CharSet", "utf8mb4"); + + migrationBuilder.AlterColumn( + name: "ProjectName", + table: "DreamMakerSettings", + type: "longtext CHARACTER SET utf8mb4", + maxLength: 10000, + nullable: true, + oldClrType: typeof(string), + oldType: "varchar(10000)", + oldMaxLength: 10000, + oldNullable: true) + .Annotation("MySql:CharSet", "utf8mb4") + .OldAnnotation("MySql:CharSet", "utf8mb4"); + + migrationBuilder.AlterColumn( + name: "AdditionalParameters", + table: "DreamDaemonSettings", + type: "longtext CHARACTER SET utf8mb4", + maxLength: 10000, + nullable: false, + oldClrType: typeof(string), + oldType: "varchar(10000)", + oldMaxLength: 10000) + .Annotation("MySql:CharSet", "utf8mb4") + .OldAnnotation("MySql:CharSet", "utf8mb4"); + + migrationBuilder.AlterColumn( + name: "RepositoryOrigin", + table: "CompileJobs", + type: "longtext CHARACTER SET utf8mb4", + nullable: true, + oldClrType: typeof(string), + oldType: "longtext", + oldNullable: true) + .Annotation("MySql:CharSet", "utf8mb4") + .OldAnnotation("MySql:CharSet", "utf8mb4"); + + migrationBuilder.AlterColumn( + name: "Output", + table: "CompileJobs", + type: "longtext CHARACTER SET utf8mb4", + nullable: false, + oldClrType: typeof(string), + oldType: "longtext") + .Annotation("MySql:CharSet", "utf8mb4") + .OldAnnotation("MySql:CharSet", "utf8mb4"); + + migrationBuilder.AlterColumn( + name: "DmeName", + table: "CompileJobs", + type: "longtext CHARACTER SET utf8mb4", + nullable: false, + oldClrType: typeof(string), + oldType: "longtext") + .Annotation("MySql:CharSet", "utf8mb4") + .OldAnnotation("MySql:CharSet", "utf8mb4"); + + migrationBuilder.AlterColumn( + name: "ByondVersion", + table: "CompileJobs", + type: "longtext CHARACTER SET utf8mb4", + nullable: false, + oldClrType: typeof(string), + oldType: "longtext") + .Annotation("MySql:CharSet", "utf8mb4") + .OldAnnotation("MySql:CharSet", "utf8mb4"); + + migrationBuilder.AlterColumn( + name: "Tag", + table: "ChatChannels", + type: "longtext CHARACTER SET utf8mb4", + maxLength: 10000, + nullable: true, + oldClrType: typeof(string), + oldType: "varchar(10000)", + oldMaxLength: 10000, + oldNullable: true) + .Annotation("MySql:CharSet", "utf8mb4") + .OldAnnotation("MySql:CharSet", "utf8mb4"); + + migrationBuilder.AlterColumn( + name: "ConnectionString", + table: "ChatBots", + type: "longtext CHARACTER SET utf8mb4", + maxLength: 10000, + nullable: false, + oldClrType: typeof(string), + oldType: "varchar(10000)", + oldMaxLength: 10000) + .Annotation("MySql:CharSet", "utf8mb4") + .OldAnnotation("MySql:CharSet", "utf8mb4"); + } + } +} diff --git a/src/Tgstation.Server.Host/Database/Migrations/20230331221032_PGAddDreamDaemonLogOutput.Designer.cs b/src/Tgstation.Server.Host/Database/Migrations/20230331221032_PGAddDreamDaemonLogOutput.Designer.cs new file mode 100644 index 0000000000..c1bb3e23c5 --- /dev/null +++ b/src/Tgstation.Server.Host/Database/Migrations/20230331221032_PGAddDreamDaemonLogOutput.Designer.cs @@ -0,0 +1,1048 @@ +// +using System; + +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Tgstation.Server.Host.Database.Migrations +{ + [DbContext(typeof(PostgresSqlDatabaseContext))] + [Migration("20230331221032_PGAddDreamDaemonLogOutput")] + partial class PGAddDreamDaemonLogOutput + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "6.0.15") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("Tgstation.Server.Host.Models.ChatBot", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ChannelLimit") + .HasColumnType("integer"); + + b.Property("ConnectionString") + .IsRequired() + .HasMaxLength(10000) + .HasColumnType("character varying(10000)"); + + b.Property("Enabled") + .HasColumnType("boolean"); + + b.Property("InstanceId") + .HasColumnType("bigint"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("Provider") + .HasColumnType("integer"); + + b.Property("ReconnectionInterval") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("InstanceId", "Name") + .IsUnique(); + + b.ToTable("ChatBots"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.ChatChannel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ChatSettingsId") + .HasColumnType("bigint"); + + b.Property("DiscordChannelId") + .HasColumnType("numeric(20,0)"); + + b.Property("IrcChannel") + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("IsAdminChannel") + .IsRequired() + .HasColumnType("boolean"); + + b.Property("IsUpdatesChannel") + .IsRequired() + .HasColumnType("boolean"); + + b.Property("IsWatchdogChannel") + .IsRequired() + .HasColumnType("boolean"); + + b.Property("Tag") + .HasMaxLength(10000) + .HasColumnType("character varying(10000)"); + + b.HasKey("Id"); + + b.HasIndex("ChatSettingsId", "DiscordChannelId") + .IsUnique(); + + b.HasIndex("ChatSettingsId", "IrcChannel") + .IsUnique(); + + b.ToTable("ChatChannels"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.CompileJob", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ByondVersion") + .IsRequired() + .HasColumnType("text"); + + b.Property("DMApiMajorVersion") + .HasColumnType("integer"); + + b.Property("DMApiMinorVersion") + .HasColumnType("integer"); + + b.Property("DMApiPatchVersion") + .HasColumnType("integer"); + + b.Property("DirectoryName") + .IsRequired() + .HasColumnType("uuid"); + + b.Property("DmeName") + .IsRequired() + .HasColumnType("text"); + + b.Property("GitHubDeploymentId") + .HasColumnType("integer"); + + b.Property("GitHubRepoId") + .HasColumnType("bigint"); + + b.Property("JobId") + .HasColumnType("bigint"); + + b.Property("MinimumSecurityLevel") + .HasColumnType("integer"); + + b.Property("Output") + .IsRequired() + .HasColumnType("text"); + + b.Property("RepositoryOrigin") + .HasColumnType("text"); + + b.Property("RevisionInformationId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("DirectoryName"); + + b.HasIndex("JobId") + .IsUnique(); + + b.HasIndex("RevisionInformationId"); + + b.ToTable("CompileJobs"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.DreamDaemonSettings", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AdditionalParameters") + .IsRequired() + .HasMaxLength(10000) + .HasColumnType("character varying(10000)"); + + b.Property("AllowWebClient") + .IsRequired() + .HasColumnType("boolean"); + + b.Property("AutoStart") + .IsRequired() + .HasColumnType("boolean"); + + b.Property("DumpOnHeartbeatRestart") + .IsRequired() + .HasColumnType("boolean"); + + b.Property("HeartbeatSeconds") + .HasColumnType("bigint"); + + b.Property("InstanceId") + .HasColumnType("bigint"); + + b.Property("LogOutput") + .IsRequired() + .HasColumnType("boolean"); + + b.Property("Port") + .HasColumnType("integer"); + + b.Property("SecurityLevel") + .HasColumnType("integer"); + + b.Property("StartProfiler") + .IsRequired() + .HasColumnType("boolean"); + + b.Property("StartupTimeout") + .HasColumnType("bigint"); + + b.Property("TopicRequestTimeout") + .HasColumnType("bigint"); + + b.Property("Visibility") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("InstanceId") + .IsUnique(); + + b.ToTable("DreamDaemonSettings"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.DreamMakerSettings", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ApiValidationPort") + .HasColumnType("integer"); + + b.Property("ApiValidationSecurityLevel") + .HasColumnType("integer"); + + b.Property("InstanceId") + .HasColumnType("bigint"); + + b.Property("ProjectName") + .HasMaxLength(10000) + .HasColumnType("character varying(10000)"); + + b.Property("RequireDMApiValidation") + .IsRequired() + .HasColumnType("boolean"); + + b.Property("Timeout") + .IsRequired() + .HasColumnType("interval"); + + b.HasKey("Id"); + + b.HasIndex("InstanceId") + .IsUnique(); + + b.ToTable("DreamMakerSettings"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.Instance", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AutoUpdateInterval") + .HasColumnType("bigint"); + + b.Property("ChatBotLimit") + .HasColumnType("integer"); + + b.Property("ConfigurationType") + .HasColumnType("integer"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("Online") + .IsRequired() + .HasColumnType("boolean"); + + b.Property("Path") + .IsRequired() + .HasColumnType("text"); + + b.Property("SwarmIdentifer") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("Path", "SwarmIdentifer") + .IsUnique(); + + b.ToTable("Instances"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.InstancePermissionSet", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ByondRights") + .HasColumnType("numeric(20,0)"); + + b.Property("ChatBotRights") + .HasColumnType("numeric(20,0)"); + + b.Property("ConfigurationRights") + .HasColumnType("numeric(20,0)"); + + b.Property("DreamDaemonRights") + .HasColumnType("numeric(20,0)"); + + b.Property("DreamMakerRights") + .HasColumnType("numeric(20,0)"); + + b.Property("InstanceId") + .HasColumnType("bigint"); + + b.Property("InstancePermissionSetRights") + .HasColumnType("numeric(20,0)"); + + b.Property("PermissionSetId") + .HasColumnType("bigint"); + + b.Property("RepositoryRights") + .HasColumnType("numeric(20,0)"); + + b.HasKey("Id"); + + b.HasIndex("InstanceId"); + + b.HasIndex("PermissionSetId", "InstanceId") + .IsUnique(); + + b.ToTable("InstancePermissionSets"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.Job", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CancelRight") + .HasColumnType("numeric(20,0)"); + + b.Property("CancelRightsType") + .HasColumnType("numeric(20,0)"); + + b.Property("Cancelled") + .IsRequired() + .HasColumnType("boolean"); + + b.Property("CancelledById") + .HasColumnType("bigint"); + + b.Property("Description") + .IsRequired() + .HasColumnType("text"); + + b.Property("ErrorCode") + .HasColumnType("bigint"); + + b.Property("ExceptionDetails") + .HasColumnType("text"); + + b.Property("InstanceId") + .HasColumnType("bigint"); + + b.Property("StartedAt") + .IsRequired() + .HasColumnType("timestamp with time zone"); + + b.Property("StartedById") + .HasColumnType("bigint"); + + b.Property("StoppedAt") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("CancelledById"); + + b.HasIndex("InstanceId"); + + b.HasIndex("StartedById"); + + b.ToTable("Jobs"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.OAuthConnection", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ExternalUserId") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("Provider") + .HasColumnType("integer"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.HasIndex("Provider", "ExternalUserId") + .IsUnique(); + + b.ToTable("OAuthConnections"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.PermissionSet", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AdministrationRights") + .HasColumnType("numeric(20,0)"); + + b.Property("GroupId") + .HasColumnType("bigint"); + + b.Property("InstanceManagerRights") + .HasColumnType("numeric(20,0)"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("GroupId") + .IsUnique(); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("PermissionSets"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.ReattachInformation", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AccessIdentifier") + .IsRequired() + .HasColumnType("text"); + + b.Property("CompileJobId") + .HasColumnType("bigint"); + + b.Property("LaunchSecurityLevel") + .HasColumnType("integer"); + + b.Property("LaunchVisibility") + .HasColumnType("integer"); + + b.Property("Port") + .HasColumnType("integer"); + + b.Property("ProcessId") + .HasColumnType("integer"); + + b.Property("RebootState") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("CompileJobId"); + + b.ToTable("ReattachInformations"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.RepositorySettings", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AccessToken") + .HasMaxLength(10000) + .HasColumnType("character varying(10000)"); + + b.Property("AccessUser") + .HasMaxLength(10000) + .HasColumnType("character varying(10000)"); + + b.Property("AutoUpdatesKeepTestMerges") + .IsRequired() + .HasColumnType("boolean"); + + b.Property("AutoUpdatesSynchronize") + .IsRequired() + .HasColumnType("boolean"); + + b.Property("CommitterEmail") + .IsRequired() + .HasMaxLength(10000) + .HasColumnType("character varying(10000)"); + + b.Property("CommitterName") + .IsRequired() + .HasMaxLength(10000) + .HasColumnType("character varying(10000)"); + + b.Property("CreateGitHubDeployments") + .IsRequired() + .HasColumnType("boolean"); + + b.Property("InstanceId") + .HasColumnType("bigint"); + + b.Property("PostTestMergeComment") + .IsRequired() + .HasColumnType("boolean"); + + b.Property("PushTestMergeCommits") + .IsRequired() + .HasColumnType("boolean"); + + b.Property("ShowTestMergeCommitters") + .IsRequired() + .HasColumnType("boolean"); + + b.Property("UpdateSubmodules") + .IsRequired() + .HasColumnType("boolean"); + + b.HasKey("Id"); + + b.HasIndex("InstanceId") + .IsUnique(); + + b.ToTable("RepositorySettings"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.RevInfoTestMerge", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("RevisionInformationId") + .HasColumnType("bigint"); + + b.Property("TestMergeId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("RevisionInformationId"); + + b.HasIndex("TestMergeId"); + + b.ToTable("RevInfoTestMerges"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.RevisionInformation", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CommitSha") + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)"); + + b.Property("InstanceId") + .HasColumnType("bigint"); + + b.Property("OriginCommitSha") + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)"); + + b.Property("Timestamp") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("InstanceId", "CommitSha") + .IsUnique(); + + b.ToTable("RevisionInformations"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.TestMerge", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Author") + .IsRequired() + .HasColumnType("text"); + + b.Property("BodyAtMerge") + .IsRequired() + .HasColumnType("text"); + + b.Property("Comment") + .HasMaxLength(10000) + .HasColumnType("character varying(10000)"); + + b.Property("MergedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("MergedById") + .HasColumnType("bigint"); + + b.Property("Number") + .HasColumnType("integer"); + + b.Property("PrimaryRevisionInformationId") + .IsRequired() + .HasColumnType("bigint"); + + b.Property("TargetCommitSha") + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)"); + + b.Property("TitleAtMerge") + .IsRequired() + .HasColumnType("text"); + + b.Property("Url") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("MergedById"); + + b.HasIndex("PrimaryRevisionInformationId") + .IsUnique(); + + b.ToTable("TestMerges"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CanonicalName") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("CreatedAt") + .IsRequired() + .HasColumnType("timestamp with time zone"); + + b.Property("CreatedById") + .HasColumnType("bigint"); + + b.Property("Enabled") + .IsRequired() + .HasColumnType("boolean"); + + b.Property("GroupId") + .HasColumnType("bigint"); + + b.Property("LastPasswordUpdate") + .HasColumnType("timestamp with time zone"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("PasswordHash") + .HasColumnType("text"); + + b.Property("SystemIdentifier") + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.HasKey("Id"); + + b.HasIndex("CanonicalName") + .IsUnique(); + + b.HasIndex("CreatedById"); + + b.HasIndex("GroupId"); + + b.HasIndex("SystemIdentifier") + .IsUnique(); + + b.ToTable("Users"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.UserGroup", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Name") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Groups"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.ChatBot", b => + { + b.HasOne("Tgstation.Server.Host.Models.Instance", "Instance") + .WithMany("ChatSettings") + .HasForeignKey("InstanceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Instance"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.ChatChannel", b => + { + b.HasOne("Tgstation.Server.Host.Models.ChatBot", "ChatSettings") + .WithMany("Channels") + .HasForeignKey("ChatSettingsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ChatSettings"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.CompileJob", b => + { + b.HasOne("Tgstation.Server.Host.Models.Job", "Job") + .WithOne() + .HasForeignKey("Tgstation.Server.Host.Models.CompileJob", "JobId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Tgstation.Server.Host.Models.RevisionInformation", "RevisionInformation") + .WithMany("CompileJobs") + .HasForeignKey("RevisionInformationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Job"); + + b.Navigation("RevisionInformation"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.DreamDaemonSettings", b => + { + b.HasOne("Tgstation.Server.Host.Models.Instance", "Instance") + .WithOne("DreamDaemonSettings") + .HasForeignKey("Tgstation.Server.Host.Models.DreamDaemonSettings", "InstanceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Instance"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.DreamMakerSettings", b => + { + b.HasOne("Tgstation.Server.Host.Models.Instance", "Instance") + .WithOne("DreamMakerSettings") + .HasForeignKey("Tgstation.Server.Host.Models.DreamMakerSettings", "InstanceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Instance"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.InstancePermissionSet", b => + { + b.HasOne("Tgstation.Server.Host.Models.Instance", "Instance") + .WithMany("InstancePermissionSets") + .HasForeignKey("InstanceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Tgstation.Server.Host.Models.PermissionSet", "PermissionSet") + .WithMany("InstancePermissionSets") + .HasForeignKey("PermissionSetId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Instance"); + + b.Navigation("PermissionSet"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.Job", b => + { + b.HasOne("Tgstation.Server.Host.Models.User", "CancelledBy") + .WithMany() + .HasForeignKey("CancelledById"); + + b.HasOne("Tgstation.Server.Host.Models.Instance", "Instance") + .WithMany("Jobs") + .HasForeignKey("InstanceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Tgstation.Server.Host.Models.User", "StartedBy") + .WithMany() + .HasForeignKey("StartedById") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CancelledBy"); + + b.Navigation("Instance"); + + b.Navigation("StartedBy"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.OAuthConnection", b => + { + b.HasOne("Tgstation.Server.Host.Models.User", "User") + .WithMany("OAuthConnections") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.PermissionSet", b => + { + b.HasOne("Tgstation.Server.Host.Models.UserGroup", "Group") + .WithOne("PermissionSet") + .HasForeignKey("Tgstation.Server.Host.Models.PermissionSet", "GroupId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("Tgstation.Server.Host.Models.User", "User") + .WithOne("PermissionSet") + .HasForeignKey("Tgstation.Server.Host.Models.PermissionSet", "UserId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("Group"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.ReattachInformation", b => + { + b.HasOne("Tgstation.Server.Host.Models.CompileJob", "CompileJob") + .WithMany() + .HasForeignKey("CompileJobId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CompileJob"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.RepositorySettings", b => + { + b.HasOne("Tgstation.Server.Host.Models.Instance", "Instance") + .WithOne("RepositorySettings") + .HasForeignKey("Tgstation.Server.Host.Models.RepositorySettings", "InstanceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Instance"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.RevInfoTestMerge", b => + { + b.HasOne("Tgstation.Server.Host.Models.RevisionInformation", "RevisionInformation") + .WithMany("ActiveTestMerges") + .HasForeignKey("RevisionInformationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Tgstation.Server.Host.Models.TestMerge", "TestMerge") + .WithMany("RevisonInformations") + .HasForeignKey("TestMergeId") + .OnDelete(DeleteBehavior.ClientNoAction) + .IsRequired(); + + b.Navigation("RevisionInformation"); + + b.Navigation("TestMerge"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.RevisionInformation", b => + { + b.HasOne("Tgstation.Server.Host.Models.Instance", "Instance") + .WithMany("RevisionInformations") + .HasForeignKey("InstanceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Instance"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.TestMerge", b => + { + b.HasOne("Tgstation.Server.Host.Models.User", "MergedBy") + .WithMany("TestMerges") + .HasForeignKey("MergedById") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("Tgstation.Server.Host.Models.RevisionInformation", "PrimaryRevisionInformation") + .WithOne("PrimaryTestMerge") + .HasForeignKey("Tgstation.Server.Host.Models.TestMerge", "PrimaryRevisionInformationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("MergedBy"); + + b.Navigation("PrimaryRevisionInformation"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.User", b => + { + b.HasOne("Tgstation.Server.Host.Models.User", "CreatedBy") + .WithMany("CreatedUsers") + .HasForeignKey("CreatedById"); + + b.HasOne("Tgstation.Server.Host.Models.UserGroup", "Group") + .WithMany("Users") + .HasForeignKey("GroupId"); + + b.Navigation("CreatedBy"); + + b.Navigation("Group"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.ChatBot", b => + { + b.Navigation("Channels"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.Instance", b => + { + b.Navigation("ChatSettings"); + + b.Navigation("DreamDaemonSettings"); + + b.Navigation("DreamMakerSettings"); + + b.Navigation("InstancePermissionSets"); + + b.Navigation("Jobs"); + + b.Navigation("RepositorySettings"); + + b.Navigation("RevisionInformations"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.PermissionSet", b => + { + b.Navigation("InstancePermissionSets"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.RevisionInformation", b => + { + b.Navigation("ActiveTestMerges"); + + b.Navigation("CompileJobs"); + + b.Navigation("PrimaryTestMerge"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.TestMerge", b => + { + b.Navigation("RevisonInformations"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.User", b => + { + b.Navigation("CreatedUsers"); + + b.Navigation("OAuthConnections"); + + b.Navigation("PermissionSet"); + + b.Navigation("TestMerges"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.UserGroup", b => + { + b.Navigation("PermissionSet") + .IsRequired(); + + b.Navigation("Users"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/Tgstation.Server.Host/Database/Migrations/20230331221032_PGAddDreamDaemonLogOutput.cs b/src/Tgstation.Server.Host/Database/Migrations/20230331221032_PGAddDreamDaemonLogOutput.cs new file mode 100644 index 0000000000..0998a70dcf --- /dev/null +++ b/src/Tgstation.Server.Host/Database/Migrations/20230331221032_PGAddDreamDaemonLogOutput.cs @@ -0,0 +1,39 @@ +using System; + +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Tgstation.Server.Host.Database.Migrations +{ + /// + /// Adds the DreamDaemon LogOutput column for PostgresSQL. + /// + public partial class PGAddDreamDaemonLogOutput : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + if (migrationBuilder == null) + throw new ArgumentNullException(nameof(migrationBuilder)); + + migrationBuilder.AddColumn( + name: "LogOutput", + table: "DreamDaemonSettings", + type: "boolean", + nullable: false, + defaultValue: false); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + if (migrationBuilder == null) + throw new ArgumentNullException(nameof(migrationBuilder)); + + migrationBuilder.DropColumn( + name: "LogOutput", + table: "DreamDaemonSettings"); + } + } +} diff --git a/src/Tgstation.Server.Host/Database/Migrations/20230331221156_SLAddDreamDaemonLogOutput.Designer.cs b/src/Tgstation.Server.Host/Database/Migrations/20230331221156_SLAddDreamDaemonLogOutput.Designer.cs new file mode 100644 index 0000000000..1e7c30621f --- /dev/null +++ b/src/Tgstation.Server.Host/Database/Migrations/20230331221156_SLAddDreamDaemonLogOutput.Designer.cs @@ -0,0 +1,1019 @@ +// +using System; + +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Tgstation.Server.Host.Database.Migrations +{ + [DbContext(typeof(SqliteDatabaseContext))] + [Migration("20230331221156_SLAddDreamDaemonLogOutput")] + partial class SLAddDreamDaemonLogOutput + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "6.0.15"); + + modelBuilder.Entity("Tgstation.Server.Host.Models.ChatBot", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChannelLimit") + .IsRequired() + .HasColumnType("INTEGER"); + + b.Property("ConnectionString") + .IsRequired() + .HasMaxLength(10000) + .HasColumnType("TEXT"); + + b.Property("Enabled") + .HasColumnType("INTEGER"); + + b.Property("InstanceId") + .HasColumnType("INTEGER"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("TEXT"); + + b.Property("Provider") + .HasColumnType("INTEGER"); + + b.Property("ReconnectionInterval") + .IsRequired() + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("InstanceId", "Name") + .IsUnique(); + + b.ToTable("ChatBots"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.ChatChannel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChatSettingsId") + .HasColumnType("INTEGER"); + + b.Property("DiscordChannelId") + .HasColumnType("INTEGER"); + + b.Property("IrcChannel") + .HasMaxLength(100) + .HasColumnType("TEXT"); + + b.Property("IsAdminChannel") + .IsRequired() + .HasColumnType("INTEGER"); + + b.Property("IsUpdatesChannel") + .IsRequired() + .HasColumnType("INTEGER"); + + b.Property("IsWatchdogChannel") + .IsRequired() + .HasColumnType("INTEGER"); + + b.Property("Tag") + .HasMaxLength(10000) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("ChatSettingsId", "DiscordChannelId") + .IsUnique(); + + b.HasIndex("ChatSettingsId", "IrcChannel") + .IsUnique(); + + b.ToTable("ChatChannels"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.CompileJob", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ByondVersion") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("DMApiMajorVersion") + .HasColumnType("INTEGER"); + + b.Property("DMApiMinorVersion") + .HasColumnType("INTEGER"); + + b.Property("DMApiPatchVersion") + .HasColumnType("INTEGER"); + + b.Property("DirectoryName") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("DmeName") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("GitHubDeploymentId") + .HasColumnType("INTEGER"); + + b.Property("GitHubRepoId") + .HasColumnType("INTEGER"); + + b.Property("JobId") + .HasColumnType("INTEGER"); + + b.Property("MinimumSecurityLevel") + .HasColumnType("INTEGER"); + + b.Property("Output") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("RepositoryOrigin") + .HasColumnType("TEXT"); + + b.Property("RevisionInformationId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("DirectoryName"); + + b.HasIndex("JobId") + .IsUnique(); + + b.HasIndex("RevisionInformationId"); + + b.ToTable("CompileJobs"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.DreamDaemonSettings", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AdditionalParameters") + .IsRequired() + .HasMaxLength(10000) + .HasColumnType("TEXT"); + + b.Property("AllowWebClient") + .IsRequired() + .HasColumnType("INTEGER"); + + b.Property("AutoStart") + .IsRequired() + .HasColumnType("INTEGER"); + + b.Property("DumpOnHeartbeatRestart") + .IsRequired() + .HasColumnType("INTEGER"); + + b.Property("HeartbeatSeconds") + .IsRequired() + .HasColumnType("INTEGER"); + + b.Property("InstanceId") + .HasColumnType("INTEGER"); + + b.Property("LogOutput") + .IsRequired() + .HasColumnType("INTEGER"); + + b.Property("Port") + .IsRequired() + .HasColumnType("INTEGER"); + + b.Property("SecurityLevel") + .HasColumnType("INTEGER"); + + b.Property("StartProfiler") + .IsRequired() + .HasColumnType("INTEGER"); + + b.Property("StartupTimeout") + .IsRequired() + .HasColumnType("INTEGER"); + + b.Property("TopicRequestTimeout") + .IsRequired() + .HasColumnType("INTEGER"); + + b.Property("Visibility") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("InstanceId") + .IsUnique(); + + b.ToTable("DreamDaemonSettings"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.DreamMakerSettings", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ApiValidationPort") + .IsRequired() + .HasColumnType("INTEGER"); + + b.Property("ApiValidationSecurityLevel") + .HasColumnType("INTEGER"); + + b.Property("InstanceId") + .HasColumnType("INTEGER"); + + b.Property("ProjectName") + .HasMaxLength(10000) + .HasColumnType("TEXT"); + + b.Property("RequireDMApiValidation") + .IsRequired() + .HasColumnType("INTEGER"); + + b.Property("Timeout") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("InstanceId") + .IsUnique(); + + b.ToTable("DreamMakerSettings"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.Instance", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AutoUpdateInterval") + .IsRequired() + .HasColumnType("INTEGER"); + + b.Property("ChatBotLimit") + .IsRequired() + .HasColumnType("INTEGER"); + + b.Property("ConfigurationType") + .HasColumnType("INTEGER"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("TEXT"); + + b.Property("Online") + .IsRequired() + .HasColumnType("INTEGER"); + + b.Property("Path") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("SwarmIdentifer") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("Path", "SwarmIdentifer") + .IsUnique(); + + b.ToTable("Instances"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.InstancePermissionSet", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ByondRights") + .HasColumnType("INTEGER"); + + b.Property("ChatBotRights") + .HasColumnType("INTEGER"); + + b.Property("ConfigurationRights") + .HasColumnType("INTEGER"); + + b.Property("DreamDaemonRights") + .HasColumnType("INTEGER"); + + b.Property("DreamMakerRights") + .HasColumnType("INTEGER"); + + b.Property("InstanceId") + .HasColumnType("INTEGER"); + + b.Property("InstancePermissionSetRights") + .HasColumnType("INTEGER"); + + b.Property("PermissionSetId") + .HasColumnType("INTEGER"); + + b.Property("RepositoryRights") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("InstanceId"); + + b.HasIndex("PermissionSetId", "InstanceId") + .IsUnique(); + + b.ToTable("InstancePermissionSets"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.Job", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CancelRight") + .HasColumnType("INTEGER"); + + b.Property("CancelRightsType") + .HasColumnType("INTEGER"); + + b.Property("Cancelled") + .IsRequired() + .HasColumnType("INTEGER"); + + b.Property("CancelledById") + .HasColumnType("INTEGER"); + + b.Property("Description") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("ErrorCode") + .HasColumnType("INTEGER"); + + b.Property("ExceptionDetails") + .HasColumnType("TEXT"); + + b.Property("InstanceId") + .HasColumnType("INTEGER"); + + b.Property("StartedAt") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("StartedById") + .HasColumnType("INTEGER"); + + b.Property("StoppedAt") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("CancelledById"); + + b.HasIndex("InstanceId"); + + b.HasIndex("StartedById"); + + b.ToTable("Jobs"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.OAuthConnection", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ExternalUserId") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("TEXT"); + + b.Property("Provider") + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.HasIndex("Provider", "ExternalUserId") + .IsUnique(); + + b.ToTable("OAuthConnections"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.PermissionSet", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AdministrationRights") + .HasColumnType("INTEGER"); + + b.Property("GroupId") + .HasColumnType("INTEGER"); + + b.Property("InstanceManagerRights") + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("GroupId") + .IsUnique(); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("PermissionSets"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.ReattachInformation", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AccessIdentifier") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("CompileJobId") + .HasColumnType("INTEGER"); + + b.Property("LaunchSecurityLevel") + .HasColumnType("INTEGER"); + + b.Property("LaunchVisibility") + .HasColumnType("INTEGER"); + + b.Property("Port") + .HasColumnType("INTEGER"); + + b.Property("ProcessId") + .HasColumnType("INTEGER"); + + b.Property("RebootState") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("CompileJobId"); + + b.ToTable("ReattachInformations"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.RepositorySettings", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AccessToken") + .HasMaxLength(10000) + .HasColumnType("TEXT"); + + b.Property("AccessUser") + .HasMaxLength(10000) + .HasColumnType("TEXT"); + + b.Property("AutoUpdatesKeepTestMerges") + .IsRequired() + .HasColumnType("INTEGER"); + + b.Property("AutoUpdatesSynchronize") + .IsRequired() + .HasColumnType("INTEGER"); + + b.Property("CommitterEmail") + .IsRequired() + .HasMaxLength(10000) + .HasColumnType("TEXT"); + + b.Property("CommitterName") + .IsRequired() + .HasMaxLength(10000) + .HasColumnType("TEXT"); + + b.Property("CreateGitHubDeployments") + .IsRequired() + .HasColumnType("INTEGER"); + + b.Property("InstanceId") + .HasColumnType("INTEGER"); + + b.Property("PostTestMergeComment") + .IsRequired() + .HasColumnType("INTEGER"); + + b.Property("PushTestMergeCommits") + .IsRequired() + .HasColumnType("INTEGER"); + + b.Property("ShowTestMergeCommitters") + .IsRequired() + .HasColumnType("INTEGER"); + + b.Property("UpdateSubmodules") + .IsRequired() + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("InstanceId") + .IsUnique(); + + b.ToTable("RepositorySettings"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.RevInfoTestMerge", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("RevisionInformationId") + .HasColumnType("INTEGER"); + + b.Property("TestMergeId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("RevisionInformationId"); + + b.HasIndex("TestMergeId"); + + b.ToTable("RevInfoTestMerges"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.RevisionInformation", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CommitSha") + .IsRequired() + .HasMaxLength(40) + .HasColumnType("TEXT"); + + b.Property("InstanceId") + .HasColumnType("INTEGER"); + + b.Property("OriginCommitSha") + .IsRequired() + .HasMaxLength(40) + .HasColumnType("TEXT"); + + b.Property("Timestamp") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("InstanceId", "CommitSha") + .IsUnique(); + + b.ToTable("RevisionInformations"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.TestMerge", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Author") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("BodyAtMerge") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Comment") + .HasMaxLength(10000) + .HasColumnType("TEXT"); + + b.Property("MergedAt") + .HasColumnType("TEXT"); + + b.Property("MergedById") + .HasColumnType("INTEGER"); + + b.Property("Number") + .HasColumnType("INTEGER"); + + b.Property("PrimaryRevisionInformationId") + .IsRequired() + .HasColumnType("INTEGER"); + + b.Property("TargetCommitSha") + .IsRequired() + .HasMaxLength(40) + .HasColumnType("TEXT"); + + b.Property("TitleAtMerge") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Url") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("MergedById"); + + b.HasIndex("PrimaryRevisionInformationId") + .IsUnique(); + + b.ToTable("TestMerges"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CanonicalName") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("TEXT"); + + b.Property("CreatedAt") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("CreatedById") + .HasColumnType("INTEGER"); + + b.Property("Enabled") + .IsRequired() + .HasColumnType("INTEGER"); + + b.Property("GroupId") + .HasColumnType("INTEGER"); + + b.Property("LastPasswordUpdate") + .HasColumnType("TEXT"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("TEXT"); + + b.Property("PasswordHash") + .HasColumnType("TEXT"); + + b.Property("SystemIdentifier") + .HasMaxLength(100) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("CanonicalName") + .IsUnique(); + + b.HasIndex("CreatedById"); + + b.HasIndex("GroupId"); + + b.HasIndex("SystemIdentifier") + .IsUnique(); + + b.ToTable("Users"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.UserGroup", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Groups"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.ChatBot", b => + { + b.HasOne("Tgstation.Server.Host.Models.Instance", "Instance") + .WithMany("ChatSettings") + .HasForeignKey("InstanceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Instance"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.ChatChannel", b => + { + b.HasOne("Tgstation.Server.Host.Models.ChatBot", "ChatSettings") + .WithMany("Channels") + .HasForeignKey("ChatSettingsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ChatSettings"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.CompileJob", b => + { + b.HasOne("Tgstation.Server.Host.Models.Job", "Job") + .WithOne() + .HasForeignKey("Tgstation.Server.Host.Models.CompileJob", "JobId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Tgstation.Server.Host.Models.RevisionInformation", "RevisionInformation") + .WithMany("CompileJobs") + .HasForeignKey("RevisionInformationId") + .OnDelete(DeleteBehavior.ClientNoAction) + .IsRequired(); + + b.Navigation("Job"); + + b.Navigation("RevisionInformation"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.DreamDaemonSettings", b => + { + b.HasOne("Tgstation.Server.Host.Models.Instance", "Instance") + .WithOne("DreamDaemonSettings") + .HasForeignKey("Tgstation.Server.Host.Models.DreamDaemonSettings", "InstanceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Instance"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.DreamMakerSettings", b => + { + b.HasOne("Tgstation.Server.Host.Models.Instance", "Instance") + .WithOne("DreamMakerSettings") + .HasForeignKey("Tgstation.Server.Host.Models.DreamMakerSettings", "InstanceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Instance"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.InstancePermissionSet", b => + { + b.HasOne("Tgstation.Server.Host.Models.Instance", "Instance") + .WithMany("InstancePermissionSets") + .HasForeignKey("InstanceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Tgstation.Server.Host.Models.PermissionSet", "PermissionSet") + .WithMany("InstancePermissionSets") + .HasForeignKey("PermissionSetId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Instance"); + + b.Navigation("PermissionSet"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.Job", b => + { + b.HasOne("Tgstation.Server.Host.Models.User", "CancelledBy") + .WithMany() + .HasForeignKey("CancelledById"); + + b.HasOne("Tgstation.Server.Host.Models.Instance", "Instance") + .WithMany("Jobs") + .HasForeignKey("InstanceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Tgstation.Server.Host.Models.User", "StartedBy") + .WithMany() + .HasForeignKey("StartedById") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CancelledBy"); + + b.Navigation("Instance"); + + b.Navigation("StartedBy"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.OAuthConnection", b => + { + b.HasOne("Tgstation.Server.Host.Models.User", "User") + .WithMany("OAuthConnections") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.PermissionSet", b => + { + b.HasOne("Tgstation.Server.Host.Models.UserGroup", "Group") + .WithOne("PermissionSet") + .HasForeignKey("Tgstation.Server.Host.Models.PermissionSet", "GroupId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("Tgstation.Server.Host.Models.User", "User") + .WithOne("PermissionSet") + .HasForeignKey("Tgstation.Server.Host.Models.PermissionSet", "UserId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("Group"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.ReattachInformation", b => + { + b.HasOne("Tgstation.Server.Host.Models.CompileJob", "CompileJob") + .WithMany() + .HasForeignKey("CompileJobId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CompileJob"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.RepositorySettings", b => + { + b.HasOne("Tgstation.Server.Host.Models.Instance", "Instance") + .WithOne("RepositorySettings") + .HasForeignKey("Tgstation.Server.Host.Models.RepositorySettings", "InstanceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Instance"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.RevInfoTestMerge", b => + { + b.HasOne("Tgstation.Server.Host.Models.RevisionInformation", "RevisionInformation") + .WithMany("ActiveTestMerges") + .HasForeignKey("RevisionInformationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Tgstation.Server.Host.Models.TestMerge", "TestMerge") + .WithMany("RevisonInformations") + .HasForeignKey("TestMergeId") + .OnDelete(DeleteBehavior.ClientNoAction) + .IsRequired(); + + b.Navigation("RevisionInformation"); + + b.Navigation("TestMerge"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.RevisionInformation", b => + { + b.HasOne("Tgstation.Server.Host.Models.Instance", "Instance") + .WithMany("RevisionInformations") + .HasForeignKey("InstanceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Instance"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.TestMerge", b => + { + b.HasOne("Tgstation.Server.Host.Models.User", "MergedBy") + .WithMany("TestMerges") + .HasForeignKey("MergedById") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("Tgstation.Server.Host.Models.RevisionInformation", "PrimaryRevisionInformation") + .WithOne("PrimaryTestMerge") + .HasForeignKey("Tgstation.Server.Host.Models.TestMerge", "PrimaryRevisionInformationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("MergedBy"); + + b.Navigation("PrimaryRevisionInformation"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.User", b => + { + b.HasOne("Tgstation.Server.Host.Models.User", "CreatedBy") + .WithMany("CreatedUsers") + .HasForeignKey("CreatedById"); + + b.HasOne("Tgstation.Server.Host.Models.UserGroup", "Group") + .WithMany("Users") + .HasForeignKey("GroupId"); + + b.Navigation("CreatedBy"); + + b.Navigation("Group"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.ChatBot", b => + { + b.Navigation("Channels"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.Instance", b => + { + b.Navigation("ChatSettings"); + + b.Navigation("DreamDaemonSettings"); + + b.Navigation("DreamMakerSettings"); + + b.Navigation("InstancePermissionSets"); + + b.Navigation("Jobs"); + + b.Navigation("RepositorySettings"); + + b.Navigation("RevisionInformations"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.PermissionSet", b => + { + b.Navigation("InstancePermissionSets"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.RevisionInformation", b => + { + b.Navigation("ActiveTestMerges"); + + b.Navigation("CompileJobs"); + + b.Navigation("PrimaryTestMerge"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.TestMerge", b => + { + b.Navigation("RevisonInformations"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.User", b => + { + b.Navigation("CreatedUsers"); + + b.Navigation("OAuthConnections"); + + b.Navigation("PermissionSet"); + + b.Navigation("TestMerges"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.UserGroup", b => + { + b.Navigation("PermissionSet") + .IsRequired(); + + b.Navigation("Users"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/Tgstation.Server.Host/Database/Migrations/20230331221156_SLAddDreamDaemonLogOutput.cs b/src/Tgstation.Server.Host/Database/Migrations/20230331221156_SLAddDreamDaemonLogOutput.cs new file mode 100644 index 0000000000..53b0c787aa --- /dev/null +++ b/src/Tgstation.Server.Host/Database/Migrations/20230331221156_SLAddDreamDaemonLogOutput.cs @@ -0,0 +1,39 @@ +using System; + +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Tgstation.Server.Host.Database.Migrations +{ + /// + /// Adds the DreamDaemon LogOutput column for SQLite. + /// + public partial class SLAddDreamDaemonLogOutput : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + if (migrationBuilder == null) + throw new ArgumentNullException(nameof(migrationBuilder)); + + migrationBuilder.AddColumn( + name: "LogOutput", + table: "DreamDaemonSettings", + type: "INTEGER", + nullable: false, + defaultValue: false); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + if (migrationBuilder == null) + throw new ArgumentNullException(nameof(migrationBuilder)); + + migrationBuilder.DropColumn( + name: "LogOutput", + table: "DreamDaemonSettings"); + } + } +} diff --git a/src/Tgstation.Server.Host/Database/Migrations/MySqlDatabaseContextModelSnapshot.cs b/src/Tgstation.Server.Host/Database/Migrations/MySqlDatabaseContextModelSnapshot.cs index 28f45c1913..910fe08225 100644 --- a/src/Tgstation.Server.Host/Database/Migrations/MySqlDatabaseContextModelSnapshot.cs +++ b/src/Tgstation.Server.Host/Database/Migrations/MySqlDatabaseContextModelSnapshot.cs @@ -4,16 +4,19 @@ using System; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; +#nullable disable + namespace Tgstation.Server.Host.Database.Migrations { [DbContext(typeof(MySqlDatabaseContext))] partial class MySqlDatabaseContextModelSnapshot : ModelSnapshot { + /// protected override void BuildModel(ModelBuilder modelBuilder) { #pragma warning disable 612, 618 modelBuilder - .HasAnnotation("ProductVersion", "3.1.20") + .HasAnnotation("ProductVersion", "6.0.15") .HasAnnotation("Relational:MaxIdentifierLength", 64); modelBuilder.Entity("Tgstation.Server.Host.Models.ChatBot", b => @@ -28,8 +31,8 @@ namespace Tgstation.Server.Host.Database.Migrations b.Property("ConnectionString") .IsRequired() - .HasColumnType("longtext CHARACTER SET utf8mb4") - .HasMaxLength(10000); + .HasMaxLength(10000) + .HasColumnType("varchar(10000)"); b.Property("Enabled") .HasColumnType("tinyint(1)"); @@ -39,8 +42,8 @@ namespace Tgstation.Server.Host.Database.Migrations b.Property("Name") .IsRequired() - .HasColumnType("varchar(100) CHARACTER SET utf8mb4") - .HasMaxLength(100); + .HasMaxLength(100) + .HasColumnType("varchar(100)"); b.Property("Provider") .HasColumnType("int"); @@ -70,8 +73,8 @@ namespace Tgstation.Server.Host.Database.Migrations .HasColumnType("bigint unsigned"); b.Property("IrcChannel") - .HasColumnType("varchar(100) CHARACTER SET utf8mb4") - .HasMaxLength(100); + .HasMaxLength(100) + .HasColumnType("varchar(100)"); b.Property("IsAdminChannel") .IsRequired() @@ -86,8 +89,8 @@ namespace Tgstation.Server.Host.Database.Migrations .HasColumnType("tinyint(1)"); b.Property("Tag") - .HasColumnType("longtext CHARACTER SET utf8mb4") - .HasMaxLength(10000); + .HasMaxLength(10000) + .HasColumnType("varchar(10000)"); b.HasKey("Id"); @@ -108,7 +111,7 @@ namespace Tgstation.Server.Host.Database.Migrations b.Property("ByondVersion") .IsRequired() - .HasColumnType("longtext CHARACTER SET utf8mb4"); + .HasColumnType("longtext"); b.Property("DMApiMajorVersion") .HasColumnType("int"); @@ -125,7 +128,7 @@ namespace Tgstation.Server.Host.Database.Migrations b.Property("DmeName") .IsRequired() - .HasColumnType("longtext CHARACTER SET utf8mb4"); + .HasColumnType("longtext"); b.Property("GitHubDeploymentId") .HasColumnType("int"); @@ -141,10 +144,10 @@ namespace Tgstation.Server.Host.Database.Migrations b.Property("Output") .IsRequired() - .HasColumnType("longtext CHARACTER SET utf8mb4"); + .HasColumnType("longtext"); b.Property("RepositoryOrigin") - .HasColumnType("longtext CHARACTER SET utf8mb4"); + .HasColumnType("longtext"); b.Property("RevisionInformationId") .HasColumnType("bigint"); @@ -169,8 +172,8 @@ namespace Tgstation.Server.Host.Database.Migrations b.Property("AdditionalParameters") .IsRequired() - .HasColumnType("longtext CHARACTER SET utf8mb4") - .HasMaxLength(10000); + .HasMaxLength(10000) + .HasColumnType("varchar(10000)"); b.Property("AllowWebClient") .IsRequired() @@ -191,6 +194,10 @@ namespace Tgstation.Server.Host.Database.Migrations b.Property("InstanceId") .HasColumnType("bigint"); + b.Property("LogOutput") + .IsRequired() + .HasColumnType("tinyint(1)"); + b.Property("Port") .IsRequired() .HasColumnType("smallint unsigned"); @@ -238,8 +245,8 @@ namespace Tgstation.Server.Host.Database.Migrations .HasColumnType("bigint"); b.Property("ProjectName") - .HasColumnType("longtext CHARACTER SET utf8mb4") - .HasMaxLength(10000); + .HasMaxLength(10000) + .HasColumnType("varchar(10000)"); b.Property("RequireDMApiValidation") .IsRequired() @@ -276,8 +283,8 @@ namespace Tgstation.Server.Host.Database.Migrations b.Property("Name") .IsRequired() - .HasColumnType("varchar(100) CHARACTER SET utf8mb4") - .HasMaxLength(100); + .HasMaxLength(100) + .HasColumnType("varchar(100)"); b.Property("Online") .IsRequired() @@ -285,10 +292,10 @@ namespace Tgstation.Server.Host.Database.Migrations b.Property("Path") .IsRequired() - .HasColumnType("varchar(255) CHARACTER SET utf8mb4"); + .HasColumnType("varchar(255)"); b.Property("SwarmIdentifer") - .HasColumnType("varchar(255) CHARACTER SET utf8mb4"); + .HasColumnType("varchar(255)"); b.HasKey("Id"); @@ -362,13 +369,13 @@ namespace Tgstation.Server.Host.Database.Migrations b.Property("Description") .IsRequired() - .HasColumnType("longtext CHARACTER SET utf8mb4"); + .HasColumnType("longtext"); b.Property("ErrorCode") .HasColumnType("int unsigned"); b.Property("ExceptionDetails") - .HasColumnType("longtext CHARACTER SET utf8mb4"); + .HasColumnType("longtext"); b.Property("InstanceId") .HasColumnType("bigint"); @@ -402,8 +409,8 @@ namespace Tgstation.Server.Host.Database.Migrations b.Property("ExternalUserId") .IsRequired() - .HasColumnType("varchar(100) CHARACTER SET utf8mb4") - .HasMaxLength(100); + .HasMaxLength(100) + .HasColumnType("varchar(100)"); b.Property("Provider") .HasColumnType("int"); @@ -458,7 +465,7 @@ namespace Tgstation.Server.Host.Database.Migrations b.Property("AccessIdentifier") .IsRequired() - .HasColumnType("longtext CHARACTER SET utf8mb4"); + .HasColumnType("longtext"); b.Property("CompileJobId") .HasColumnType("bigint"); @@ -492,12 +499,12 @@ namespace Tgstation.Server.Host.Database.Migrations .HasColumnType("bigint"); b.Property("AccessToken") - .HasColumnType("longtext CHARACTER SET utf8mb4") - .HasMaxLength(10000); + .HasMaxLength(10000) + .HasColumnType("varchar(10000)"); b.Property("AccessUser") - .HasColumnType("longtext CHARACTER SET utf8mb4") - .HasMaxLength(10000); + .HasMaxLength(10000) + .HasColumnType("varchar(10000)"); b.Property("AutoUpdatesKeepTestMerges") .IsRequired() @@ -509,13 +516,13 @@ namespace Tgstation.Server.Host.Database.Migrations b.Property("CommitterEmail") .IsRequired() - .HasColumnType("longtext CHARACTER SET utf8mb4") - .HasMaxLength(10000); + .HasMaxLength(10000) + .HasColumnType("varchar(10000)"); b.Property("CommitterName") .IsRequired() - .HasColumnType("longtext CHARACTER SET utf8mb4") - .HasMaxLength(10000); + .HasMaxLength(10000) + .HasColumnType("varchar(10000)"); b.Property("CreateGitHubDeployments") .IsRequired() @@ -577,16 +584,16 @@ namespace Tgstation.Server.Host.Database.Migrations b.Property("CommitSha") .IsRequired() - .HasColumnType("varchar(40) CHARACTER SET utf8mb4") - .HasMaxLength(40); + .HasMaxLength(40) + .HasColumnType("varchar(40)"); b.Property("InstanceId") .HasColumnType("bigint"); b.Property("OriginCommitSha") .IsRequired() - .HasColumnType("varchar(40) CHARACTER SET utf8mb4") - .HasMaxLength(40); + .HasMaxLength(40) + .HasColumnType("varchar(40)"); b.Property("Timestamp") .HasColumnType("datetime(6)"); @@ -607,15 +614,15 @@ namespace Tgstation.Server.Host.Database.Migrations b.Property("Author") .IsRequired() - .HasColumnType("longtext CHARACTER SET utf8mb4"); + .HasColumnType("longtext"); b.Property("BodyAtMerge") .IsRequired() - .HasColumnType("longtext CHARACTER SET utf8mb4"); + .HasColumnType("longtext"); b.Property("Comment") - .HasColumnType("longtext CHARACTER SET utf8mb4") - .HasMaxLength(10000); + .HasMaxLength(10000) + .HasColumnType("varchar(10000)"); b.Property("MergedAt") .HasColumnType("datetime(6)"); @@ -632,16 +639,16 @@ namespace Tgstation.Server.Host.Database.Migrations b.Property("TargetCommitSha") .IsRequired() - .HasColumnType("varchar(40) CHARACTER SET utf8mb4") - .HasMaxLength(40); + .HasMaxLength(40) + .HasColumnType("varchar(40)"); b.Property("TitleAtMerge") .IsRequired() - .HasColumnType("longtext CHARACTER SET utf8mb4"); + .HasColumnType("longtext"); b.Property("Url") .IsRequired() - .HasColumnType("longtext CHARACTER SET utf8mb4"); + .HasColumnType("longtext"); b.HasKey("Id"); @@ -661,8 +668,8 @@ namespace Tgstation.Server.Host.Database.Migrations b.Property("CanonicalName") .IsRequired() - .HasColumnType("varchar(100) CHARACTER SET utf8mb4") - .HasMaxLength(100); + .HasMaxLength(100) + .HasColumnType("varchar(100)"); b.Property("CreatedAt") .IsRequired() @@ -683,15 +690,15 @@ namespace Tgstation.Server.Host.Database.Migrations b.Property("Name") .IsRequired() - .HasColumnType("varchar(100) CHARACTER SET utf8mb4") - .HasMaxLength(100); + .HasMaxLength(100) + .HasColumnType("varchar(100)"); b.Property("PasswordHash") - .HasColumnType("longtext CHARACTER SET utf8mb4"); + .HasColumnType("longtext"); b.Property("SystemIdentifier") - .HasColumnType("varchar(100) CHARACTER SET utf8mb4") - .HasMaxLength(100); + .HasMaxLength(100) + .HasColumnType("varchar(100)"); b.HasKey("Id"); @@ -716,8 +723,8 @@ namespace Tgstation.Server.Host.Database.Migrations b.Property("Name") .IsRequired() - .HasColumnType("varchar(100) CHARACTER SET utf8mb4") - .HasMaxLength(100); + .HasMaxLength(100) + .HasColumnType("varchar(100)"); b.HasKey("Id"); @@ -734,6 +741,8 @@ namespace Tgstation.Server.Host.Database.Migrations .HasForeignKey("InstanceId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); + + b.Navigation("Instance"); }); modelBuilder.Entity("Tgstation.Server.Host.Models.ChatChannel", b => @@ -743,6 +752,8 @@ namespace Tgstation.Server.Host.Database.Migrations .HasForeignKey("ChatSettingsId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); + + b.Navigation("ChatSettings"); }); modelBuilder.Entity("Tgstation.Server.Host.Models.CompileJob", b => @@ -758,6 +769,10 @@ namespace Tgstation.Server.Host.Database.Migrations .HasForeignKey("RevisionInformationId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); + + b.Navigation("Job"); + + b.Navigation("RevisionInformation"); }); modelBuilder.Entity("Tgstation.Server.Host.Models.DreamDaemonSettings", b => @@ -767,6 +782,8 @@ namespace Tgstation.Server.Host.Database.Migrations .HasForeignKey("Tgstation.Server.Host.Models.DreamDaemonSettings", "InstanceId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); + + b.Navigation("Instance"); }); modelBuilder.Entity("Tgstation.Server.Host.Models.DreamMakerSettings", b => @@ -776,6 +793,8 @@ namespace Tgstation.Server.Host.Database.Migrations .HasForeignKey("Tgstation.Server.Host.Models.DreamMakerSettings", "InstanceId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); + + b.Navigation("Instance"); }); modelBuilder.Entity("Tgstation.Server.Host.Models.InstancePermissionSet", b => @@ -791,6 +810,10 @@ namespace Tgstation.Server.Host.Database.Migrations .HasForeignKey("PermissionSetId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); + + b.Navigation("Instance"); + + b.Navigation("PermissionSet"); }); modelBuilder.Entity("Tgstation.Server.Host.Models.Job", b => @@ -810,6 +833,12 @@ namespace Tgstation.Server.Host.Database.Migrations .HasForeignKey("StartedById") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); + + b.Navigation("CancelledBy"); + + b.Navigation("Instance"); + + b.Navigation("StartedBy"); }); modelBuilder.Entity("Tgstation.Server.Host.Models.OAuthConnection", b => @@ -818,6 +847,8 @@ namespace Tgstation.Server.Host.Database.Migrations .WithMany("OAuthConnections") .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("User"); }); modelBuilder.Entity("Tgstation.Server.Host.Models.PermissionSet", b => @@ -831,6 +862,10 @@ namespace Tgstation.Server.Host.Database.Migrations .WithOne("PermissionSet") .HasForeignKey("Tgstation.Server.Host.Models.PermissionSet", "UserId") .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("Group"); + + b.Navigation("User"); }); modelBuilder.Entity("Tgstation.Server.Host.Models.ReattachInformation", b => @@ -840,6 +875,8 @@ namespace Tgstation.Server.Host.Database.Migrations .HasForeignKey("CompileJobId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); + + b.Navigation("CompileJob"); }); modelBuilder.Entity("Tgstation.Server.Host.Models.RepositorySettings", b => @@ -849,6 +886,8 @@ namespace Tgstation.Server.Host.Database.Migrations .HasForeignKey("Tgstation.Server.Host.Models.RepositorySettings", "InstanceId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); + + b.Navigation("Instance"); }); modelBuilder.Entity("Tgstation.Server.Host.Models.RevInfoTestMerge", b => @@ -864,6 +903,10 @@ namespace Tgstation.Server.Host.Database.Migrations .HasForeignKey("TestMergeId") .OnDelete(DeleteBehavior.ClientNoAction) .IsRequired(); + + b.Navigation("RevisionInformation"); + + b.Navigation("TestMerge"); }); modelBuilder.Entity("Tgstation.Server.Host.Models.RevisionInformation", b => @@ -873,6 +916,8 @@ namespace Tgstation.Server.Host.Database.Migrations .HasForeignKey("InstanceId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); + + b.Navigation("Instance"); }); modelBuilder.Entity("Tgstation.Server.Host.Models.TestMerge", b => @@ -888,6 +933,10 @@ namespace Tgstation.Server.Host.Database.Migrations .HasForeignKey("Tgstation.Server.Host.Models.TestMerge", "PrimaryRevisionInformationId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); + + b.Navigation("MergedBy"); + + b.Navigation("PrimaryRevisionInformation"); }); modelBuilder.Entity("Tgstation.Server.Host.Models.User", b => @@ -899,6 +948,70 @@ namespace Tgstation.Server.Host.Database.Migrations b.HasOne("Tgstation.Server.Host.Models.UserGroup", "Group") .WithMany("Users") .HasForeignKey("GroupId"); + + b.Navigation("CreatedBy"); + + b.Navigation("Group"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.ChatBot", b => + { + b.Navigation("Channels"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.Instance", b => + { + b.Navigation("ChatSettings"); + + b.Navigation("DreamDaemonSettings"); + + b.Navigation("DreamMakerSettings"); + + b.Navigation("InstancePermissionSets"); + + b.Navigation("Jobs"); + + b.Navigation("RepositorySettings"); + + b.Navigation("RevisionInformations"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.PermissionSet", b => + { + b.Navigation("InstancePermissionSets"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.RevisionInformation", b => + { + b.Navigation("ActiveTestMerges"); + + b.Navigation("CompileJobs"); + + b.Navigation("PrimaryTestMerge"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.TestMerge", b => + { + b.Navigation("RevisonInformations"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.User", b => + { + b.Navigation("CreatedUsers"); + + b.Navigation("OAuthConnections"); + + b.Navigation("PermissionSet"); + + b.Navigation("TestMerges"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.UserGroup", b => + { + b.Navigation("PermissionSet") + .IsRequired(); + + b.Navigation("Users"); }); #pragma warning restore 612, 618 } diff --git a/src/Tgstation.Server.Host/Database/Migrations/PostgresSqlDatabaseContextModelSnapshot.cs b/src/Tgstation.Server.Host/Database/Migrations/PostgresSqlDatabaseContextModelSnapshot.cs index 7de916fe92..5d1e2d4387 100644 --- a/src/Tgstation.Server.Host/Database/Migrations/PostgresSqlDatabaseContextModelSnapshot.cs +++ b/src/Tgstation.Server.Host/Database/Migrations/PostgresSqlDatabaseContextModelSnapshot.cs @@ -3,35 +3,39 @@ using System; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; -using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable namespace Tgstation.Server.Host.Database.Migrations { [DbContext(typeof(PostgresSqlDatabaseContext))] partial class PostgresSqlDatabaseContextModelSnapshot : ModelSnapshot { + /// protected override void BuildModel(ModelBuilder modelBuilder) { #pragma warning disable 612, 618 modelBuilder - .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn) - .HasAnnotation("ProductVersion", "3.1.20") + .HasAnnotation("ProductVersion", "6.0.15") .HasAnnotation("Relational:MaxIdentifierLength", 63); + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + modelBuilder.Entity("Tgstation.Server.Host.Models.ChatBot", b => { b.Property("Id") .ValueGeneratedOnAdd() - .HasColumnType("bigint") - .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); b.Property("ChannelLimit") .HasColumnType("integer"); b.Property("ConnectionString") .IsRequired() - .HasColumnType("character varying(10000)") - .HasMaxLength(10000); + .HasMaxLength(10000) + .HasColumnType("character varying(10000)"); b.Property("Enabled") .HasColumnType("boolean"); @@ -41,8 +45,8 @@ namespace Tgstation.Server.Host.Database.Migrations b.Property("Name") .IsRequired() - .HasColumnType("character varying(100)") - .HasMaxLength(100); + .HasMaxLength(100) + .HasColumnType("character varying(100)"); b.Property("Provider") .HasColumnType("integer"); @@ -62,8 +66,9 @@ namespace Tgstation.Server.Host.Database.Migrations { b.Property("Id") .ValueGeneratedOnAdd() - .HasColumnType("bigint") - .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); b.Property("ChatSettingsId") .HasColumnType("bigint"); @@ -72,8 +77,8 @@ namespace Tgstation.Server.Host.Database.Migrations .HasColumnType("numeric(20,0)"); b.Property("IrcChannel") - .HasColumnType("character varying(100)") - .HasMaxLength(100); + .HasMaxLength(100) + .HasColumnType("character varying(100)"); b.Property("IsAdminChannel") .IsRequired() @@ -88,8 +93,8 @@ namespace Tgstation.Server.Host.Database.Migrations .HasColumnType("boolean"); b.Property("Tag") - .HasColumnType("character varying(10000)") - .HasMaxLength(10000); + .HasMaxLength(10000) + .HasColumnType("character varying(10000)"); b.HasKey("Id"); @@ -106,8 +111,9 @@ namespace Tgstation.Server.Host.Database.Migrations { b.Property("Id") .ValueGeneratedOnAdd() - .HasColumnType("bigint") - .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); b.Property("ByondVersion") .IsRequired() @@ -168,13 +174,14 @@ namespace Tgstation.Server.Host.Database.Migrations { b.Property("Id") .ValueGeneratedOnAdd() - .HasColumnType("bigint") - .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); b.Property("AdditionalParameters") .IsRequired() - .HasColumnType("character varying(10000)") - .HasMaxLength(10000); + .HasMaxLength(10000) + .HasColumnType("character varying(10000)"); b.Property("AllowWebClient") .IsRequired() @@ -194,6 +201,10 @@ namespace Tgstation.Server.Host.Database.Migrations b.Property("InstanceId") .HasColumnType("bigint"); + b.Property("LogOutput") + .IsRequired() + .HasColumnType("boolean"); + b.Property("Port") .HasColumnType("integer"); @@ -225,8 +236,9 @@ namespace Tgstation.Server.Host.Database.Migrations { b.Property("Id") .ValueGeneratedOnAdd() - .HasColumnType("bigint") - .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); b.Property("ApiValidationPort") .HasColumnType("integer"); @@ -238,8 +250,8 @@ namespace Tgstation.Server.Host.Database.Migrations .HasColumnType("bigint"); b.Property("ProjectName") - .HasColumnType("character varying(10000)") - .HasMaxLength(10000); + .HasMaxLength(10000) + .HasColumnType("character varying(10000)"); b.Property("RequireDMApiValidation") .IsRequired() @@ -261,8 +273,9 @@ namespace Tgstation.Server.Host.Database.Migrations { b.Property("Id") .ValueGeneratedOnAdd() - .HasColumnType("bigint") - .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); b.Property("AutoUpdateInterval") .HasColumnType("bigint"); @@ -275,8 +288,8 @@ namespace Tgstation.Server.Host.Database.Migrations b.Property("Name") .IsRequired() - .HasColumnType("character varying(100)") - .HasMaxLength(100); + .HasMaxLength(100) + .HasColumnType("character varying(100)"); b.Property("Online") .IsRequired() @@ -301,8 +314,9 @@ namespace Tgstation.Server.Host.Database.Migrations { b.Property("Id") .ValueGeneratedOnAdd() - .HasColumnType("bigint") - .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); b.Property("ByondRights") .HasColumnType("numeric(20,0)"); @@ -345,8 +359,9 @@ namespace Tgstation.Server.Host.Database.Migrations { b.Property("Id") .ValueGeneratedOnAdd() - .HasColumnType("bigint") - .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); b.Property("CancelRight") .HasColumnType("numeric(20,0)"); @@ -399,13 +414,14 @@ namespace Tgstation.Server.Host.Database.Migrations { b.Property("Id") .ValueGeneratedOnAdd() - .HasColumnType("bigint") - .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); b.Property("ExternalUserId") .IsRequired() - .HasColumnType("character varying(100)") - .HasMaxLength(100); + .HasMaxLength(100) + .HasColumnType("character varying(100)"); b.Property("Provider") .HasColumnType("integer"); @@ -427,8 +443,9 @@ namespace Tgstation.Server.Host.Database.Migrations { b.Property("Id") .ValueGeneratedOnAdd() - .HasColumnType("bigint") - .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); b.Property("AdministrationRights") .HasColumnType("numeric(20,0)"); @@ -457,8 +474,9 @@ namespace Tgstation.Server.Host.Database.Migrations { b.Property("Id") .ValueGeneratedOnAdd() - .HasColumnType("bigint") - .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); b.Property("AccessIdentifier") .IsRequired() @@ -493,16 +511,17 @@ namespace Tgstation.Server.Host.Database.Migrations { b.Property("Id") .ValueGeneratedOnAdd() - .HasColumnType("bigint") - .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); b.Property("AccessToken") - .HasColumnType("character varying(10000)") - .HasMaxLength(10000); + .HasMaxLength(10000) + .HasColumnType("character varying(10000)"); b.Property("AccessUser") - .HasColumnType("character varying(10000)") - .HasMaxLength(10000); + .HasMaxLength(10000) + .HasColumnType("character varying(10000)"); b.Property("AutoUpdatesKeepTestMerges") .IsRequired() @@ -514,13 +533,13 @@ namespace Tgstation.Server.Host.Database.Migrations b.Property("CommitterEmail") .IsRequired() - .HasColumnType("character varying(10000)") - .HasMaxLength(10000); + .HasMaxLength(10000) + .HasColumnType("character varying(10000)"); b.Property("CommitterName") .IsRequired() - .HasColumnType("character varying(10000)") - .HasMaxLength(10000); + .HasMaxLength(10000) + .HasColumnType("character varying(10000)"); b.Property("CreateGitHubDeployments") .IsRequired() @@ -557,8 +576,9 @@ namespace Tgstation.Server.Host.Database.Migrations { b.Property("Id") .ValueGeneratedOnAdd() - .HasColumnType("bigint") - .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); b.Property("RevisionInformationId") .HasColumnType("bigint"); @@ -579,21 +599,22 @@ namespace Tgstation.Server.Host.Database.Migrations { b.Property("Id") .ValueGeneratedOnAdd() - .HasColumnType("bigint") - .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); b.Property("CommitSha") .IsRequired() - .HasColumnType("character varying(40)") - .HasMaxLength(40); + .HasMaxLength(40) + .HasColumnType("character varying(40)"); b.Property("InstanceId") .HasColumnType("bigint"); b.Property("OriginCommitSha") .IsRequired() - .HasColumnType("character varying(40)") - .HasMaxLength(40); + .HasMaxLength(40) + .HasColumnType("character varying(40)"); b.Property("Timestamp") .HasColumnType("timestamp with time zone"); @@ -610,8 +631,9 @@ namespace Tgstation.Server.Host.Database.Migrations { b.Property("Id") .ValueGeneratedOnAdd() - .HasColumnType("bigint") - .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); b.Property("Author") .IsRequired() @@ -622,8 +644,8 @@ namespace Tgstation.Server.Host.Database.Migrations .HasColumnType("text"); b.Property("Comment") - .HasColumnType("character varying(10000)") - .HasMaxLength(10000); + .HasMaxLength(10000) + .HasColumnType("character varying(10000)"); b.Property("MergedAt") .HasColumnType("timestamp with time zone"); @@ -640,8 +662,8 @@ namespace Tgstation.Server.Host.Database.Migrations b.Property("TargetCommitSha") .IsRequired() - .HasColumnType("character varying(40)") - .HasMaxLength(40); + .HasMaxLength(40) + .HasColumnType("character varying(40)"); b.Property("TitleAtMerge") .IsRequired() @@ -665,13 +687,14 @@ namespace Tgstation.Server.Host.Database.Migrations { b.Property("Id") .ValueGeneratedOnAdd() - .HasColumnType("bigint") - .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); b.Property("CanonicalName") .IsRequired() - .HasColumnType("character varying(100)") - .HasMaxLength(100); + .HasMaxLength(100) + .HasColumnType("character varying(100)"); b.Property("CreatedAt") .IsRequired() @@ -692,15 +715,15 @@ namespace Tgstation.Server.Host.Database.Migrations b.Property("Name") .IsRequired() - .HasColumnType("character varying(100)") - .HasMaxLength(100); + .HasMaxLength(100) + .HasColumnType("character varying(100)"); b.Property("PasswordHash") .HasColumnType("text"); b.Property("SystemIdentifier") - .HasColumnType("character varying(100)") - .HasMaxLength(100); + .HasMaxLength(100) + .HasColumnType("character varying(100)"); b.HasKey("Id"); @@ -721,13 +744,14 @@ namespace Tgstation.Server.Host.Database.Migrations { b.Property("Id") .ValueGeneratedOnAdd() - .HasColumnType("bigint") - .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); b.Property("Name") .IsRequired() - .HasColumnType("character varying(100)") - .HasMaxLength(100); + .HasMaxLength(100) + .HasColumnType("character varying(100)"); b.HasKey("Id"); @@ -744,6 +768,8 @@ namespace Tgstation.Server.Host.Database.Migrations .HasForeignKey("InstanceId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); + + b.Navigation("Instance"); }); modelBuilder.Entity("Tgstation.Server.Host.Models.ChatChannel", b => @@ -753,6 +779,8 @@ namespace Tgstation.Server.Host.Database.Migrations .HasForeignKey("ChatSettingsId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); + + b.Navigation("ChatSettings"); }); modelBuilder.Entity("Tgstation.Server.Host.Models.CompileJob", b => @@ -768,6 +796,10 @@ namespace Tgstation.Server.Host.Database.Migrations .HasForeignKey("RevisionInformationId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); + + b.Navigation("Job"); + + b.Navigation("RevisionInformation"); }); modelBuilder.Entity("Tgstation.Server.Host.Models.DreamDaemonSettings", b => @@ -777,6 +809,8 @@ namespace Tgstation.Server.Host.Database.Migrations .HasForeignKey("Tgstation.Server.Host.Models.DreamDaemonSettings", "InstanceId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); + + b.Navigation("Instance"); }); modelBuilder.Entity("Tgstation.Server.Host.Models.DreamMakerSettings", b => @@ -786,6 +820,8 @@ namespace Tgstation.Server.Host.Database.Migrations .HasForeignKey("Tgstation.Server.Host.Models.DreamMakerSettings", "InstanceId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); + + b.Navigation("Instance"); }); modelBuilder.Entity("Tgstation.Server.Host.Models.InstancePermissionSet", b => @@ -801,6 +837,10 @@ namespace Tgstation.Server.Host.Database.Migrations .HasForeignKey("PermissionSetId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); + + b.Navigation("Instance"); + + b.Navigation("PermissionSet"); }); modelBuilder.Entity("Tgstation.Server.Host.Models.Job", b => @@ -820,6 +860,12 @@ namespace Tgstation.Server.Host.Database.Migrations .HasForeignKey("StartedById") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); + + b.Navigation("CancelledBy"); + + b.Navigation("Instance"); + + b.Navigation("StartedBy"); }); modelBuilder.Entity("Tgstation.Server.Host.Models.OAuthConnection", b => @@ -828,6 +874,8 @@ namespace Tgstation.Server.Host.Database.Migrations .WithMany("OAuthConnections") .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("User"); }); modelBuilder.Entity("Tgstation.Server.Host.Models.PermissionSet", b => @@ -841,6 +889,10 @@ namespace Tgstation.Server.Host.Database.Migrations .WithOne("PermissionSet") .HasForeignKey("Tgstation.Server.Host.Models.PermissionSet", "UserId") .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("Group"); + + b.Navigation("User"); }); modelBuilder.Entity("Tgstation.Server.Host.Models.ReattachInformation", b => @@ -850,6 +902,8 @@ namespace Tgstation.Server.Host.Database.Migrations .HasForeignKey("CompileJobId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); + + b.Navigation("CompileJob"); }); modelBuilder.Entity("Tgstation.Server.Host.Models.RepositorySettings", b => @@ -859,6 +913,8 @@ namespace Tgstation.Server.Host.Database.Migrations .HasForeignKey("Tgstation.Server.Host.Models.RepositorySettings", "InstanceId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); + + b.Navigation("Instance"); }); modelBuilder.Entity("Tgstation.Server.Host.Models.RevInfoTestMerge", b => @@ -874,6 +930,10 @@ namespace Tgstation.Server.Host.Database.Migrations .HasForeignKey("TestMergeId") .OnDelete(DeleteBehavior.ClientNoAction) .IsRequired(); + + b.Navigation("RevisionInformation"); + + b.Navigation("TestMerge"); }); modelBuilder.Entity("Tgstation.Server.Host.Models.RevisionInformation", b => @@ -883,6 +943,8 @@ namespace Tgstation.Server.Host.Database.Migrations .HasForeignKey("InstanceId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); + + b.Navigation("Instance"); }); modelBuilder.Entity("Tgstation.Server.Host.Models.TestMerge", b => @@ -898,6 +960,10 @@ namespace Tgstation.Server.Host.Database.Migrations .HasForeignKey("Tgstation.Server.Host.Models.TestMerge", "PrimaryRevisionInformationId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); + + b.Navigation("MergedBy"); + + b.Navigation("PrimaryRevisionInformation"); }); modelBuilder.Entity("Tgstation.Server.Host.Models.User", b => @@ -909,6 +975,70 @@ namespace Tgstation.Server.Host.Database.Migrations b.HasOne("Tgstation.Server.Host.Models.UserGroup", "Group") .WithMany("Users") .HasForeignKey("GroupId"); + + b.Navigation("CreatedBy"); + + b.Navigation("Group"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.ChatBot", b => + { + b.Navigation("Channels"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.Instance", b => + { + b.Navigation("ChatSettings"); + + b.Navigation("DreamDaemonSettings"); + + b.Navigation("DreamMakerSettings"); + + b.Navigation("InstancePermissionSets"); + + b.Navigation("Jobs"); + + b.Navigation("RepositorySettings"); + + b.Navigation("RevisionInformations"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.PermissionSet", b => + { + b.Navigation("InstancePermissionSets"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.RevisionInformation", b => + { + b.Navigation("ActiveTestMerges"); + + b.Navigation("CompileJobs"); + + b.Navigation("PrimaryTestMerge"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.TestMerge", b => + { + b.Navigation("RevisonInformations"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.User", b => + { + b.Navigation("CreatedUsers"); + + b.Navigation("OAuthConnections"); + + b.Navigation("PermissionSet"); + + b.Navigation("TestMerges"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.UserGroup", b => + { + b.Navigation("PermissionSet") + .IsRequired(); + + b.Navigation("Users"); }); #pragma warning restore 612, 618 } diff --git a/src/Tgstation.Server.Host/Database/Migrations/SqlServerDatabaseContextModelSnapshot.cs b/src/Tgstation.Server.Host/Database/Migrations/SqlServerDatabaseContextModelSnapshot.cs index 90376c4b01..cc6e484f9b 100644 --- a/src/Tgstation.Server.Host/Database/Migrations/SqlServerDatabaseContextModelSnapshot.cs +++ b/src/Tgstation.Server.Host/Database/Migrations/SqlServerDatabaseContextModelSnapshot.cs @@ -3,35 +3,39 @@ using System; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Metadata; + +#nullable disable namespace Tgstation.Server.Host.Database.Migrations { [DbContext(typeof(SqlServerDatabaseContext))] partial class SqlServerDatabaseContextModelSnapshot : ModelSnapshot { + /// protected override void BuildModel(ModelBuilder modelBuilder) { #pragma warning disable 612, 618 modelBuilder - .HasAnnotation("ProductVersion", "3.1.20") - .HasAnnotation("Relational:MaxIdentifierLength", 128) - .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + .HasAnnotation("ProductVersion", "6.0.15") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder, 1L, 1); modelBuilder.Entity("Tgstation.Server.Host.Models.ChatBot", b => { b.Property("Id") .ValueGeneratedOnAdd() - .HasColumnType("bigint") - .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); b.Property("ChannelLimit") .HasColumnType("int"); b.Property("ConnectionString") .IsRequired() - .HasColumnType("nvarchar(max)") - .HasMaxLength(10000); + .HasMaxLength(10000) + .HasColumnType("nvarchar(max)"); b.Property("Enabled") .HasColumnType("bit"); @@ -41,8 +45,8 @@ namespace Tgstation.Server.Host.Database.Migrations b.Property("Name") .IsRequired() - .HasColumnType("nvarchar(100)") - .HasMaxLength(100); + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); b.Property("Provider") .HasColumnType("int"); @@ -62,8 +66,9 @@ namespace Tgstation.Server.Host.Database.Migrations { b.Property("Id") .ValueGeneratedOnAdd() - .HasColumnType("bigint") - .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); b.Property("ChatSettingsId") .HasColumnType("bigint"); @@ -72,8 +77,8 @@ namespace Tgstation.Server.Host.Database.Migrations .HasColumnType("decimal(20,0)"); b.Property("IrcChannel") - .HasColumnType("nvarchar(100)") - .HasMaxLength(100); + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); b.Property("IsAdminChannel") .IsRequired() @@ -88,8 +93,8 @@ namespace Tgstation.Server.Host.Database.Migrations .HasColumnType("bit"); b.Property("Tag") - .HasColumnType("nvarchar(max)") - .HasMaxLength(10000); + .HasMaxLength(10000) + .HasColumnType("nvarchar(max)"); b.HasKey("Id"); @@ -108,8 +113,9 @@ namespace Tgstation.Server.Host.Database.Migrations { b.Property("Id") .ValueGeneratedOnAdd() - .HasColumnType("bigint") - .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); b.Property("ByondVersion") .IsRequired() @@ -170,13 +176,14 @@ namespace Tgstation.Server.Host.Database.Migrations { b.Property("Id") .ValueGeneratedOnAdd() - .HasColumnType("bigint") - .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); b.Property("AdditionalParameters") .IsRequired() - .HasColumnType("nvarchar(max)") - .HasMaxLength(10000); + .HasMaxLength(10000) + .HasColumnType("nvarchar(max)"); b.Property("AllowWebClient") .IsRequired() @@ -196,6 +203,10 @@ namespace Tgstation.Server.Host.Database.Migrations b.Property("InstanceId") .HasColumnType("bigint"); + b.Property("LogOutput") + .IsRequired() + .HasColumnType("bit"); + b.Property("Port") .HasColumnType("int"); @@ -227,8 +238,9 @@ namespace Tgstation.Server.Host.Database.Migrations { b.Property("Id") .ValueGeneratedOnAdd() - .HasColumnType("bigint") - .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); b.Property("ApiValidationPort") .HasColumnType("int"); @@ -240,8 +252,8 @@ namespace Tgstation.Server.Host.Database.Migrations .HasColumnType("bigint"); b.Property("ProjectName") - .HasColumnType("nvarchar(max)") - .HasMaxLength(10000); + .HasMaxLength(10000) + .HasColumnType("nvarchar(max)"); b.Property("RequireDMApiValidation") .IsRequired() @@ -263,8 +275,9 @@ namespace Tgstation.Server.Host.Database.Migrations { b.Property("Id") .ValueGeneratedOnAdd() - .HasColumnType("bigint") - .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); b.Property("AutoUpdateInterval") .HasColumnType("bigint"); @@ -277,8 +290,8 @@ namespace Tgstation.Server.Host.Database.Migrations b.Property("Name") .IsRequired() - .HasColumnType("nvarchar(100)") - .HasMaxLength(100); + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); b.Property("Online") .IsRequired() @@ -304,8 +317,9 @@ namespace Tgstation.Server.Host.Database.Migrations { b.Property("Id") .ValueGeneratedOnAdd() - .HasColumnType("bigint") - .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); b.Property("ByondRights") .HasColumnType("decimal(20,0)"); @@ -348,8 +362,9 @@ namespace Tgstation.Server.Host.Database.Migrations { b.Property("Id") .ValueGeneratedOnAdd() - .HasColumnType("bigint") - .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); b.Property("CancelRight") .HasColumnType("decimal(20,0)"); @@ -402,13 +417,14 @@ namespace Tgstation.Server.Host.Database.Migrations { b.Property("Id") .ValueGeneratedOnAdd() - .HasColumnType("bigint") - .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); b.Property("ExternalUserId") .IsRequired() - .HasColumnType("nvarchar(100)") - .HasMaxLength(100); + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); b.Property("Provider") .HasColumnType("int"); @@ -430,8 +446,9 @@ namespace Tgstation.Server.Host.Database.Migrations { b.Property("Id") .ValueGeneratedOnAdd() - .HasColumnType("bigint") - .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); b.Property("AdministrationRights") .HasColumnType("decimal(20,0)"); @@ -462,8 +479,9 @@ namespace Tgstation.Server.Host.Database.Migrations { b.Property("Id") .ValueGeneratedOnAdd() - .HasColumnType("bigint") - .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); b.Property("AccessIdentifier") .IsRequired() @@ -498,16 +516,17 @@ namespace Tgstation.Server.Host.Database.Migrations { b.Property("Id") .ValueGeneratedOnAdd() - .HasColumnType("bigint") - .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); b.Property("AccessToken") - .HasColumnType("nvarchar(max)") - .HasMaxLength(10000); + .HasMaxLength(10000) + .HasColumnType("nvarchar(max)"); b.Property("AccessUser") - .HasColumnType("nvarchar(max)") - .HasMaxLength(10000); + .HasMaxLength(10000) + .HasColumnType("nvarchar(max)"); b.Property("AutoUpdatesKeepTestMerges") .IsRequired() @@ -519,13 +538,13 @@ namespace Tgstation.Server.Host.Database.Migrations b.Property("CommitterEmail") .IsRequired() - .HasColumnType("nvarchar(max)") - .HasMaxLength(10000); + .HasMaxLength(10000) + .HasColumnType("nvarchar(max)"); b.Property("CommitterName") .IsRequired() - .HasColumnType("nvarchar(max)") - .HasMaxLength(10000); + .HasMaxLength(10000) + .HasColumnType("nvarchar(max)"); b.Property("CreateGitHubDeployments") .IsRequired() @@ -562,8 +581,9 @@ namespace Tgstation.Server.Host.Database.Migrations { b.Property("Id") .ValueGeneratedOnAdd() - .HasColumnType("bigint") - .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); b.Property("RevisionInformationId") .HasColumnType("bigint"); @@ -584,21 +604,22 @@ namespace Tgstation.Server.Host.Database.Migrations { b.Property("Id") .ValueGeneratedOnAdd() - .HasColumnType("bigint") - .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); b.Property("CommitSha") .IsRequired() - .HasColumnType("nvarchar(40)") - .HasMaxLength(40); + .HasMaxLength(40) + .HasColumnType("nvarchar(40)"); b.Property("InstanceId") .HasColumnType("bigint"); b.Property("OriginCommitSha") .IsRequired() - .HasColumnType("nvarchar(40)") - .HasMaxLength(40); + .HasMaxLength(40) + .HasColumnType("nvarchar(40)"); b.Property("Timestamp") .HasColumnType("datetimeoffset"); @@ -615,8 +636,9 @@ namespace Tgstation.Server.Host.Database.Migrations { b.Property("Id") .ValueGeneratedOnAdd() - .HasColumnType("bigint") - .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); b.Property("Author") .IsRequired() @@ -627,8 +649,8 @@ namespace Tgstation.Server.Host.Database.Migrations .HasColumnType("nvarchar(max)"); b.Property("Comment") - .HasColumnType("nvarchar(max)") - .HasMaxLength(10000); + .HasMaxLength(10000) + .HasColumnType("nvarchar(max)"); b.Property("MergedAt") .HasColumnType("datetimeoffset"); @@ -645,8 +667,8 @@ namespace Tgstation.Server.Host.Database.Migrations b.Property("TargetCommitSha") .IsRequired() - .HasColumnType("nvarchar(40)") - .HasMaxLength(40); + .HasMaxLength(40) + .HasColumnType("nvarchar(40)"); b.Property("TitleAtMerge") .IsRequired() @@ -670,13 +692,14 @@ namespace Tgstation.Server.Host.Database.Migrations { b.Property("Id") .ValueGeneratedOnAdd() - .HasColumnType("bigint") - .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); b.Property("CanonicalName") .IsRequired() - .HasColumnType("nvarchar(100)") - .HasMaxLength(100); + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); b.Property("CreatedAt") .IsRequired() @@ -697,15 +720,15 @@ namespace Tgstation.Server.Host.Database.Migrations b.Property("Name") .IsRequired() - .HasColumnType("nvarchar(100)") - .HasMaxLength(100); + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); b.Property("PasswordHash") .HasColumnType("nvarchar(max)"); b.Property("SystemIdentifier") - .HasColumnType("nvarchar(100)") - .HasMaxLength(100); + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); b.HasKey("Id"); @@ -727,13 +750,14 @@ namespace Tgstation.Server.Host.Database.Migrations { b.Property("Id") .ValueGeneratedOnAdd() - .HasColumnType("bigint") - .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); b.Property("Name") .IsRequired() - .HasColumnType("nvarchar(100)") - .HasMaxLength(100); + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); b.HasKey("Id"); @@ -750,6 +774,8 @@ namespace Tgstation.Server.Host.Database.Migrations .HasForeignKey("InstanceId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); + + b.Navigation("Instance"); }); modelBuilder.Entity("Tgstation.Server.Host.Models.ChatChannel", b => @@ -759,6 +785,8 @@ namespace Tgstation.Server.Host.Database.Migrations .HasForeignKey("ChatSettingsId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); + + b.Navigation("ChatSettings"); }); modelBuilder.Entity("Tgstation.Server.Host.Models.CompileJob", b => @@ -774,6 +802,10 @@ namespace Tgstation.Server.Host.Database.Migrations .HasForeignKey("RevisionInformationId") .OnDelete(DeleteBehavior.ClientNoAction) .IsRequired(); + + b.Navigation("Job"); + + b.Navigation("RevisionInformation"); }); modelBuilder.Entity("Tgstation.Server.Host.Models.DreamDaemonSettings", b => @@ -783,6 +815,8 @@ namespace Tgstation.Server.Host.Database.Migrations .HasForeignKey("Tgstation.Server.Host.Models.DreamDaemonSettings", "InstanceId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); + + b.Navigation("Instance"); }); modelBuilder.Entity("Tgstation.Server.Host.Models.DreamMakerSettings", b => @@ -792,6 +826,8 @@ namespace Tgstation.Server.Host.Database.Migrations .HasForeignKey("Tgstation.Server.Host.Models.DreamMakerSettings", "InstanceId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); + + b.Navigation("Instance"); }); modelBuilder.Entity("Tgstation.Server.Host.Models.InstancePermissionSet", b => @@ -807,6 +843,10 @@ namespace Tgstation.Server.Host.Database.Migrations .HasForeignKey("PermissionSetId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); + + b.Navigation("Instance"); + + b.Navigation("PermissionSet"); }); modelBuilder.Entity("Tgstation.Server.Host.Models.Job", b => @@ -826,6 +866,12 @@ namespace Tgstation.Server.Host.Database.Migrations .HasForeignKey("StartedById") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); + + b.Navigation("CancelledBy"); + + b.Navigation("Instance"); + + b.Navigation("StartedBy"); }); modelBuilder.Entity("Tgstation.Server.Host.Models.OAuthConnection", b => @@ -834,6 +880,8 @@ namespace Tgstation.Server.Host.Database.Migrations .WithMany("OAuthConnections") .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("User"); }); modelBuilder.Entity("Tgstation.Server.Host.Models.PermissionSet", b => @@ -847,6 +895,10 @@ namespace Tgstation.Server.Host.Database.Migrations .WithOne("PermissionSet") .HasForeignKey("Tgstation.Server.Host.Models.PermissionSet", "UserId") .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("Group"); + + b.Navigation("User"); }); modelBuilder.Entity("Tgstation.Server.Host.Models.ReattachInformation", b => @@ -856,6 +908,8 @@ namespace Tgstation.Server.Host.Database.Migrations .HasForeignKey("CompileJobId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); + + b.Navigation("CompileJob"); }); modelBuilder.Entity("Tgstation.Server.Host.Models.RepositorySettings", b => @@ -865,6 +919,8 @@ namespace Tgstation.Server.Host.Database.Migrations .HasForeignKey("Tgstation.Server.Host.Models.RepositorySettings", "InstanceId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); + + b.Navigation("Instance"); }); modelBuilder.Entity("Tgstation.Server.Host.Models.RevInfoTestMerge", b => @@ -880,6 +936,10 @@ namespace Tgstation.Server.Host.Database.Migrations .HasForeignKey("TestMergeId") .OnDelete(DeleteBehavior.ClientNoAction) .IsRequired(); + + b.Navigation("RevisionInformation"); + + b.Navigation("TestMerge"); }); modelBuilder.Entity("Tgstation.Server.Host.Models.RevisionInformation", b => @@ -889,6 +949,8 @@ namespace Tgstation.Server.Host.Database.Migrations .HasForeignKey("InstanceId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); + + b.Navigation("Instance"); }); modelBuilder.Entity("Tgstation.Server.Host.Models.TestMerge", b => @@ -904,6 +966,10 @@ namespace Tgstation.Server.Host.Database.Migrations .HasForeignKey("Tgstation.Server.Host.Models.TestMerge", "PrimaryRevisionInformationId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); + + b.Navigation("MergedBy"); + + b.Navigation("PrimaryRevisionInformation"); }); modelBuilder.Entity("Tgstation.Server.Host.Models.User", b => @@ -915,6 +981,70 @@ namespace Tgstation.Server.Host.Database.Migrations b.HasOne("Tgstation.Server.Host.Models.UserGroup", "Group") .WithMany("Users") .HasForeignKey("GroupId"); + + b.Navigation("CreatedBy"); + + b.Navigation("Group"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.ChatBot", b => + { + b.Navigation("Channels"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.Instance", b => + { + b.Navigation("ChatSettings"); + + b.Navigation("DreamDaemonSettings"); + + b.Navigation("DreamMakerSettings"); + + b.Navigation("InstancePermissionSets"); + + b.Navigation("Jobs"); + + b.Navigation("RepositorySettings"); + + b.Navigation("RevisionInformations"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.PermissionSet", b => + { + b.Navigation("InstancePermissionSets"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.RevisionInformation", b => + { + b.Navigation("ActiveTestMerges"); + + b.Navigation("CompileJobs"); + + b.Navigation("PrimaryTestMerge"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.TestMerge", b => + { + b.Navigation("RevisonInformations"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.User", b => + { + b.Navigation("CreatedUsers"); + + b.Navigation("OAuthConnections"); + + b.Navigation("PermissionSet"); + + b.Navigation("TestMerges"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.UserGroup", b => + { + b.Navigation("PermissionSet") + .IsRequired(); + + b.Navigation("Users"); }); #pragma warning restore 612, 618 } diff --git a/src/Tgstation.Server.Host/Database/Migrations/SqliteDatabaseContextModelSnapshot.cs b/src/Tgstation.Server.Host/Database/Migrations/SqliteDatabaseContextModelSnapshot.cs index 64ce232058..cdc004f6a5 100644 --- a/src/Tgstation.Server.Host/Database/Migrations/SqliteDatabaseContextModelSnapshot.cs +++ b/src/Tgstation.Server.Host/Database/Migrations/SqliteDatabaseContextModelSnapshot.cs @@ -4,16 +4,18 @@ using System; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; +#nullable disable + namespace Tgstation.Server.Host.Database.Migrations { [DbContext(typeof(SqliteDatabaseContext))] partial class SqliteDatabaseContextModelSnapshot : ModelSnapshot { + /// protected override void BuildModel(ModelBuilder modelBuilder) { #pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "3.1.20"); + modelBuilder.HasAnnotation("ProductVersion", "6.0.15"); modelBuilder.Entity("Tgstation.Server.Host.Models.ChatBot", b => { @@ -27,8 +29,8 @@ namespace Tgstation.Server.Host.Database.Migrations b.Property("ConnectionString") .IsRequired() - .HasColumnType("TEXT") - .HasMaxLength(10000); + .HasMaxLength(10000) + .HasColumnType("TEXT"); b.Property("Enabled") .HasColumnType("INTEGER"); @@ -38,8 +40,8 @@ namespace Tgstation.Server.Host.Database.Migrations b.Property("Name") .IsRequired() - .HasColumnType("TEXT") - .HasMaxLength(100); + .HasMaxLength(100) + .HasColumnType("TEXT"); b.Property("Provider") .HasColumnType("INTEGER"); @@ -69,8 +71,8 @@ namespace Tgstation.Server.Host.Database.Migrations .HasColumnType("INTEGER"); b.Property("IrcChannel") - .HasColumnType("TEXT") - .HasMaxLength(100); + .HasMaxLength(100) + .HasColumnType("TEXT"); b.Property("IsAdminChannel") .IsRequired() @@ -85,8 +87,8 @@ namespace Tgstation.Server.Host.Database.Migrations .HasColumnType("INTEGER"); b.Property("Tag") - .HasColumnType("TEXT") - .HasMaxLength(10000); + .HasMaxLength(10000) + .HasColumnType("TEXT"); b.HasKey("Id"); @@ -168,8 +170,8 @@ namespace Tgstation.Server.Host.Database.Migrations b.Property("AdditionalParameters") .IsRequired() - .HasColumnType("TEXT") - .HasMaxLength(10000); + .HasMaxLength(10000) + .HasColumnType("TEXT"); b.Property("AllowWebClient") .IsRequired() @@ -190,6 +192,10 @@ namespace Tgstation.Server.Host.Database.Migrations b.Property("InstanceId") .HasColumnType("INTEGER"); + b.Property("LogOutput") + .IsRequired() + .HasColumnType("INTEGER"); + b.Property("Port") .IsRequired() .HasColumnType("INTEGER"); @@ -237,8 +243,8 @@ namespace Tgstation.Server.Host.Database.Migrations .HasColumnType("INTEGER"); b.Property("ProjectName") - .HasColumnType("TEXT") - .HasMaxLength(10000); + .HasMaxLength(10000) + .HasColumnType("TEXT"); b.Property("RequireDMApiValidation") .IsRequired() @@ -275,8 +281,8 @@ namespace Tgstation.Server.Host.Database.Migrations b.Property("Name") .IsRequired() - .HasColumnType("TEXT") - .HasMaxLength(100); + .HasMaxLength(100) + .HasColumnType("TEXT"); b.Property("Online") .IsRequired() @@ -401,8 +407,8 @@ namespace Tgstation.Server.Host.Database.Migrations b.Property("ExternalUserId") .IsRequired() - .HasColumnType("TEXT") - .HasMaxLength(100); + .HasMaxLength(100) + .HasColumnType("TEXT"); b.Property("Provider") .HasColumnType("INTEGER"); @@ -491,12 +497,12 @@ namespace Tgstation.Server.Host.Database.Migrations .HasColumnType("INTEGER"); b.Property("AccessToken") - .HasColumnType("TEXT") - .HasMaxLength(10000); + .HasMaxLength(10000) + .HasColumnType("TEXT"); b.Property("AccessUser") - .HasColumnType("TEXT") - .HasMaxLength(10000); + .HasMaxLength(10000) + .HasColumnType("TEXT"); b.Property("AutoUpdatesKeepTestMerges") .IsRequired() @@ -508,13 +514,13 @@ namespace Tgstation.Server.Host.Database.Migrations b.Property("CommitterEmail") .IsRequired() - .HasColumnType("TEXT") - .HasMaxLength(10000); + .HasMaxLength(10000) + .HasColumnType("TEXT"); b.Property("CommitterName") .IsRequired() - .HasColumnType("TEXT") - .HasMaxLength(10000); + .HasMaxLength(10000) + .HasColumnType("TEXT"); b.Property("CreateGitHubDeployments") .IsRequired() @@ -576,16 +582,16 @@ namespace Tgstation.Server.Host.Database.Migrations b.Property("CommitSha") .IsRequired() - .HasColumnType("TEXT") - .HasMaxLength(40); + .HasMaxLength(40) + .HasColumnType("TEXT"); b.Property("InstanceId") .HasColumnType("INTEGER"); b.Property("OriginCommitSha") .IsRequired() - .HasColumnType("TEXT") - .HasMaxLength(40); + .HasMaxLength(40) + .HasColumnType("TEXT"); b.Property("Timestamp") .HasColumnType("TEXT"); @@ -613,8 +619,8 @@ namespace Tgstation.Server.Host.Database.Migrations .HasColumnType("TEXT"); b.Property("Comment") - .HasColumnType("TEXT") - .HasMaxLength(10000); + .HasMaxLength(10000) + .HasColumnType("TEXT"); b.Property("MergedAt") .HasColumnType("TEXT"); @@ -631,8 +637,8 @@ namespace Tgstation.Server.Host.Database.Migrations b.Property("TargetCommitSha") .IsRequired() - .HasColumnType("TEXT") - .HasMaxLength(40); + .HasMaxLength(40) + .HasColumnType("TEXT"); b.Property("TitleAtMerge") .IsRequired() @@ -660,8 +666,8 @@ namespace Tgstation.Server.Host.Database.Migrations b.Property("CanonicalName") .IsRequired() - .HasColumnType("TEXT") - .HasMaxLength(100); + .HasMaxLength(100) + .HasColumnType("TEXT"); b.Property("CreatedAt") .IsRequired() @@ -682,15 +688,15 @@ namespace Tgstation.Server.Host.Database.Migrations b.Property("Name") .IsRequired() - .HasColumnType("TEXT") - .HasMaxLength(100); + .HasMaxLength(100) + .HasColumnType("TEXT"); b.Property("PasswordHash") .HasColumnType("TEXT"); b.Property("SystemIdentifier") - .HasColumnType("TEXT") - .HasMaxLength(100); + .HasMaxLength(100) + .HasColumnType("TEXT"); b.HasKey("Id"); @@ -715,8 +721,8 @@ namespace Tgstation.Server.Host.Database.Migrations b.Property("Name") .IsRequired() - .HasColumnType("TEXT") - .HasMaxLength(100); + .HasMaxLength(100) + .HasColumnType("TEXT"); b.HasKey("Id"); @@ -733,6 +739,8 @@ namespace Tgstation.Server.Host.Database.Migrations .HasForeignKey("InstanceId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); + + b.Navigation("Instance"); }); modelBuilder.Entity("Tgstation.Server.Host.Models.ChatChannel", b => @@ -742,6 +750,8 @@ namespace Tgstation.Server.Host.Database.Migrations .HasForeignKey("ChatSettingsId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); + + b.Navigation("ChatSettings"); }); modelBuilder.Entity("Tgstation.Server.Host.Models.CompileJob", b => @@ -757,6 +767,10 @@ namespace Tgstation.Server.Host.Database.Migrations .HasForeignKey("RevisionInformationId") .OnDelete(DeleteBehavior.ClientNoAction) .IsRequired(); + + b.Navigation("Job"); + + b.Navigation("RevisionInformation"); }); modelBuilder.Entity("Tgstation.Server.Host.Models.DreamDaemonSettings", b => @@ -766,6 +780,8 @@ namespace Tgstation.Server.Host.Database.Migrations .HasForeignKey("Tgstation.Server.Host.Models.DreamDaemonSettings", "InstanceId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); + + b.Navigation("Instance"); }); modelBuilder.Entity("Tgstation.Server.Host.Models.DreamMakerSettings", b => @@ -775,6 +791,8 @@ namespace Tgstation.Server.Host.Database.Migrations .HasForeignKey("Tgstation.Server.Host.Models.DreamMakerSettings", "InstanceId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); + + b.Navigation("Instance"); }); modelBuilder.Entity("Tgstation.Server.Host.Models.InstancePermissionSet", b => @@ -790,6 +808,10 @@ namespace Tgstation.Server.Host.Database.Migrations .HasForeignKey("PermissionSetId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); + + b.Navigation("Instance"); + + b.Navigation("PermissionSet"); }); modelBuilder.Entity("Tgstation.Server.Host.Models.Job", b => @@ -809,6 +831,12 @@ namespace Tgstation.Server.Host.Database.Migrations .HasForeignKey("StartedById") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); + + b.Navigation("CancelledBy"); + + b.Navigation("Instance"); + + b.Navigation("StartedBy"); }); modelBuilder.Entity("Tgstation.Server.Host.Models.OAuthConnection", b => @@ -817,6 +845,8 @@ namespace Tgstation.Server.Host.Database.Migrations .WithMany("OAuthConnections") .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("User"); }); modelBuilder.Entity("Tgstation.Server.Host.Models.PermissionSet", b => @@ -830,6 +860,10 @@ namespace Tgstation.Server.Host.Database.Migrations .WithOne("PermissionSet") .HasForeignKey("Tgstation.Server.Host.Models.PermissionSet", "UserId") .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("Group"); + + b.Navigation("User"); }); modelBuilder.Entity("Tgstation.Server.Host.Models.ReattachInformation", b => @@ -839,6 +873,8 @@ namespace Tgstation.Server.Host.Database.Migrations .HasForeignKey("CompileJobId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); + + b.Navigation("CompileJob"); }); modelBuilder.Entity("Tgstation.Server.Host.Models.RepositorySettings", b => @@ -848,6 +884,8 @@ namespace Tgstation.Server.Host.Database.Migrations .HasForeignKey("Tgstation.Server.Host.Models.RepositorySettings", "InstanceId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); + + b.Navigation("Instance"); }); modelBuilder.Entity("Tgstation.Server.Host.Models.RevInfoTestMerge", b => @@ -863,6 +901,10 @@ namespace Tgstation.Server.Host.Database.Migrations .HasForeignKey("TestMergeId") .OnDelete(DeleteBehavior.ClientNoAction) .IsRequired(); + + b.Navigation("RevisionInformation"); + + b.Navigation("TestMerge"); }); modelBuilder.Entity("Tgstation.Server.Host.Models.RevisionInformation", b => @@ -872,6 +914,8 @@ namespace Tgstation.Server.Host.Database.Migrations .HasForeignKey("InstanceId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); + + b.Navigation("Instance"); }); modelBuilder.Entity("Tgstation.Server.Host.Models.TestMerge", b => @@ -887,6 +931,10 @@ namespace Tgstation.Server.Host.Database.Migrations .HasForeignKey("Tgstation.Server.Host.Models.TestMerge", "PrimaryRevisionInformationId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); + + b.Navigation("MergedBy"); + + b.Navigation("PrimaryRevisionInformation"); }); modelBuilder.Entity("Tgstation.Server.Host.Models.User", b => @@ -898,6 +946,70 @@ namespace Tgstation.Server.Host.Database.Migrations b.HasOne("Tgstation.Server.Host.Models.UserGroup", "Group") .WithMany("Users") .HasForeignKey("GroupId"); + + b.Navigation("CreatedBy"); + + b.Navigation("Group"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.ChatBot", b => + { + b.Navigation("Channels"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.Instance", b => + { + b.Navigation("ChatSettings"); + + b.Navigation("DreamDaemonSettings"); + + b.Navigation("DreamMakerSettings"); + + b.Navigation("InstancePermissionSets"); + + b.Navigation("Jobs"); + + b.Navigation("RepositorySettings"); + + b.Navigation("RevisionInformations"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.PermissionSet", b => + { + b.Navigation("InstancePermissionSets"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.RevisionInformation", b => + { + b.Navigation("ActiveTestMerges"); + + b.Navigation("CompileJobs"); + + b.Navigation("PrimaryTestMerge"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.TestMerge", b => + { + b.Navigation("RevisonInformations"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.User", b => + { + b.Navigation("CreatedUsers"); + + b.Navigation("OAuthConnections"); + + b.Navigation("PermissionSet"); + + b.Navigation("TestMerges"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.UserGroup", b => + { + b.Navigation("PermissionSet") + .IsRequired(); + + b.Navigation("Users"); }); #pragma warning restore 612, 618 } diff --git a/src/Tgstation.Server.Host/IO/DefaultIOManager.cs b/src/Tgstation.Server.Host/IO/DefaultIOManager.cs index d943fb8399..54eb3e86bb 100644 --- a/src/Tgstation.Server.Host/IO/DefaultIOManager.cs +++ b/src/Tgstation.Server.Host/IO/DefaultIOManager.cs @@ -246,16 +246,22 @@ namespace Tgstation.Server.Host.IO /// public async Task WriteAllBytes(string path, byte[] contents, CancellationToken cancellationToken) + { + using var file = CreateAsyncWriteStream(path); + await file.WriteAsync(contents, cancellationToken); + } + + /// + public FileStream CreateAsyncWriteStream(string path) { path = ResolvePath(path); - using var file = new FileStream( + return new FileStream( path, FileMode.Create, FileAccess.Write, - FileShare.ReadWrite, + FileShare.Read, DefaultBufferSize, FileOptions.Asynchronous | FileOptions.SequentialScan); - await file.WriteAsync(contents, cancellationToken); } /// diff --git a/src/Tgstation.Server.Host/IO/IIOManager.cs b/src/Tgstation.Server.Host/IO/IIOManager.cs index 2e50ee317d..e46bb74676 100644 --- a/src/Tgstation.Server.Host/IO/IIOManager.cs +++ b/src/Tgstation.Server.Host/IO/IIOManager.cs @@ -101,6 +101,13 @@ namespace Tgstation.Server.Host.IO /// A resulting in the files in . Task> GetFiles(string path, CancellationToken cancellationToken); + /// + /// Creates a for writing. + /// + /// The path of the file to write, will be truncated. + /// The open . + FileStream CreateAsyncWriteStream(string path); + /// /// Writes some to a file at overwriting previous content. /// diff --git a/src/Tgstation.Server.Host/Server.cs b/src/Tgstation.Server.Host/Server.cs index e67d6b15a3..f4e6c195b7 100644 --- a/src/Tgstation.Server.Host/Server.cs +++ b/src/Tgstation.Server.Host/Server.cs @@ -112,8 +112,7 @@ namespace Tgstation.Server.Host { if (b.FullPath == updatePath && File.Exists(b.FullPath)) { - if (logger != null) - logger.LogInformation("Host watchdog appears to be requesting server termination!"); + logger?.LogInformation("Host watchdog appears to be requesting server termination!"); cancellationTokenSource.Cancel(); } }; @@ -134,8 +133,7 @@ namespace Tgstation.Server.Host } catch (OperationCanceledException ex) { - if (logger != null) - logger.LogDebug(ex, "Server run cancelled!"); + logger?.LogDebug(ex, "Server run cancelled!"); } catch (Exception ex) { diff --git a/src/Tgstation.Server.Host/System/IProcess.cs b/src/Tgstation.Server.Host/System/IProcess.cs index 7dfaf923b2..176aea16da 100644 --- a/src/Tgstation.Server.Host/System/IProcess.cs +++ b/src/Tgstation.Server.Host/System/IProcess.cs @@ -7,7 +7,7 @@ namespace Tgstation.Server.Host.System /// /// Abstraction over a . /// - interface IProcess : IProcessBase, IDisposable + interface IProcess : IProcessBase, IAsyncDisposable { /// /// The ' ID. @@ -19,20 +19,6 @@ namespace Tgstation.Server.Host.System /// Task Startup { get; } - /// - /// Get the stderr output of the . - /// - /// The for the operation. - /// A resulting in the stderr output of the . - Task GetErrorOutput(CancellationToken cancellationToken); - - /// - /// Get the stdout output of the . - /// - /// The for the operation. - /// A resulting in the stdout output of the . - Task GetStandardOutput(CancellationToken cancellationToken); - /// /// Get the stderr and stdout output of the . /// diff --git a/src/Tgstation.Server.Host/System/IProcessExecutor.cs b/src/Tgstation.Server.Host/System/IProcessExecutor.cs index 0ab2e90f02..e862a5ec87 100644 --- a/src/Tgstation.Server.Host/System/IProcessExecutor.cs +++ b/src/Tgstation.Server.Host/System/IProcessExecutor.cs @@ -1,4 +1,6 @@ -namespace Tgstation.Server.Host.System +using System.Threading.Tasks; + +namespace Tgstation.Server.Host.System { /// /// For launching '. @@ -11,16 +13,16 @@ /// The full path to the executable file. /// The working directory for the . /// The arguments for the . - /// If standard output should be read. - /// If standard error should be read. - /// If shell execute should not be used. Must be set if or are set. - /// A new . - IProcess LaunchProcess( + /// File to write process output and error streams to. Requires to be . + /// If the process output and error streams should be read. + /// If shell execute should not be used. Must be set if is set. + /// A resulting in the new . + Task LaunchProcess( string fileName, string workingDirectory, string arguments = null, - bool readOutput = false, - bool readError = false, + string fileRedirect = null, + bool readStandardHandles = false, bool noShellExecute = false); /// diff --git a/src/Tgstation.Server.Host/System/PosixProcessFeatures.cs b/src/Tgstation.Server.Host/System/PosixProcessFeatures.cs index b821993053..184ce2b55e 100644 --- a/src/Tgstation.Server.Host/System/PosixProcessFeatures.cs +++ b/src/Tgstation.Server.Host/System/PosixProcessFeatures.cs @@ -90,13 +90,12 @@ namespace Tgstation.Server.Host.System string output; int exitCode; - using (var gcoreProc = lazyLoadedProcessExecutor.Value.LaunchProcess( + await using (var gcoreProc = await lazyLoadedProcessExecutor.Value.LaunchProcess( GCorePath, Environment.CurrentDirectory, $"-o {outputFile} {process.Id}", - true, - true, - true)) + readStandardHandles: true, + noShellExecute: true)) { using (cancellationToken.Register(() => gcoreProc.Terminate())) exitCode = await gcoreProc.Lifetime; diff --git a/src/Tgstation.Server.Host/System/Process.cs b/src/Tgstation.Server.Host/System/Process.cs index 4a7225df13..723f06698d 100644 --- a/src/Tgstation.Server.Host/System/Process.cs +++ b/src/Tgstation.Server.Host/System/Process.cs @@ -1,13 +1,11 @@ using System; using System.Diagnostics; -using System.Text; using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Logging; using Microsoft.Win32.SafeHandles; -using Tgstation.Server.Host.Extensions; using Tgstation.Server.Host.IO; namespace Tgstation.Server.Host.System @@ -39,6 +37,11 @@ namespace Tgstation.Server.Host.System /// readonly global::System.Diagnostics.Process handle; + /// + /// The used to shutdown the . + /// + readonly CancellationTokenSource readerCts; + /// /// The . /// @@ -46,38 +49,26 @@ namespace Tgstation.Server.Host.System readonly SafeProcessHandle safeHandle; /// - /// The resulting in the process' standard output text. + /// The resulting in the process' standard output/error text. /// - readonly Task standardOutputTask; - - /// - /// The resulting in the process' standard error text. - /// - readonly Task standardErrorTask; - - /// - /// The resulting in the process' unified standard output and standard error text. - /// - readonly StringBuilder combinedStringBuilder; + readonly Task readTask; /// /// Initializes a new instance of the class. /// /// 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 . /// If was NOT just created. public Process( IProcessFeatures processFeatures, global::System.Diagnostics.Process handle, + CancellationTokenSource readerCts, Task lifetime, - Task standardOutputTask, - Task standardErrorTask, - StringBuilder combinedStringBuilder, + Task readTask, ILogger logger, bool preExisting) { @@ -87,11 +78,11 @@ namespace Tgstation.Server.Host.System safeHandle = handle.SafeHandle; Id = handle.Id; + this.readerCts = readerCts; + this.processFeatures = processFeatures ?? throw new ArgumentNullException(nameof(processFeatures)); - this.standardOutputTask = standardOutputTask; - this.standardErrorTask = standardErrorTask; - this.combinedStringBuilder = combinedStringBuilder; + this.readTask = readTask; this.logger = logger ?? throw new ArgumentNullException(nameof(logger)); @@ -123,42 +114,23 @@ namespace Tgstation.Server.Host.System } /// - public void Dispose() + public async ValueTask DisposeAsync() { + readerCts?.Cancel(); + readerCts?.Dispose(); + if (readTask != null) + await readTask; + safeHandle.Dispose(); handle.Dispose(); } /// - public async Task GetCombinedOutput(CancellationToken cancellationToken) + public Task GetCombinedOutput(CancellationToken cancellationToken) { - if (combinedStringBuilder == null) + if (readTask == null) throw new InvalidOperationException("Output/Error stream reading was not enabled!"); - await Task.WhenAll( - GetStandardOutput(cancellationToken), - GetErrorOutput(cancellationToken)) - ; - return combinedStringBuilder.ToString().TrimStart(Environment.NewLine.ToCharArray()); - } - - /// - public async Task GetErrorOutput(CancellationToken cancellationToken) - { - if (standardErrorTask == null) - throw new InvalidOperationException("Error stream reading was not enabled!"); - if (!standardErrorTask.IsCompleted) - logger.LogTrace("Waiting for PID {0} to close error stream...", Id); - return await standardErrorTask.WithToken(cancellationToken); - } - - /// - public async Task GetStandardOutput(CancellationToken cancellationToken) - { - if (standardOutputTask == null) - throw new InvalidOperationException("Output stream reading was not enabled!"); - if (!standardOutputTask.IsCompleted) - logger.LogTrace("Waiting for PID {0} to close output stream...", Id); - return await standardOutputTask.WithToken(cancellationToken); + return readTask; } /// diff --git a/src/Tgstation.Server.Host/System/ProcessExecutor.cs b/src/Tgstation.Server.Host/System/ProcessExecutor.cs index ffe39218ba..6b035eb23a 100644 --- a/src/Tgstation.Server.Host/System/ProcessExecutor.cs +++ b/src/Tgstation.Server.Host/System/ProcessExecutor.cs @@ -1,10 +1,14 @@ using System; using System.IO; using System.Text; +using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Logging; +using Tgstation.Server.Host.Extensions; +using Tgstation.Server.Host.IO; + namespace Tgstation.Server.Host.System { /// @@ -15,6 +19,11 @@ namespace Tgstation.Server.Host.System /// readonly IProcessFeatures processFeatures; + /// + /// The for the . + /// + readonly IIOManager ioManager; + /// /// The for the . /// @@ -25,6 +34,150 @@ namespace Tgstation.Server.Host.System /// readonly ILoggerFactory loggerFactory; + /// + /// Initializes a new instance of the class. + /// + /// The value of . + /// The value of . + /// The value of . + /// The value of . + public ProcessExecutor( + IProcessFeatures processFeatures, + IIOManager ioManager, + ILogger logger, + ILoggerFactory loggerFactory) + { + this.processFeatures = processFeatures ?? throw new ArgumentNullException(nameof(processFeatures)); + this.ioManager = ioManager ?? throw new ArgumentNullException(nameof(ioManager)); + this.logger = logger ?? throw new ArgumentNullException(nameof(logger)); + this.loggerFactory = loggerFactory ?? throw new ArgumentNullException(nameof(loggerFactory)); + } + + /// + public IProcess GetProcess(int id) + { + logger.LogDebug("Attaching to process {0}...", id); + global::System.Diagnostics.Process handle; + try + { + handle = global::System.Diagnostics.Process.GetProcessById(id); + } + catch (Exception e) + { + logger.LogDebug(e, "Unable to get process {0}!", id); + return null; + } + + return CreateFromExistingHandle(handle); + } + + /// + public IProcess GetCurrentProcess() + { + logger.LogTrace("Getting current process..."); + var handle = global::System.Diagnostics.Process.GetCurrentProcess(); + return CreateFromExistingHandle(handle); + } + + /// + public async Task LaunchProcess( + string fileName, + string workingDirectory, + string arguments, + string fileRedirect, + bool readStandardHandles, + bool noShellExecute) + { + if (fileName == null) + throw new ArgumentNullException(nameof(fileName)); + if (workingDirectory == null) + throw new ArgumentNullException(nameof(workingDirectory)); + if (arguments == null) + throw new ArgumentNullException(nameof(arguments)); + + if (!noShellExecute && readStandardHandles) + throw new InvalidOperationException("Requesting output/error reading requires noShellExecute to be true!"); + + logger.LogDebug( + "{0}aunching process in {1}: {2} {3}", + noShellExecute ? "L" : "Shell l", + workingDirectory, + fileName, + arguments); + var handle = new global::System.Diagnostics.Process(); + try + { + handle.StartInfo.FileName = fileName; + handle.StartInfo.Arguments = arguments; + handle.StartInfo.WorkingDirectory = workingDirectory; + + handle.StartInfo.UseShellExecute = !noShellExecute; + + var processStartTcs = new TaskCompletionSource(); + var lifetimeTaskTask = AttachExitHandlerBeforeLaunch(handle, processStartTcs.Task); + + Task readTask = null; + CancellationTokenSource disposeCts = null; + if (readStandardHandles) + { + handle.StartInfo.RedirectStandardOutput = true; + handle.StartInfo.RedirectStandardError = true; + + disposeCts = new CancellationTokenSource(); + readTask = ConsumeReaders(handle, processStartTcs.Task, fileRedirect, disposeCts.Token); + } + + try + { + handle.Start(); + + processStartTcs.SetResult(); + } + catch (Exception ex) + { + processStartTcs.SetException(ex); + throw; + } + + var process = new Process( + processFeatures, + handle, + disposeCts, + await lifetimeTaskTask, // won't block + readTask, + loggerFactory.CreateLogger(), + false); + + return process; + } + catch + { + handle.Dispose(); + throw; + } + } + + /// + public IProcess GetProcessByName(string name) + { + logger.LogTrace("GetProcessByName: {processName}...", name ?? throw new ArgumentNullException(nameof(name))); + var procs = global::System.Diagnostics.Process.GetProcessesByName(name); + global::System.Diagnostics.Process handle = null; + foreach (var proc in procs) + if (handle == null) + handle = proc; + else + { + logger.LogTrace("Disposing extra found PID: {pid}...", proc.Id); + proc.Dispose(); + } + + if (handle == null) + return null; + + return CreateFromExistingHandle(handle); + } + /// /// Wrapper for to safely provide the process ID. /// @@ -92,180 +245,81 @@ namespace Tgstation.Server.Host.System } /// - /// Initializes a new instance of the class. + /// Consume the stdout/stderr streams into a . /// - /// The value of . - /// The value of . - /// The value of . - public ProcessExecutor( - IProcessFeatures processFeatures, - ILogger logger, - ILoggerFactory loggerFactory) + /// The . + /// The that completes when starts. + /// The optional path to redirect the streams to. + /// The that triggers when the is disposed. + /// A resulting in the program's output/error text if is , otherwise. + async Task ConsumeReaders(global::System.Diagnostics.Process handle, Task startTask, string fileRedirect, CancellationToken disposeToken) { - this.processFeatures = processFeatures ?? throw new ArgumentNullException(nameof(processFeatures)); - this.logger = logger ?? throw new ArgumentNullException(nameof(logger)); - this.loggerFactory = loggerFactory ?? throw new ArgumentNullException(nameof(loggerFactory)); - } + await startTask; - /// - public IProcess GetProcess(int id) - { - logger.LogDebug("Attaching to process {0}...", id); - global::System.Diagnostics.Process handle; - try + var pid = handle.Id; + logger.LogTrace("Starting read for PID {pid}...", pid); + + var stdOutHandle = handle.StandardOutput; + var stdErrHandle = handle.StandardError; + Task outputReadTask = null, errorReadTask = null; + bool outputOpen = true, errorOpen = true; + async Task GetNextLine() { - handle = global::System.Diagnostics.Process.GetProcessById(id); - } - catch (Exception e) - { - logger.LogDebug(e, "Unable to get process {0}!", id); - return null; - } + if (outputOpen && outputReadTask == null) + outputReadTask = stdOutHandle.ReadLineAsync(); - return CreateFromExistingHandle(handle); - } + if (errorOpen && errorReadTask == null) + errorReadTask = stdErrHandle.ReadLineAsync(); - /// - public IProcess GetCurrentProcess() - { - logger.LogTrace("Getting current process..."); - var handle = global::System.Diagnostics.Process.GetCurrentProcess(); - return CreateFromExistingHandle(handle); - } - - /// - public IProcess LaunchProcess( - string fileName, - string workingDirectory, - string arguments, - bool readOutput, - bool readError, - bool noShellExecute) - { - if (fileName == null) - throw new ArgumentNullException(nameof(fileName)); - if (workingDirectory == null) - throw new ArgumentNullException(nameof(workingDirectory)); - if (arguments == null) - throw new ArgumentNullException(nameof(arguments)); - - if (!noShellExecute && (readOutput || readError)) - throw new InvalidOperationException("Requesting output/error reading requires noShellExecute to be true!"); - - logger.LogDebug( - "{0}aunching process in {1}: {2} {3}", - noShellExecute ? "L" : "Shell l", - workingDirectory, - fileName, - arguments); - var handle = new global::System.Diagnostics.Process(); - try - { - handle.StartInfo.FileName = fileName; - handle.StartInfo.Arguments = arguments; - handle.StartInfo.WorkingDirectory = workingDirectory; - - handle.StartInfo.UseShellExecute = !noShellExecute; - - StringBuilder combinedStringBuilder = null; - - Task outputTask = null; - Task errorTask = null; - var processStartTcs = new TaskCompletionSource(); - if (readOutput || readError) + var completedTask = await Task.WhenAny(outputReadTask ?? errorReadTask, errorReadTask ?? outputReadTask).WithToken(disposeToken); + var line = await completedTask; + if (completedTask == outputReadTask) { - combinedStringBuilder = new StringBuilder(); - - async Task ConsumeReader(Func readerFunc, bool isOutputStream) - { - var stringBuilder = new StringBuilder(); - string text; - - await processStartTcs.Task; - - var pid = handle.Id; - var streamType = isOutputStream ? "out" : "err"; - logger.LogTrace("Starting std{0} read for PID {1}...", streamType, pid); - - var reader = readerFunc(); - while ((text = await reader.ReadLineAsync()) != null) - { - combinedStringBuilder.AppendLine(); - combinedStringBuilder.Append(text); - stringBuilder.AppendLine(); - stringBuilder.Append(text); - } - - logger.LogTrace("Finished std{0} read for PID {1}", streamType, pid); - - return stringBuilder.ToString(); - } - - if (readOutput) - { - outputTask = ConsumeReader(() => handle.StandardOutput, true); - handle.StartInfo.RedirectStandardOutput = true; - } - - if (readError) - { - errorTask = ConsumeReader(() => handle.StandardError, false); - handle.StartInfo.RedirectStandardError = true; - } + outputReadTask = null; + if (line == null) + outputOpen = false; } - - var lifetimeTaskTask = AttachExitHandlerBeforeLaunch(handle, processStartTcs.Task); - - try - { - handle.Start(); - - processStartTcs.SetResult(null); - } - catch (Exception ex) - { - processStartTcs.SetException(ex); - throw; - } - - var process = new Process( - processFeatures, - handle, - lifetimeTaskTask.GetAwaiter().GetResult(), // won't block - outputTask, - errorTask, - combinedStringBuilder, - loggerFactory.CreateLogger(), - false); - - return process; - } - catch - { - handle.Dispose(); - throw; - } - } - - /// - public IProcess GetProcessByName(string name) - { - logger.LogTrace("GetProcessByName: {processName}...", name ?? throw new ArgumentNullException(nameof(name))); - var procs = global::System.Diagnostics.Process.GetProcessesByName(name); - global::System.Diagnostics.Process handle = null; - foreach (var proc in procs) - if (handle == null) - handle = proc; else { - logger.LogTrace("Disposing extra found PID: {pid}...", proc.Id); - proc.Dispose(); + errorReadTask = null; + if (line == null) + errorOpen = false; } - if (handle == null) - return null; + if (line == null && (errorOpen || outputOpen)) + return await GetNextLine(); - return CreateFromExistingHandle(handle); + return line; + } + + using var fileStream = fileRedirect != null ? ioManager.CreateAsyncWriteStream(fileRedirect) : null; + using var writer = fileStream != null ? new StreamWriter(fileStream) : null; + + string text; + var stringBuilder = fileStream == null ? new StringBuilder() : null; + try + { + while ((text = await GetNextLine()) != null) + { + if (fileStream != null) + { + await writer.WriteLineAsync(text); + await writer.FlushAsync(); + } + else + stringBuilder.AppendLine(text); + } + + logger.LogTrace("Finished read for PID {pid}", pid); + } + catch (OperationCanceledException ex) + { + logger.LogWarning(ex, "PID {pid} stream reading interrupted!", pid); + if (fileStream != null) + await writer.WriteLineAsync("-- Process detached, log truncated. This is likely due a to TGS restart --"); + } + + return stringBuilder?.ToString(); } /// @@ -273,7 +327,7 @@ namespace Tgstation.Server.Host.System /// /// The to create a from. /// The based on . - private IProcess CreateFromExistingHandle(global::System.Diagnostics.Process handle) + IProcess CreateFromExistingHandle(global::System.Diagnostics.Process handle) { try { @@ -281,10 +335,9 @@ namespace Tgstation.Server.Host.System return new Process( processFeatures, handle, + null, AttachExitHandler(handle, () => pid), null, - null, - null, loggerFactory.CreateLogger(), true); } diff --git a/tests/Tgstation.Server.Host.Tests/System/TestPosixSignalHandler.cs b/tests/Tgstation.Server.Host.Tests/System/TestPosixSignalHandler.cs index c816b44041..382e060f72 100644 --- a/tests/Tgstation.Server.Host.Tests/System/TestPosixSignalHandler.cs +++ b/tests/Tgstation.Server.Host.Tests/System/TestPosixSignalHandler.cs @@ -59,14 +59,15 @@ namespace Tgstation.Server.Host.System.Tests new Lazy(() => processExecutor), new DefaultIOManager(new AssemblyInformationProvider()), loggerFactory.CreateLogger()), + Mock.Of(), loggerFactory.CreateLogger(), loggerFactory); - using var subProc = processExecutor + await using var subProc = await processExecutor .LaunchProcess( "dotnet", pathToSignalTestApp, $"run -c {CurrentConfig} --no-build", - true, + null, true, true); diff --git a/tests/Tgstation.Server.Tests/Instance/WatchdogTest.cs b/tests/Tgstation.Server.Tests/Instance/WatchdogTest.cs index f74d82ad5c..6fd138d17d 100644 --- a/tests/Tgstation.Server.Tests/Instance/WatchdogTest.cs +++ b/tests/Tgstation.Server.Tests/Instance/WatchdogTest.cs @@ -230,11 +230,12 @@ namespace Tgstation.Server.Tests.Instance IProcessExecutor executor = null; executor = new ProcessExecutor( RuntimeInformation.IsOSPlatform(OSPlatform.Windows) - ? (IProcessFeatures)new WindowsProcessFeatures(Mock.Of>()) + ? new WindowsProcessFeatures(Mock.Of>()) : new PosixProcessFeatures(new Lazy(() => executor), Mock.Of(), Mock.Of>()), + Mock.Of(), Mock.Of>(), LoggerFactory.Create(x => { })); - using var ourProcessHandler = executor + await using var ourProcessHandler = executor .GetProcess(ddProc.Id); // Ensure it's responding to heartbeats diff --git a/tests/Tgstation.Server.Tests/IntegrationTest.cs b/tests/Tgstation.Server.Tests/IntegrationTest.cs index 592d6da6a6..87bac80011 100644 --- a/tests/Tgstation.Server.Tests/IntegrationTest.cs +++ b/tests/Tgstation.Server.Tests/IntegrationTest.cs @@ -32,6 +32,7 @@ using Tgstation.Server.Host.Configuration; using Tgstation.Server.Host.Database; using Tgstation.Server.Host.Database.Migrations; using Tgstation.Server.Host.Extensions; +using Tgstation.Server.Host.IO; using Tgstation.Server.Host.Jobs; using Tgstation.Server.Host.System; using Tgstation.Server.Tests.Instance; @@ -627,7 +628,7 @@ namespace Tgstation.Server.Tests { try { - Console.WriteLine($"TEST: CreateAdminClient attempt {I}..."); + System.Console.WriteLine($"TEST: CreateAdminClient attempt {I}..."); return await clientFactory.CreateFromLogin( url, DefaultCredentials.AdminUserName, @@ -856,7 +857,7 @@ namespace Tgstation.Server.Tests } catch (Exception ex) { - Console.WriteLine($"[{DateTimeOffset.UtcNow}] TEST ERROR: {ex}"); + System.Console.WriteLine($"[{DateTimeOffset.UtcNow}] TEST ERROR: {ex}"); serverCts.Cancel(); throw; } @@ -991,12 +992,12 @@ namespace Tgstation.Server.Tests } catch (ApiException ex) { - Console.WriteLine($"[{DateTimeOffset.UtcNow}] TEST ERROR: {ex.ErrorCode}: {ex.Message}\n{ex.AdditionalServerData}"); + System.Console.WriteLine($"[{DateTimeOffset.UtcNow}] TEST ERROR: {ex.ErrorCode}: {ex.Message}\n{ex.AdditionalServerData}"); throw; } catch (Exception ex) { - Console.WriteLine($"[{DateTimeOffset.UtcNow}] TEST ERROR: {ex}"); + System.Console.WriteLine($"[{DateTimeOffset.UtcNow}] TEST ERROR: {ex}"); throw; } finally @@ -1048,17 +1049,17 @@ namespace Tgstation.Server.Tests var platformIdentifier = new PlatformIdentifier(); var processExecutor = new ProcessExecutor( Mock.Of(), + Mock.Of(), Mock.Of>(), LoggerFactory.Create(x => { })); - using var process = processExecutor.LaunchProcess("test." + platformIdentifier.ScriptFileExtension, ".", String.Empty, true, true, true); + await using var process = await processExecutor.LaunchProcess("test." + platformIdentifier.ScriptFileExtension, ".", String.Empty, null, true, true); using var cts = new CancellationTokenSource(); cts.CancelAfter(3000); var exitCode = await process.Lifetime.WithToken(cts.Token); Assert.AreEqual(0, exitCode); - Assert.AreEqual(String.Empty, (await process.GetErrorOutput(default)).Trim()); - Assert.AreEqual("Hello World!", (await process.GetStandardOutput(default)).Trim()); + Assert.AreEqual("Hello World!", (await process.GetCombinedOutput(default)).Trim()); } [TestMethod]