mirror of
https://github.com/tgstation/tgstation-server.git
synced 2026-08-23 04:57:17 +01:00
Merge pull request #1787 from tgstation/v620 [TGSDeploy]
v6.2.0 Release
This commit is contained in:
@@ -539,7 +539,11 @@ Manual operations on the repository while an instance is running may lead to git
|
||||
|
||||
#### Byond
|
||||
|
||||
The `Byond` folder contains installations of [BYOND](https://www.byond.com/) versions. The version which is used by your game code can be changed on a whim (Note that only versions >= 511.1385 have been thouroughly tested. Lower versions should work but if one doesn't function, please open an issue report) and the server will take care of installing it.
|
||||
The `Byond` folder contains installations of [BYOND](https://www.byond.com/) or [OpenDream](https://github.com/OpenDreamProject/OpenDream) versions. The version which is used by your game code can be changed on a whim (Note that only versions >= 511.1385 have been thouroughly tested. Lower versions should work but if one doesn't function, please open an issue report) and the server will take care of installing it.
|
||||
|
||||
##### Environment Variables
|
||||
|
||||
You can specify additional environment variables to launch your server/compiler with by adding `server.env`/`compiler.env` to your engine installation directory (i.e. `<instance>/Byond/515.1530/server.env`). These are [.env](https://hexdocs.pm/dotenvy/dotenv-file-format.html) files.
|
||||
|
||||
#### Compiler
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
|
||||
<ItemGroup>
|
||||
<!-- Usage: Linting -->
|
||||
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.507">
|
||||
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.556">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
|
||||
@@ -18,9 +18,9 @@
|
||||
<!-- Pinned: Be VERY careful about updating https://github.com/moq/moq/issues/1372 -->
|
||||
<PackageReference Include="Moq" Version="4.20.70" />
|
||||
<!-- Usage: MSTest execution -->
|
||||
<PackageReference Include="MSTest.TestAdapter" Version="3.1.1" />
|
||||
<PackageReference Include="MSTest.TestAdapter" Version="3.2.0" />
|
||||
<!-- Usage: MSTest asserts etc... -->
|
||||
<PackageReference Include="MSTest.TestFramework" Version="3.1.1" />
|
||||
<PackageReference Include="MSTest.TestFramework" Version="3.2.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
+6
-6
@@ -3,13 +3,13 @@
|
||||
<!-- Integration tests will ensure they match across the board -->
|
||||
<Import Project="WebpanelVersion.props" />
|
||||
<PropertyGroup>
|
||||
<TgsCoreVersion>6.1.5</TgsCoreVersion>
|
||||
<TgsConfigVersion>5.0.0</TgsConfigVersion>
|
||||
<TgsApiVersion>10.0.0</TgsApiVersion>
|
||||
<TgsCoreVersion>6.2.0</TgsCoreVersion>
|
||||
<TgsConfigVersion>5.1.0</TgsConfigVersion>
|
||||
<TgsApiVersion>10.1.0</TgsApiVersion>
|
||||
<TgsCommonLibraryVersion>7.0.0</TgsCommonLibraryVersion>
|
||||
<TgsApiLibraryVersion>13.0.1</TgsApiLibraryVersion>
|
||||
<TgsClientVersion>15.0.1</TgsClientVersion>
|
||||
<TgsDmapiVersion>7.0.1</TgsDmapiVersion>
|
||||
<TgsApiLibraryVersion>13.1.0</TgsApiLibraryVersion>
|
||||
<TgsClientVersion>15.1.0</TgsClientVersion>
|
||||
<TgsDmapiVersion>7.0.2</TgsDmapiVersion>
|
||||
<TgsInteropVersion>5.8.0</TgsInteropVersion>
|
||||
<TgsHostWatchdogVersion>1.4.1</TgsHostWatchdogVersion>
|
||||
<TgsContainerScriptVersion>1.2.1</TgsContainerScriptVersion>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<!-- This is in it's own file to help incremental building, changing it causes a complete rebuild of the web panel -->
|
||||
<TgsWebpanelVersion>5.4.2</TgsWebpanelVersion>
|
||||
<TgsWebpanelVersion>5.5.0</TgsWebpanelVersion>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
|
||||
+4
-1
@@ -1,6 +1,6 @@
|
||||
// tgstation-server DMAPI
|
||||
|
||||
#define TGS_DMAPI_VERSION "7.0.1"
|
||||
#define TGS_DMAPI_VERSION "7.0.2"
|
||||
|
||||
// All functions and datums outside this document are subject to change with any version and should not be relied on.
|
||||
|
||||
@@ -426,6 +426,7 @@
|
||||
|
||||
/**
|
||||
* Send a message to connected chats. This function may sleep!
|
||||
* If TGS is offline when called, the message may be placed in a queue to be sent and this function will return immediately. Your message will be sent when TGS reconnects to the game.
|
||||
*
|
||||
* message - The [/datum/tgs_message_content] to send.
|
||||
* admin_only: If [TRUE], message will be sent to admin connected chats. Vice-versa applies.
|
||||
@@ -435,6 +436,7 @@
|
||||
|
||||
/**
|
||||
* Send a private message to a specific user. This function may sleep!
|
||||
* If TGS is offline when called, the message may be placed in a queue to be sent and this function will return immediately. Your message will be sent when TGS reconnects to the game.
|
||||
*
|
||||
* message - The [/datum/tgs_message_content] to send.
|
||||
* user: The [/datum/tgs_chat_user] to PM.
|
||||
@@ -444,6 +446,7 @@
|
||||
|
||||
/**
|
||||
* Send a message to connected chats that are flagged as game-related in TGS. This function may sleep!
|
||||
* If TGS is offline when called, the message may be placed in a queue to be sent and this function will return immediately. Your message will be sent when TGS reconnects to the game.
|
||||
*
|
||||
* message - The [/datum/tgs_message_content] to send.
|
||||
* channels - Optional list of [/datum/tgs_chat_channel]s to restrict the message to.
|
||||
|
||||
+32
-22
@@ -8,8 +8,12 @@
|
||||
|
||||
var/reboot_mode = TGS_REBOOT_MODE_NORMAL
|
||||
|
||||
/// List of chat messages list()s that attempted to be sent during a topic call. To be bundled in the result of the call
|
||||
var/list/intercepted_message_queue
|
||||
|
||||
/// List of chat messages list()s that attempted to be sent during a topic call. To be bundled in the result of the call
|
||||
var/list/offline_message_queue
|
||||
|
||||
var/list/custom_commands
|
||||
|
||||
var/list/test_merges
|
||||
@@ -194,17 +198,7 @@
|
||||
var/datum/tgs_chat_channel/channel = I
|
||||
ids += channel.id
|
||||
|
||||
message2 = UpgradeDeprecatedChatMessage(message2)
|
||||
|
||||
if (!length(channels))
|
||||
return
|
||||
|
||||
var/list/data = message2._interop_serialize()
|
||||
data[DMAPI5_CHAT_MESSAGE_CHANNEL_IDS] = ids
|
||||
if(intercepted_message_queue)
|
||||
intercepted_message_queue += list(data)
|
||||
else
|
||||
Bridge(DMAPI5_BRIDGE_COMMAND_CHAT_SEND, list(DMAPI5_BRIDGE_PARAMETER_CHAT_MESSAGE = data))
|
||||
SendChatMessageRaw(message2, ids)
|
||||
|
||||
/datum/tgs_api/v5/ChatTargetedBroadcast(datum/tgs_message_content/message2, admin_only)
|
||||
var/list/channels = list()
|
||||
@@ -213,26 +207,42 @@
|
||||
if (!channel.is_private_channel && ((channel.is_admin_channel && admin_only) || (!channel.is_admin_channel && !admin_only)))
|
||||
channels += channel.id
|
||||
|
||||
SendChatMessageRaw(message2, channels)
|
||||
|
||||
/datum/tgs_api/v5/ChatPrivateMessage(datum/tgs_message_content/message2, datum/tgs_chat_user/user)
|
||||
SendChatMessageRaw(message2, list(user.channel.id))
|
||||
|
||||
/datum/tgs_api/v5/proc/SendChatMessageRaw(datum/tgs_message_content/message2, list/channel_ids)
|
||||
message2 = UpgradeDeprecatedChatMessage(message2)
|
||||
|
||||
if (!length(channels))
|
||||
if (!length(channel_ids))
|
||||
return
|
||||
|
||||
var/list/data = message2._interop_serialize()
|
||||
data[DMAPI5_CHAT_MESSAGE_CHANNEL_IDS] = channels
|
||||
data[DMAPI5_CHAT_MESSAGE_CHANNEL_IDS] = channel_ids
|
||||
if(intercepted_message_queue)
|
||||
intercepted_message_queue += list(data)
|
||||
else
|
||||
Bridge(DMAPI5_BRIDGE_COMMAND_CHAT_SEND, list(DMAPI5_BRIDGE_PARAMETER_CHAT_MESSAGE = data))
|
||||
return
|
||||
|
||||
/datum/tgs_api/v5/ChatPrivateMessage(datum/tgs_message_content/message2, datum/tgs_chat_user/user)
|
||||
message2 = UpgradeDeprecatedChatMessage(message2)
|
||||
var/list/data = message2._interop_serialize()
|
||||
data[DMAPI5_CHAT_MESSAGE_CHANNEL_IDS] = list(user.channel.id)
|
||||
if(intercepted_message_queue)
|
||||
intercepted_message_queue += list(data)
|
||||
if(offline_message_queue)
|
||||
offline_message_queue += list(data)
|
||||
return
|
||||
|
||||
if(detached)
|
||||
offline_message_queue = list(data)
|
||||
|
||||
WaitForReattach(FALSE)
|
||||
|
||||
data = offline_message_queue
|
||||
offline_message_queue = null
|
||||
|
||||
for(var/queued_message in data)
|
||||
SendChatDataRaw(queued_message)
|
||||
else
|
||||
Bridge(DMAPI5_BRIDGE_COMMAND_CHAT_SEND, list(DMAPI5_BRIDGE_PARAMETER_CHAT_MESSAGE = data))
|
||||
SendChatDataRaw(data)
|
||||
|
||||
/datum/tgs_api/v5/proc/SendChatDataRaw(list/data)
|
||||
Bridge(DMAPI5_BRIDGE_COMMAND_CHAT_SEND, list(DMAPI5_BRIDGE_PARAMETER_CHAT_MESSAGE = data))
|
||||
|
||||
/datum/tgs_api/v5/ChatChannelInfo()
|
||||
RequireInitialBridgeResponse()
|
||||
|
||||
@@ -98,6 +98,13 @@ namespace Tgstation.Server.Api.Models.Internal
|
||||
[ResponseOptions]
|
||||
public uint? MapThreads { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// If minidumps should be taken instead of full dumps.
|
||||
/// </summary>
|
||||
[Required]
|
||||
[ResponseOptions]
|
||||
public bool? Minidumps { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Check if we match a given set of <paramref name="otherParameters"/>. <see cref="StartupTimeout"/> is excluded.
|
||||
/// </summary>
|
||||
@@ -116,7 +123,7 @@ namespace Tgstation.Server.Api.Models.Internal
|
||||
&& AdditionalParameters == otherParameters.AdditionalParameters
|
||||
&& StartProfiler == otherParameters.StartProfiler
|
||||
&& LogOutput == otherParameters.LogOutput
|
||||
&& MapThreads == otherParameters.MapThreads; // We intentionally don't check StartupTimeout, health check seconds, or health check dump as they don't matter in terms of the watchdog
|
||||
&& MapThreads == otherParameters.MapThreads; // We intentionally don't check StartupTimeout, Minidumps, health check seconds, or health check dump as they don't matter in terms of the watchdog
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -117,5 +117,10 @@ namespace Tgstation.Server.Api.Rights
|
||||
/// User can use <see cref="Models.Request.DreamDaemonRequest.BroadcastMessage"/>.
|
||||
/// </summary>
|
||||
BroadcastMessage = 1 << 20,
|
||||
|
||||
/// <summary>
|
||||
/// User can use <see cref="Models.Internal.DreamDaemonLaunchParameters.Minidumps"/>.
|
||||
/// </summary>
|
||||
SetMinidumps = 1 << 21,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
<!-- Usage: HTTP constants reference -->
|
||||
<PackageReference Include="Microsoft.AspNetCore.Http.Extensions" Version="2.2.0" />
|
||||
<!-- Usage: Decoding the 'nbf' property of JWTs -->
|
||||
<PackageReference Include="Microsoft.IdentityModel.JsonWebTokens" Version="7.1.2" />
|
||||
<PackageReference Include="Microsoft.IdentityModel.JsonWebTokens" Version="7.3.0" />
|
||||
<!-- Usage: Primary JSON library -->
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
<!-- Usage: Data model annotating -->
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"isRoot": true,
|
||||
"tools": {
|
||||
"dotnet-ef": {
|
||||
"version": "8.0.0",
|
||||
"version": "8.0.1",
|
||||
"commands": [
|
||||
"dotnet-ef"
|
||||
]
|
||||
|
||||
@@ -852,6 +852,7 @@ namespace Tgstation.Server.Host.Components.Deployment
|
||||
/// <returns>A <see cref="ValueTask{TResult}"/> resulting in <see langword="true"/> if compilation succeeded, <see langword="false"/> otherwise.</returns>
|
||||
async ValueTask<bool> RunDreamMaker(IEngineExecutableLock engineLock, Models.CompileJob job, CancellationToken cancellationToken)
|
||||
{
|
||||
var environment = await engineLock.LoadEnv(logger, true, cancellationToken);
|
||||
var arguments = engineLock.FormatCompilerArguments($"{job.DmeName}.{DmeExtension}");
|
||||
|
||||
await using var dm = processExecutor.LaunchProcess(
|
||||
@@ -859,6 +860,7 @@ namespace Tgstation.Server.Host.Components.Deployment
|
||||
ioManager.ResolvePath(
|
||||
job.DirectoryName!.Value.ToString()),
|
||||
arguments,
|
||||
environment,
|
||||
readStandardHandles: true,
|
||||
noShellExecute: true);
|
||||
|
||||
@@ -953,6 +955,12 @@ namespace Tgstation.Server.Host.Components.Deployment
|
||||
{
|
||||
async ValueTask CleanDir()
|
||||
{
|
||||
if (sessionConfiguration.DelayCleaningFailedDeployments)
|
||||
{
|
||||
logger.LogDebug("Not cleaning up errored deployment directory {guid} due to config.", job.DirectoryName);
|
||||
return;
|
||||
}
|
||||
|
||||
logger.LogTrace("Cleaning compile directory...");
|
||||
var jobPath = job.DirectoryName!.Value.ToString();
|
||||
try
|
||||
|
||||
@@ -6,6 +6,7 @@ using System.Threading.Tasks;
|
||||
using Tgstation.Server.Api.Models;
|
||||
using Tgstation.Server.Api.Models.Internal;
|
||||
using Tgstation.Server.Host.Components.Deployment;
|
||||
using Tgstation.Server.Host.IO;
|
||||
|
||||
namespace Tgstation.Server.Host.Components.Engine
|
||||
{
|
||||
@@ -32,6 +33,9 @@ namespace Tgstation.Server.Host.Components.Engine
|
||||
/// <inheritdoc />
|
||||
public override bool PreferFileLogging => false;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool UseDotnetDump => false;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override Task InstallationTask { get; }
|
||||
|
||||
@@ -75,6 +79,7 @@ namespace Tgstation.Server.Host.Components.Engine
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ByondInstallation"/> class.
|
||||
/// </summary>
|
||||
/// <param name="installationIOManager">The <see cref="IIOManager"/> for the <see cref="EngineInstallationBase"/>.</param>
|
||||
/// <param name="installationTask">The value of <see cref="InstallationTask"/>.</param>
|
||||
/// <param name="version">The value of <see cref="Version"/>.</param>
|
||||
/// <param name="dreamDaemonPath">The value of <see cref="ServerExePath"/>.</param>
|
||||
@@ -82,12 +87,14 @@ namespace Tgstation.Server.Host.Components.Engine
|
||||
/// <param name="supportsCli">If a CLI application is being used.</param>
|
||||
/// <param name="supportsMapThreads">The value of <see cref="supportsMapThreads"/>.</param>
|
||||
public ByondInstallation(
|
||||
IIOManager installationIOManager,
|
||||
Task installationTask,
|
||||
EngineVersion version,
|
||||
string dreamDaemonPath,
|
||||
string dreamMakerPath,
|
||||
bool supportsCli,
|
||||
bool supportsMapThreads)
|
||||
: base(installationIOManager)
|
||||
{
|
||||
InstallationTask = installationTask ?? throw new ArgumentNullException(nameof(installationTask));
|
||||
ArgumentNullException.ThrowIfNull(version);
|
||||
|
||||
@@ -88,21 +88,22 @@ namespace Tgstation.Server.Host.Components.Engine
|
||||
{
|
||||
CheckVersionValidity(version);
|
||||
|
||||
var binPathForVersion = IOManager.ConcatPath(path, ByondBinPath);
|
||||
var installationIOManager = new ResolvingIOManager(IOManager, path);
|
||||
var supportsMapThreads = version.Version >= MapThreadsVersion;
|
||||
|
||||
return new ByondInstallation(
|
||||
installationIOManager,
|
||||
installationTask,
|
||||
version,
|
||||
IOManager.ResolvePath(
|
||||
IOManager.ConcatPath(
|
||||
binPathForVersion,
|
||||
installationIOManager.ResolvePath(
|
||||
installationIOManager.ConcatPath(
|
||||
ByondBinPath,
|
||||
GetDreamDaemonName(
|
||||
version.Version!,
|
||||
out var supportsCli))),
|
||||
IOManager.ResolvePath(
|
||||
IOManager.ConcatPath(
|
||||
binPathForVersion,
|
||||
installationIOManager.ResolvePath(
|
||||
installationIOManager.ConcatPath(
|
||||
ByondBinPath,
|
||||
DreamMakerName)),
|
||||
supportsCli,
|
||||
supportsMapThreads);
|
||||
|
||||
@@ -41,8 +41,8 @@ namespace Tgstation.Server.Host.Components.Engine
|
||||
=> DelegateCall(version, installer => installer.DownloadVersion(version, jobProgressReporter, cancellationToken));
|
||||
|
||||
/// <inheritdoc />
|
||||
public ValueTask Install(EngineVersion version, string path, CancellationToken cancellationToken)
|
||||
=> DelegateCall(version, installer => installer.Install(version, path, cancellationToken));
|
||||
public ValueTask Install(EngineVersion version, string path, bool deploymentPipelineProcesses, CancellationToken cancellationToken)
|
||||
=> DelegateCall(version, installer => installer.Install(version, path, deploymentPipelineProcesses, cancellationToken));
|
||||
|
||||
/// <inheritdoc />
|
||||
public ValueTask TrustDmbPath(EngineVersion version, string fullDmbPath, CancellationToken cancellationToken)
|
||||
|
||||
@@ -36,6 +36,9 @@ namespace Tgstation.Server.Host.Components.Engine
|
||||
/// <inheritdoc />
|
||||
public Task InstallationTask => Instance.InstallationTask;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool UseDotnetDump => Instance.UseDotnetDump;
|
||||
|
||||
/// <inheritdoc />
|
||||
public void DoNotDeleteThisSession() => DangerousDropReference();
|
||||
|
||||
@@ -62,5 +65,9 @@ namespace Tgstation.Server.Host.Components.Engine
|
||||
accessIdentifier,
|
||||
port,
|
||||
cancellationToken);
|
||||
|
||||
/// <inheritdoc />
|
||||
public ValueTask<Dictionary<string, string>?> LoadEnv(ILogger logger, bool forCompiler, CancellationToken cancellationToken)
|
||||
=> Instance.LoadEnv(logger, forCompiler, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +1,19 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web;
|
||||
|
||||
using DotEnv.Core;
|
||||
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
using Tgstation.Server.Api.Models;
|
||||
using Tgstation.Server.Api.Models.Internal;
|
||||
using Tgstation.Server.Host.Components.Deployment;
|
||||
using Tgstation.Server.Host.IO;
|
||||
using Tgstation.Server.Host.System;
|
||||
|
||||
namespace Tgstation.Server.Host.Components.Engine
|
||||
@@ -35,9 +39,17 @@ namespace Tgstation.Server.Host.Components.Engine
|
||||
/// <inheritdoc />
|
||||
public abstract bool PromptsForNetworkAccess { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public abstract bool UseDotnetDump { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public abstract Task InstallationTask { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="IIOManager"/> pointing to the installation directory.
|
||||
/// </summary>
|
||||
protected IIOManager InstallationIOManager { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Encode given parameters for passing as world.params on the command line.
|
||||
/// </summary>
|
||||
@@ -56,6 +68,15 @@ namespace Tgstation.Server.Host.Components.Engine
|
||||
return parametersString;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="EngineInstallationBase"/> class.
|
||||
/// </summary>
|
||||
/// <param name="installationIOManager">The value of <see cref="InstallationIOManager"/>.</param>
|
||||
public EngineInstallationBase(IIOManager installationIOManager)
|
||||
{
|
||||
InstallationIOManager = installationIOManager ?? throw new ArgumentNullException(nameof(installationIOManager));
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public abstract string FormatCompilerArguments(string dmePath);
|
||||
|
||||
@@ -69,10 +90,45 @@ namespace Tgstation.Server.Host.Components.Engine
|
||||
/// <inheritdoc />
|
||||
public virtual async ValueTask StopServerProcess(ILogger logger, IProcess process, string accessIdentifier, ushort port, CancellationToken cancellationToken)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(logger);
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
logger.LogTrace("Terminating engine server process...");
|
||||
process.Terminate();
|
||||
await process.Lifetime;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async ValueTask<Dictionary<string, string>?> LoadEnv(ILogger logger, bool forCompiler, CancellationToken cancellationToken)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(logger);
|
||||
|
||||
var envFile = forCompiler
|
||||
? "compiler.env"
|
||||
: "server.env";
|
||||
|
||||
if (!await InstallationIOManager.FileExists(envFile, cancellationToken))
|
||||
{
|
||||
logger.LogTrace("No {envFile} present in engine installation {version}", envFile, Version);
|
||||
return null;
|
||||
}
|
||||
|
||||
logger.LogDebug("Loading {envFile} for engine installation {version}...", envFile, Version);
|
||||
|
||||
var fileBytes = await InstallationIOManager.ReadAllBytes(envFile, cancellationToken);
|
||||
var fileContents = Encoding.UTF8.GetString(fileBytes);
|
||||
var parser = new EnvParser();
|
||||
|
||||
try
|
||||
{
|
||||
var variables = parser.Parse(fileContents);
|
||||
|
||||
return variables.ToDictionary();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.LogWarning(ex, "Unable to parse {envFile}!", envFile);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ namespace Tgstation.Server.Host.Components.Engine
|
||||
public abstract Task CleanCache(CancellationToken cancellationToken);
|
||||
|
||||
/// <inheritdoc />
|
||||
public abstract ValueTask Install(EngineVersion version, string path, CancellationToken cancellationToken);
|
||||
public abstract ValueTask Install(EngineVersion version, string path, bool deploymentPipelineProcesses, CancellationToken cancellationToken);
|
||||
|
||||
/// <inheritdoc />
|
||||
public abstract ValueTask UpgradeInstallation(EngineVersion version, string path, CancellationToken cancellationToken);
|
||||
|
||||
@@ -438,6 +438,7 @@ namespace Tgstation.Server.Host.Components.Engine
|
||||
installLock = installationContainer.AddReference();
|
||||
}
|
||||
|
||||
var deploymentPipelineProcesses = !neededForLock;
|
||||
try
|
||||
{
|
||||
if (installedOrInstalling)
|
||||
@@ -471,18 +472,18 @@ namespace Tgstation.Server.Host.Components.Engine
|
||||
progressReporter.StageName = "Running event";
|
||||
|
||||
var versionString = version.ToString();
|
||||
await eventConsumer.HandleEvent(EventType.EngineInstallStart, new List<string> { versionString }, false, cancellationToken);
|
||||
await eventConsumer.HandleEvent(EventType.EngineInstallStart, new List<string> { versionString }, deploymentPipelineProcesses, cancellationToken);
|
||||
|
||||
await InstallVersionFiles(progressReporter, version, customVersionStream, cancellationToken);
|
||||
await InstallVersionFiles(progressReporter, version, customVersionStream, deploymentPipelineProcesses, cancellationToken);
|
||||
|
||||
ourTcs.SetResult();
|
||||
|
||||
await eventConsumer.HandleEvent(EventType.EngineInstallComplete, new List<string> { versionString }, false, cancellationToken);
|
||||
await eventConsumer.HandleEvent(EventType.EngineInstallComplete, new List<string> { versionString }, deploymentPipelineProcesses, cancellationToken);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (ex is not OperationCanceledException)
|
||||
await eventConsumer.HandleEvent(EventType.EngineInstallFail, new List<string> { ex.Message }, false, cancellationToken);
|
||||
await eventConsumer.HandleEvent(EventType.EngineInstallFail, new List<string> { ex.Message }, deploymentPipelineProcesses, cancellationToken);
|
||||
|
||||
lock (installedVersions)
|
||||
installedVersions.Remove(version);
|
||||
@@ -506,9 +507,15 @@ namespace Tgstation.Server.Host.Components.Engine
|
||||
/// <param name="progressReporter">The optional <see cref="JobProgressReporter"/> for the operation.</param>
|
||||
/// <param name="version">The <see cref="EngineVersion"/> being installed with the <see cref="Version.Build"/> number set if appropriate.</param>
|
||||
/// <param name="customVersionStream">Custom zip file <see cref="Stream"/> to use. Will cause a <see cref="Version.Build"/> number to be added.</param>
|
||||
/// <param name="deploymentPipelineProcesses">If processes should be launched as part of the deployment pipeline.</param>
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation.</param>
|
||||
/// <returns>A <see cref="ValueTask"/> representing the running operation.</returns>
|
||||
async ValueTask InstallVersionFiles(JobProgressReporter? progressReporter, EngineVersion version, Stream? customVersionStream, CancellationToken cancellationToken)
|
||||
async ValueTask InstallVersionFiles(
|
||||
JobProgressReporter? progressReporter,
|
||||
EngineVersion version,
|
||||
Stream? customVersionStream,
|
||||
bool deploymentPipelineProcesses,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var installFullPath = ioManager.ResolvePath(version.ToString());
|
||||
async ValueTask DirectoryCleanup()
|
||||
@@ -554,7 +561,7 @@ namespace Tgstation.Server.Host.Components.Engine
|
||||
if (progressReporter != null)
|
||||
progressReporter.StageName = "Running installation actions";
|
||||
|
||||
await engineInstaller.Install(version, installFullPath, cancellationToken);
|
||||
await engineInstaller.Install(version, installFullPath, deploymentPipelineProcesses, cancellationToken);
|
||||
|
||||
if (progressReporter != null)
|
||||
progressReporter.StageName = "Writing version file";
|
||||
|
||||
@@ -46,6 +46,11 @@ namespace Tgstation.Server.Host.Components.Engine
|
||||
/// </summary>
|
||||
bool PreferFileLogging { get; }
|
||||
|
||||
/// <summary>
|
||||
/// If dotnet-dump should be used to create process dumps for this installation.
|
||||
/// </summary>
|
||||
bool UseDotnetDump { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="Task"/> that completes when the BYOND version finished installing.
|
||||
/// </summary>
|
||||
@@ -82,5 +87,14 @@ namespace Tgstation.Server.Host.Components.Engine
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation.</param>
|
||||
/// <returns>A <see cref="ValueTask"/> representing the running operation.</returns>
|
||||
ValueTask StopServerProcess(ILogger logger, IProcess process, string accessIdentifier, ushort port, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Loads the environment settings for either the server or compiler.
|
||||
/// </summary>
|
||||
/// <param name="logger">The <see cref="ILogger"/> to write to.</param>
|
||||
/// <param name="forCompiler">If <see langword="false"/> server.env will be loaded. If <see langword="true"/> compiler.env will be loaded.</param>
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation.</param>
|
||||
/// <returns>A <see cref="ValueTask{TResult}"/> resulting in the environment <see cref="Dictionary{TKey, TValue}"/> or <see langword="null"/> if the target environment file doesn't exist.</returns>
|
||||
ValueTask<Dictionary<string, string>?> LoadEnv(ILogger logger, bool forCompiler, CancellationToken cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,9 +34,10 @@ namespace Tgstation.Server.Host.Components.Engine
|
||||
/// </summary>
|
||||
/// <param name="version">The <see cref="EngineVersion"/> being installed.</param>
|
||||
/// <param name="path">The path to the installation.</param>
|
||||
/// <param name="deploymentPipelineProcesses">If the operation should consider processes it launches to be part of the deployment pipeline.</param>
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation.</param>
|
||||
/// <returns>A <see cref="ValueTask"/> representing the running operation.</returns>
|
||||
ValueTask Install(EngineVersion version, string path, CancellationToken cancellationToken);
|
||||
ValueTask Install(EngineVersion version, string path, bool deploymentPipelineProcesses, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Does actions necessary to get upgrade a version installed by a previous version of TGS.
|
||||
|
||||
@@ -45,12 +45,10 @@ namespace Tgstation.Server.Host.Components.Engine
|
||||
public override bool PreferFileLogging => true;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override Task InstallationTask { get; }
|
||||
public override bool UseDotnetDump => true;
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="IIOManager"/> for the <see cref="OpenDreamInstallation"/>.
|
||||
/// </summary>
|
||||
readonly IIOManager ioManager;
|
||||
/// <inheritdoc />
|
||||
public override Task InstallationTask { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="IAsyncDelayer"/> for the <see cref="OpenDreamInstallation"/>.
|
||||
@@ -65,7 +63,7 @@ namespace Tgstation.Server.Host.Components.Engine
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="OpenDreamInstallation"/> class.
|
||||
/// </summary>
|
||||
/// <param name="ioManager">The value of <see cref="ioManager"/>.</param>
|
||||
/// <param name="installationIOManager">The <see cref="IIOManager"/> for the <see cref="EngineInstallationBase"/>.</param>
|
||||
/// <param name="asyncDelayer">The value of <see cref="asyncDelayer"/>.</param>
|
||||
/// <param name="httpClientFactory">The value of <see cref="httpClientFactory"/>.</param>
|
||||
/// <param name="serverExePath">The value of <see cref="ServerExePath"/>.</param>
|
||||
@@ -73,15 +71,15 @@ namespace Tgstation.Server.Host.Components.Engine
|
||||
/// <param name="installationTask">The value of <see cref="InstallationTask"/>.</param>
|
||||
/// <param name="version">The value of <see cref="Version"/>.</param>
|
||||
public OpenDreamInstallation(
|
||||
IIOManager ioManager,
|
||||
IIOManager installationIOManager,
|
||||
IAsyncDelayer asyncDelayer,
|
||||
IAbstractHttpClientFactory httpClientFactory,
|
||||
string serverExePath,
|
||||
string compilerExePath,
|
||||
Task installationTask,
|
||||
EngineVersion version)
|
||||
: base(installationIOManager)
|
||||
{
|
||||
this.ioManager = ioManager ?? throw new ArgumentNullException(nameof(ioManager));
|
||||
this.asyncDelayer = asyncDelayer ?? throw new ArgumentNullException(nameof(asyncDelayer));
|
||||
this.httpClientFactory = httpClientFactory ?? throw new ArgumentNullException(nameof(httpClientFactory));
|
||||
ServerExePath = serverExePath ?? throw new ArgumentNullException(nameof(serverExePath));
|
||||
@@ -109,7 +107,7 @@ namespace Tgstation.Server.Host.Components.Engine
|
||||
|
||||
var parametersString = EncodeParameters(parameters, launchParameters);
|
||||
|
||||
var arguments = $"--cvar {(logFilePath != null ? $"log.path=\"{ioManager.GetDirectoryName(logFilePath)}\" --cvar log.format=\"{ioManager.GetFileName(logFilePath)}\"" : "log.enabled=false")} --cvar watchdog.token={accessIdentifier} --cvar log.runtimelog=false --cvar net.port={launchParameters.Port!.Value} --cvar opendream.topic_port=0 --cvar opendream.world_params=\"{parametersString}\" --cvar opendream.json_path=\"./{dmbProvider.DmbName}\"";
|
||||
var arguments = $"--cvar {(logFilePath != null ? $"log.path=\"{InstallationIOManager.GetDirectoryName(logFilePath)}\" --cvar log.format=\"{InstallationIOManager.GetFileName(logFilePath)}\"" : "log.enabled=false")} --cvar watchdog.token={accessIdentifier} --cvar log.runtimelog=false --cvar net.port={launchParameters.Port!.Value} --cvar opendream.topic_port=0 --cvar opendream.world_params=\"{parametersString}\" --cvar opendream.json_path=\"./{dmbProvider.DmbName}\"";
|
||||
return arguments;
|
||||
}
|
||||
|
||||
@@ -125,6 +123,8 @@ namespace Tgstation.Server.Host.Components.Engine
|
||||
ushort port,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(logger);
|
||||
|
||||
const int MaximumTerminationSeconds = 5;
|
||||
|
||||
logger.LogTrace("Attempting Robust.Server graceful exit (Timeout: {seconds}s)...", MaximumTerminationSeconds);
|
||||
|
||||
@@ -9,7 +9,6 @@ using Microsoft.Extensions.Options;
|
||||
using Tgstation.Server.Api.Models;
|
||||
using Tgstation.Server.Common.Extensions;
|
||||
using Tgstation.Server.Common.Http;
|
||||
using Tgstation.Server.Host.Common;
|
||||
using Tgstation.Server.Host.Components.Repository;
|
||||
using Tgstation.Server.Host.Configuration;
|
||||
using Tgstation.Server.Host.IO;
|
||||
@@ -124,7 +123,7 @@ namespace Tgstation.Server.Host.Components.Engine
|
||||
CheckVersionValidity(version);
|
||||
GetExecutablePaths(path, out var serverExePath, out var compilerExePath);
|
||||
return new OpenDreamInstallation(
|
||||
IOManager,
|
||||
new ResolvingIOManager(IOManager, path),
|
||||
asyncDelayer,
|
||||
httpClientFactory,
|
||||
serverExePath,
|
||||
@@ -193,7 +192,7 @@ namespace Tgstation.Server.Host.Components.Engine
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override async ValueTask Install(EngineVersion version, string installPath, CancellationToken cancellationToken)
|
||||
public override async ValueTask Install(EngineVersion version, string installPath, bool deploymentPipelineProcesses, CancellationToken cancellationToken)
|
||||
{
|
||||
CheckVersionValidity(version);
|
||||
ArgumentNullException.ThrowIfNull(installPath);
|
||||
@@ -232,21 +231,10 @@ namespace Tgstation.Server.Host.Components.Engine
|
||||
await Task.WhenAll(dirsMoveTasks.Concat(filesMoveTask));
|
||||
}
|
||||
|
||||
var dotnetPaths = DotnetHelper.GetPotentialDotnetPaths(platformIdentifier.IsWindows)
|
||||
.ToList();
|
||||
var tasks = dotnetPaths
|
||||
.Select(path => IOManager.FileExists(path, cancellationToken))
|
||||
.ToList();
|
||||
|
||||
await Task.WhenAll(tasks);
|
||||
|
||||
var selectedPathIndex = tasks.FindIndex(pathValidTask => pathValidTask.Result);
|
||||
|
||||
if (selectedPathIndex == -1)
|
||||
var dotnetPath = await DotnetHelper.GetDotnetPath(platformIdentifier, IOManager, cancellationToken);
|
||||
if (dotnetPath == null)
|
||||
throw new JobException(ErrorCode.OpenDreamCantFindDotnet);
|
||||
|
||||
var dotnetPath = dotnetPaths[selectedPathIndex];
|
||||
|
||||
const string DeployDir = "tgs_deploy";
|
||||
int? buildExitCode = null;
|
||||
await HandleExtremelyLongPathOperation(
|
||||
@@ -258,10 +246,11 @@ namespace Tgstation.Server.Host.Components.Engine
|
||||
shortenedPath,
|
||||
$"run -c Release --project OpenDreamPackageTool -- --tgs -o {shortenedDeployPath}",
|
||||
null,
|
||||
null,
|
||||
!GeneralConfiguration.OpenDreamSuppressInstallOutput,
|
||||
!GeneralConfiguration.OpenDreamSuppressInstallOutput);
|
||||
|
||||
if (SessionConfiguration.LowPriorityDeploymentProcesses)
|
||||
if (deploymentPipelineProcesses && SessionConfiguration.LowPriorityDeploymentProcesses)
|
||||
buildProcess.AdjustPriority(false);
|
||||
|
||||
using (cancellationToken.Register(() => buildProcess.Terminate()))
|
||||
|
||||
@@ -71,7 +71,7 @@ namespace Tgstation.Server.Host.Components.Engine
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override ValueTask Install(EngineVersion version, string path, CancellationToken cancellationToken)
|
||||
public override ValueTask Install(EngineVersion version, string path, bool deploymentPipelineProcesses, CancellationToken cancellationToken)
|
||||
{
|
||||
CheckVersionValidity(version);
|
||||
ArgumentNullException.ThrowIfNull(path);
|
||||
|
||||
@@ -127,7 +127,7 @@ namespace Tgstation.Server.Host.Components.Engine
|
||||
public void Dispose() => semaphore.Dispose();
|
||||
|
||||
/// <inheritdoc />
|
||||
public override ValueTask Install(EngineVersion version, string path, CancellationToken cancellationToken)
|
||||
public override ValueTask Install(EngineVersion version, string path, bool deploymentPipelineProcesses, CancellationToken cancellationToken)
|
||||
{
|
||||
CheckVersionValidity(version);
|
||||
ArgumentNullException.ThrowIfNull(path);
|
||||
@@ -142,7 +142,7 @@ namespace Tgstation.Server.Host.Components.Engine
|
||||
|
||||
if (!generalConfiguration.SkipAddingByondFirewallException)
|
||||
{
|
||||
var firewallTask = AddDreamDaemonToFirewall(version, path, cancellationToken);
|
||||
var firewallTask = AddDreamDaemonToFirewall(version, path, deploymentPipelineProcesses, cancellationToken);
|
||||
tasks.Add(firewallTask);
|
||||
}
|
||||
|
||||
@@ -165,7 +165,7 @@ namespace Tgstation.Server.Host.Components.Engine
|
||||
return;
|
||||
|
||||
Logger.LogInformation("BYOND Version {version} needs dd.exe added to firewall", version);
|
||||
await AddDreamDaemonToFirewall(version, path, cancellationToken);
|
||||
await AddDreamDaemonToFirewall(version, path, true, cancellationToken);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -243,9 +243,10 @@ namespace Tgstation.Server.Host.Components.Engine
|
||||
/// </summary>
|
||||
/// <param name="version">The BYOND <see cref="EngineVersion"/>.</param>
|
||||
/// <param name="path">The path to the BYOND installation.</param>
|
||||
/// <param name="deploymentPipelineProcesses">If the operation is part of the deployment pipeline.</param>
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation.</param>
|
||||
/// <returns>A <see cref="ValueTask"/> representing the running operation.</returns>
|
||||
async ValueTask AddDreamDaemonToFirewall(EngineVersion version, string path, CancellationToken cancellationToken)
|
||||
async ValueTask AddDreamDaemonToFirewall(EngineVersion version, string path, bool deploymentPipelineProcesses, CancellationToken cancellationToken)
|
||||
{
|
||||
var dreamDaemonName = GetDreamDaemonName(version.Version!, out var usesDDExe);
|
||||
|
||||
@@ -268,7 +269,7 @@ namespace Tgstation.Server.Host.Components.Engine
|
||||
Logger,
|
||||
ruleName,
|
||||
dreamDaemonPath,
|
||||
sessionConfiguration.LowPriorityDeploymentProcesses,
|
||||
deploymentPipelineProcesses && sessionConfiguration.LowPriorityDeploymentProcesses,
|
||||
cancellationToken);
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
||||
@@ -66,15 +66,17 @@ namespace Tgstation.Server.Host.Components.Engine
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override ValueTask Install(EngineVersion version, string installPath, CancellationToken cancellationToken)
|
||||
public override ValueTask Install(EngineVersion version, string installPath, bool deploymentPipelineProcesses, CancellationToken cancellationToken)
|
||||
{
|
||||
var installTask = base.Install(
|
||||
version,
|
||||
installPath,
|
||||
deploymentPipelineProcesses,
|
||||
cancellationToken);
|
||||
var firewallTask = AddServerFirewallException(
|
||||
version,
|
||||
installPath,
|
||||
deploymentPipelineProcesses,
|
||||
cancellationToken);
|
||||
|
||||
return ValueTaskExtensions.WhenAll(installTask, firewallTask);
|
||||
@@ -101,9 +103,10 @@ namespace Tgstation.Server.Host.Components.Engine
|
||||
/// </summary>
|
||||
/// <param name="version">The BYOND <see cref="EngineVersion"/>.</param>
|
||||
/// <param name="path">The path to the BYOND installation.</param>
|
||||
/// <param name="deploymentPipelineProcesses">If the operation is part of the deployment pipeline.</param>
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation.</param>
|
||||
/// <returns>A <see cref="ValueTask"/> representing the running operation.</returns>
|
||||
async ValueTask AddServerFirewallException(EngineVersion version, string path, CancellationToken cancellationToken)
|
||||
async ValueTask AddServerFirewallException(EngineVersion version, string path, bool deploymentPipelineProcesses, CancellationToken cancellationToken)
|
||||
{
|
||||
if (GeneralConfiguration.SkipAddingByondFirewallException)
|
||||
return;
|
||||
@@ -123,7 +126,7 @@ namespace Tgstation.Server.Host.Components.Engine
|
||||
Logger,
|
||||
ruleName,
|
||||
serverExePath,
|
||||
SessionConfiguration.LowPriorityDeploymentProcesses,
|
||||
deploymentPipelineProcesses && SessionConfiguration.LowPriorityDeploymentProcesses,
|
||||
cancellationToken);
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
||||
@@ -135,6 +135,11 @@ namespace Tgstation.Server.Host.Components
|
||||
/// </summary>
|
||||
readonly IAsyncDelayer asyncDelayer;
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="IDotnetDumpService"/> for the <see cref="InstanceFactory"/>.
|
||||
/// </summary>
|
||||
readonly IDotnetDumpService dotnetDumpService;
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="GeneralConfiguration"/> for the <see cref="InstanceFactory"/>.
|
||||
/// </summary>
|
||||
@@ -177,6 +182,7 @@ namespace Tgstation.Server.Host.Components
|
||||
/// <param name="fileTransferService">The value of <see cref="fileTransferService"/>.</param>
|
||||
/// <param name="remoteDeploymentManagerFactory">The value of <see cref="remoteDeploymentManagerFactory"/>.</param>
|
||||
/// <param name="asyncDelayer">The value of <see cref="asyncDelayer"/>.</param>
|
||||
/// <param name="dotnetDumpService">The value of <see cref="dotnetDumpService"/>.</param>
|
||||
/// <param name="generalConfigurationOptions">The <see cref="IOptions{TOptions}"/> containing the value of <see cref="generalConfiguration"/>.</param>
|
||||
/// <param name="sessionConfigurationOptions">The <see cref="IOptions{TOptions}"/> containing the value of <see cref="sessionConfiguration"/>.</param>
|
||||
public InstanceFactory(
|
||||
@@ -201,6 +207,7 @@ namespace Tgstation.Server.Host.Components
|
||||
IFileTransferTicketProvider fileTransferService,
|
||||
IRemoteDeploymentManagerFactory remoteDeploymentManagerFactory,
|
||||
IAsyncDelayer asyncDelayer,
|
||||
IDotnetDumpService dotnetDumpService,
|
||||
IOptions<GeneralConfiguration> generalConfigurationOptions,
|
||||
IOptions<SessionConfiguration> sessionConfigurationOptions)
|
||||
{
|
||||
@@ -225,6 +232,7 @@ namespace Tgstation.Server.Host.Components
|
||||
this.fileTransferService = fileTransferService ?? throw new ArgumentNullException(nameof(fileTransferService));
|
||||
this.remoteDeploymentManagerFactory = remoteDeploymentManagerFactory ?? throw new ArgumentNullException(nameof(remoteDeploymentManagerFactory));
|
||||
this.asyncDelayer = asyncDelayer ?? throw new ArgumentNullException(nameof(asyncDelayer));
|
||||
this.dotnetDumpService = dotnetDumpService ?? throw new ArgumentNullException(nameof(dotnetDumpService));
|
||||
generalConfiguration = generalConfigurationOptions?.Value ?? throw new ArgumentNullException(nameof(generalConfigurationOptions));
|
||||
sessionConfiguration = sessionConfigurationOptions?.Value ?? throw new ArgumentNullException(nameof(sessionConfigurationOptions));
|
||||
}
|
||||
@@ -271,7 +279,11 @@ namespace Tgstation.Server.Host.Components
|
||||
var repoManager = repositoryManagerFactory.CreateRepositoryManager(repoIoManager, eventConsumer);
|
||||
try
|
||||
{
|
||||
var engineManager = new EngineManager(byondIOManager, engineInstaller, eventConsumer, loggerFactory.CreateLogger<EngineManager>());
|
||||
var engineManager = new EngineManager(
|
||||
byondIOManager,
|
||||
engineInstaller,
|
||||
eventConsumer,
|
||||
loggerFactory.CreateLogger<EngineManager>());
|
||||
|
||||
var dmbFactory = new DmbFactory(
|
||||
databaseContextFactory,
|
||||
@@ -309,6 +321,7 @@ namespace Tgstation.Server.Host.Components
|
||||
serverPortProvider,
|
||||
eventConsumer,
|
||||
asyncDelayer,
|
||||
dotnetDumpService,
|
||||
loggerFactory,
|
||||
loggerFactory.CreateLogger<SessionControllerFactory>(),
|
||||
sessionConfiguration,
|
||||
|
||||
@@ -84,6 +84,11 @@ namespace Tgstation.Server.Host.Components.Session
|
||||
/// </summary>
|
||||
bool DMApiAvailable { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The file extension to use for process dumps created from this session.
|
||||
/// </summary>
|
||||
string DumpFileExtension { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Releases the <see cref="IProcess"/> without terminating it. Also calls <see cref="IDisposable.Dispose"/>.
|
||||
/// </summary>
|
||||
|
||||
@@ -104,6 +104,11 @@ namespace Tgstation.Server.Host.Components.Session
|
||||
/// <inheritdoc />
|
||||
public bool ProcessingRebootBridgeRequest => rebootBridgeRequestsProcessing > 0;
|
||||
|
||||
/// <inheritdoc />
|
||||
public string DumpFileExtension => engineLock.UseDotnetDump
|
||||
? ".net.dmp"
|
||||
: ".dmp";
|
||||
|
||||
/// <summary>
|
||||
/// The up to date <see cref="Session.ReattachInformation"/>.
|
||||
/// </summary>
|
||||
@@ -149,6 +154,11 @@ namespace Tgstation.Server.Host.Components.Session
|
||||
/// </summary>
|
||||
readonly IAsyncDelayer asyncDelayer;
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="IDotnetDumpService"/> for the <see cref="SessionController"/>.
|
||||
/// </summary>
|
||||
readonly IDotnetDumpService dotnetDumpService;
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="TaskCompletionSource"/> that completes when DD makes it's first bridge request.
|
||||
/// </summary>
|
||||
@@ -236,7 +246,8 @@ namespace Tgstation.Server.Host.Components.Session
|
||||
/// <param name="chat">The value of <see cref="chat"/>.</param>
|
||||
/// <param name="chatTrackingContext">The value of <see cref="chatTrackingContext"/>.</param>
|
||||
/// <param name="assemblyInformationProvider">The <see cref="IAssemblyInformationProvider"/> for the <see cref="SessionController"/>.</param>
|
||||
/// <param name="asyncDelayer">The <see cref="IAsyncDelayer"/> for the <see cref="SessionController"/>.</param>
|
||||
/// <param name="asyncDelayer">The value of <see cref="asyncDelayer"/>.</param>
|
||||
/// <param name="dotnetDumpService">The value of <see cref="dotnetDumpService"/>.</param>
|
||||
/// <param name="logger">The value of <see cref="Chunker.Logger"/>.</param>
|
||||
/// <param name="postLifetimeCallback">The <see cref="Func{TResult}"/> returning a <see cref="ValueTask"/> to be run after the <paramref name="process"/> ends.</param>
|
||||
/// <param name="startupTimeout">The optional time to wait before failing the <see cref="LaunchResult"/>.</param>
|
||||
@@ -253,6 +264,7 @@ namespace Tgstation.Server.Host.Components.Session
|
||||
IChatManager chat,
|
||||
IAssemblyInformationProvider assemblyInformationProvider,
|
||||
IAsyncDelayer asyncDelayer,
|
||||
IDotnetDumpService dotnetDumpService,
|
||||
ILogger<SessionController> logger,
|
||||
Func<ValueTask> postLifetimeCallback,
|
||||
uint? startupTimeout,
|
||||
@@ -272,6 +284,7 @@ namespace Tgstation.Server.Host.Components.Session
|
||||
ArgumentNullException.ThrowIfNull(assemblyInformationProvider);
|
||||
|
||||
this.asyncDelayer = asyncDelayer ?? throw new ArgumentNullException(nameof(asyncDelayer));
|
||||
this.dotnetDumpService = dotnetDumpService ?? throw new ArgumentNullException(nameof(dotnetDumpService));
|
||||
|
||||
apiValidationSession = apiValidate;
|
||||
|
||||
@@ -474,7 +487,13 @@ namespace Tgstation.Server.Host.Components.Session
|
||||
cancellationToken);
|
||||
|
||||
/// <inheritdoc />
|
||||
public ValueTask CreateDump(string outputFile, CancellationToken cancellationToken) => process.CreateDump(outputFile, cancellationToken);
|
||||
public ValueTask CreateDump(string outputFile, bool minidump, CancellationToken cancellationToken)
|
||||
{
|
||||
if (engineLock.UseDotnetDump)
|
||||
return dotnetDumpService.Dump(process, outputFile, minidump, cancellationToken);
|
||||
|
||||
return process.CreateDump(outputFile, minidump, cancellationToken);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="Task{TResult}"/> for <see cref="LaunchResult"/>.
|
||||
|
||||
@@ -106,6 +106,11 @@ namespace Tgstation.Server.Host.Components.Session
|
||||
/// </summary>
|
||||
readonly IAsyncDelayer asyncDelayer;
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="IDotnetDumpService"/> for the <see cref="SessionControllerFactory"/>.
|
||||
/// </summary>
|
||||
readonly IDotnetDumpService dotnetDumpService;
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="ILoggerFactory"/> for the <see cref="SessionControllerFactory"/>.
|
||||
/// </summary>
|
||||
@@ -178,6 +183,7 @@ namespace Tgstation.Server.Host.Components.Session
|
||||
/// <param name="serverPortProvider">The value of <see cref="serverPortProvider"/>.</param>
|
||||
/// <param name="eventConsumer">The value of <see cref="eventConsumer"/>.</param>
|
||||
/// <param name="asyncDelayer">The value of <see cref="asyncDelayer"/>.</param>
|
||||
/// <param name="dotnetDumpService">The value of <see cref="dotnetDumpService"/>.</param>
|
||||
/// <param name="loggerFactory">The value of <see cref="loggerFactory"/>.</param>
|
||||
/// <param name="logger">The value of <see cref="logger"/>.</param>
|
||||
/// <param name="sessionConfiguration">The value of <see cref="sessionConfiguration"/>.</param>
|
||||
@@ -196,6 +202,7 @@ namespace Tgstation.Server.Host.Components.Session
|
||||
IServerPortProvider serverPortProvider,
|
||||
IEventConsumer eventConsumer,
|
||||
IAsyncDelayer asyncDelayer,
|
||||
IDotnetDumpService dotnetDumpService,
|
||||
ILoggerFactory loggerFactory,
|
||||
ILogger<SessionControllerFactory> logger,
|
||||
SessionConfiguration sessionConfiguration,
|
||||
@@ -215,6 +222,7 @@ namespace Tgstation.Server.Host.Components.Session
|
||||
this.serverPortProvider = serverPortProvider ?? throw new ArgumentNullException(nameof(serverPortProvider));
|
||||
this.eventConsumer = eventConsumer ?? throw new ArgumentNullException(nameof(eventConsumer));
|
||||
this.asyncDelayer = asyncDelayer ?? throw new ArgumentNullException(nameof(asyncDelayer));
|
||||
this.dotnetDumpService = dotnetDumpService ?? throw new ArgumentNullException(nameof(dotnetDumpService));
|
||||
this.loggerFactory = loggerFactory ?? throw new ArgumentNullException(nameof(loggerFactory));
|
||||
this.logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||
this.sessionConfiguration = sessionConfiguration ?? throw new ArgumentNullException(nameof(sessionConfiguration));
|
||||
@@ -346,6 +354,7 @@ namespace Tgstation.Server.Host.Components.Session
|
||||
chat,
|
||||
assemblyInformationProvider,
|
||||
asyncDelayer,
|
||||
dotnetDumpService,
|
||||
loggerFactory.CreateLogger<SessionController>(),
|
||||
() => LogDDOutput(
|
||||
process,
|
||||
@@ -436,6 +445,7 @@ namespace Tgstation.Server.Host.Components.Session
|
||||
chat,
|
||||
assemblyInformationProvider,
|
||||
asyncDelayer,
|
||||
dotnetDumpService,
|
||||
loggerFactory.CreateLogger<SessionController>(),
|
||||
() => ValueTask.CompletedTask,
|
||||
null,
|
||||
@@ -490,6 +500,7 @@ namespace Tgstation.Server.Host.Components.Session
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
// important to run on all ports to allow port changing
|
||||
var environment = await engineLock.LoadEnv(logger, false, cancellationToken);
|
||||
var arguments = engineLock.FormatServerArguments(
|
||||
dmbProvider,
|
||||
new Dictionary<string, string>
|
||||
@@ -507,6 +518,7 @@ namespace Tgstation.Server.Host.Components.Session
|
||||
engineLock.ServerExePath,
|
||||
dmbProvider.Directory,
|
||||
arguments,
|
||||
environment,
|
||||
logFilePath,
|
||||
engineLock.HasStandardOutput,
|
||||
true);
|
||||
|
||||
@@ -1225,25 +1225,31 @@ namespace Tgstation.Server.Host.Components.Watchdog
|
||||
async ValueTask CreateDumpNoLock(CancellationToken cancellationToken)
|
||||
{
|
||||
const string DumpDirectory = "ProcessDumps";
|
||||
var dumpFileNameTemplate = diagnosticsIOManager.ResolvePath(
|
||||
diagnosticsIOManager.ConcatPath(
|
||||
DumpDirectory,
|
||||
$"DreamDaemon-{DateTimeOffset.UtcNow.ToFileStamp()}.dmp"));
|
||||
|
||||
var dumpFileName = dumpFileNameTemplate;
|
||||
var iteration = 0;
|
||||
while (await diagnosticsIOManager.FileExists(dumpFileName, cancellationToken))
|
||||
dumpFileName = $"{dumpFileNameTemplate} ({++iteration})";
|
||||
|
||||
if (iteration == 0)
|
||||
await diagnosticsIOManager.CreateDirectory(DumpDirectory, cancellationToken);
|
||||
|
||||
var session = GetActiveController();
|
||||
if (session?.Lifetime.IsCompleted != false)
|
||||
throw new JobException(ErrorCode.GameServerOffline);
|
||||
|
||||
var dumpFileExtension = session.DumpFileExtension;
|
||||
|
||||
var dumpFileNameTemplate = diagnosticsIOManager.ResolvePath(
|
||||
diagnosticsIOManager.ConcatPath(
|
||||
DumpDirectory,
|
||||
$"DreamDaemon-{DateTimeOffset.UtcNow.ToFileStamp()}"));
|
||||
|
||||
var dumpFileName = $"{dumpFileNameTemplate}{dumpFileExtension}";
|
||||
var iteration = 0;
|
||||
while (await diagnosticsIOManager.FileExists(dumpFileName, cancellationToken))
|
||||
dumpFileName = $"{dumpFileNameTemplate} ({++iteration}){dumpFileExtension}";
|
||||
|
||||
if (iteration == 0)
|
||||
await diagnosticsIOManager.CreateDirectory(DumpDirectory, cancellationToken);
|
||||
|
||||
if (session.Lifetime.IsCompleted)
|
||||
throw new JobException(ErrorCode.GameServerOffline);
|
||||
|
||||
Logger.LogInformation("Dumping session to {dumpFileName}...", dumpFileName);
|
||||
await session.CreateDump(dumpFileName, cancellationToken);
|
||||
await session.CreateDump(dumpFileName, ActiveLaunchParameters.Minidumps!.Value, cancellationToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -187,6 +187,9 @@ namespace Tgstation.Server.Host.Configuration
|
||||
else if (this.GetCopyDirectoryTaskThrottle() < 1)
|
||||
throw new InvalidOperationException(
|
||||
$"{nameof(DeploymentDirectoryCopyTasksPerCore)} is too large for the CPU core count of {Environment.ProcessorCount} and overflows a 32-bit signed integer. Please lower the value!");
|
||||
|
||||
if (ByondTopicTimeout <= 1000)
|
||||
logger.LogWarning("The timeout for sending BYOND topics is very low ({ms}ms). Topic calls may fail to complete at all!", ByondTopicTimeout);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,5 +24,10 @@
|
||||
/// If the deployment DreamMaker and DreamDaemon instances are set to be below normal priority processes.
|
||||
/// </summary>
|
||||
public bool LowPriorityDeploymentProcesses { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// If <see langword="true"/>, deployments that fail will not be immediately cleaned up. They will be cleaned up the next time the instance is onlined.
|
||||
/// </summary>
|
||||
public bool DelayCleaningFailedDeployments { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -149,7 +149,8 @@ namespace Tgstation.Server.Host.Controllers
|
||||
| DreamDaemonRights.SetProfiler
|
||||
| DreamDaemonRights.SetLogOutput
|
||||
| DreamDaemonRights.SetMapThreads
|
||||
| DreamDaemonRights.BroadcastMessage)]
|
||||
| DreamDaemonRights.BroadcastMessage
|
||||
| DreamDaemonRights.SetMinidumps)]
|
||||
[ProducesResponseType(typeof(DreamDaemonResponse), 200)]
|
||||
[ProducesResponseType(typeof(ErrorMessageResponse), 410)]
|
||||
#pragma warning disable CA1502 // TODO: Decomplexify
|
||||
@@ -222,7 +223,8 @@ namespace Tgstation.Server.Host.Controllers
|
||||
|| CheckModified(x => x.AdditionalParameters, DreamDaemonRights.SetAdditionalParameters)
|
||||
|| CheckModified(x => x.StartProfiler, DreamDaemonRights.SetProfiler)
|
||||
|| CheckModified(x => x.LogOutput, DreamDaemonRights.SetLogOutput)
|
||||
|| CheckModified(x => x.MapThreads, DreamDaemonRights.SetMapThreads))
|
||||
|| CheckModified(x => x.MapThreads, DreamDaemonRights.SetMapThreads)
|
||||
|| CheckModified(x => x.Minidumps, DreamDaemonRights.SetMinidumps))
|
||||
return Forbid();
|
||||
|
||||
return await WithComponentInstance(
|
||||
@@ -379,6 +381,7 @@ namespace Tgstation.Server.Host.Controllers
|
||||
result.StartProfiler = settings.StartProfiler;
|
||||
result.LogOutput = settings.LogOutput;
|
||||
result.MapThreads = settings.MapThreads;
|
||||
result.Minidumps = settings.Minidumps;
|
||||
}
|
||||
|
||||
if (revision)
|
||||
|
||||
@@ -732,6 +732,7 @@ namespace Tgstation.Server.Host.Controllers
|
||||
StartProfiler = false,
|
||||
LogOutput = false,
|
||||
MapThreads = 0,
|
||||
Minidumps = true,
|
||||
},
|
||||
DreamMakerSettings = new DreamMakerSettings
|
||||
{
|
||||
|
||||
@@ -365,11 +365,9 @@ namespace Tgstation.Server.Host.Core
|
||||
}
|
||||
|
||||
// only global repo manager should be for the OD repo
|
||||
// god help me if we need more
|
||||
var openDreamRepositoryDirectory = ioManager.ConcatPath(
|
||||
Environment.GetFolderPath(
|
||||
Environment.SpecialFolder.LocalApplicationData,
|
||||
Environment.SpecialFolderOption.DoNotVerify),
|
||||
assemblyInformationProvider.VersionPrefix,
|
||||
ioManager.GetPathInLocalDirectory(assemblyInformationProvider),
|
||||
"OpenDreamRepository");
|
||||
services.AddSingleton(
|
||||
services => services
|
||||
@@ -416,6 +414,7 @@ namespace Tgstation.Server.Host.Core
|
||||
services.AddSingleton<IChatManagerFactory, ChatManagerFactory>();
|
||||
services.AddSingleton<IServerUpdater, ServerUpdater>();
|
||||
services.AddSingleton<IServerUpdateInitiator, ServerUpdateInitiator>();
|
||||
services.AddSingleton<IDotnetDumpService, DotnetDumpService>();
|
||||
|
||||
// configure misc services
|
||||
services.AddSingleton<IProcessExecutor, ProcessExecutor>();
|
||||
|
||||
@@ -375,22 +375,22 @@ namespace Tgstation.Server.Host.Database
|
||||
/// <summary>
|
||||
/// Used by unit tests to remind us to setup the correct MSSQL migration downgrades.
|
||||
/// </summary>
|
||||
internal static readonly Type MSLatestMigration = typeof(MSAddTopicPort);
|
||||
internal static readonly Type MSLatestMigration = typeof(MSAddMinidumpsOption);
|
||||
|
||||
/// <summary>
|
||||
/// Used by unit tests to remind us to setup the correct MYSQL migration downgrades.
|
||||
/// </summary>
|
||||
internal static readonly Type MYLatestMigration = typeof(MYAddTopicPort);
|
||||
internal static readonly Type MYLatestMigration = typeof(MYAddMinidumpsOption);
|
||||
|
||||
/// <summary>
|
||||
/// Used by unit tests to remind us to setup the correct PostgresSQL migration downgrades.
|
||||
/// </summary>
|
||||
internal static readonly Type PGLatestMigration = typeof(PGAddTopicPort);
|
||||
internal static readonly Type PGLatestMigration = typeof(PGAddMinidumpsOption);
|
||||
|
||||
/// <summary>
|
||||
/// Used by unit tests to remind us to setup the correct SQLite migration downgrades.
|
||||
/// </summary>
|
||||
internal static readonly Type SLLatestMigration = typeof(SLAddTopicPort);
|
||||
internal static readonly Type SLLatestMigration = typeof(SLAddMinidumpsOption);
|
||||
|
||||
/// <inheritdoc />
|
||||
#pragma warning disable CA1502 // Cyclomatic complexity
|
||||
@@ -419,6 +419,16 @@ namespace Tgstation.Server.Host.Database
|
||||
|
||||
string BadDatabaseType() => throw new ArgumentException($"Invalid DatabaseType: {currentDatabaseType}", nameof(currentDatabaseType));
|
||||
|
||||
if (targetVersion < new Version(6, 2, 0))
|
||||
targetMigration = currentDatabaseType switch
|
||||
{
|
||||
DatabaseType.MySql => nameof(MYAddTopicPort),
|
||||
DatabaseType.PostgresSql => nameof(PGAddTopicPort),
|
||||
DatabaseType.SqlServer => nameof(MSAddTopicPort),
|
||||
DatabaseType.Sqlite => nameof(SLAddTopicPort),
|
||||
_ => BadDatabaseType(),
|
||||
};
|
||||
|
||||
if (targetVersion < new Version(6, 0, 0))
|
||||
targetMigration = currentDatabaseType switch
|
||||
{
|
||||
|
||||
Generated
+1080
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,37 @@
|
||||
using System;
|
||||
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
using Tgstation.Server.Host.System;
|
||||
|
||||
namespace Tgstation.Server.Host.Database.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class MSAddMinidumpsOption : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(migrationBuilder);
|
||||
|
||||
// This was originally minidumps on Linux and full dumps on Windows
|
||||
var defaultValue = !new PlatformIdentifier().IsWindows;
|
||||
migrationBuilder.AddColumn<bool>(
|
||||
name: "Minidumps",
|
||||
table: "DreamDaemonSettings",
|
||||
type: "bit",
|
||||
nullable: false,
|
||||
defaultValue: defaultValue);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(migrationBuilder);
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "Minidumps",
|
||||
table: "DreamDaemonSettings");
|
||||
}
|
||||
}
|
||||
}
|
||||
Generated
+1114
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,37 @@
|
||||
using System;
|
||||
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
using Tgstation.Server.Host.System;
|
||||
|
||||
namespace Tgstation.Server.Host.Database.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class MYAddMinidumpsOption : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(migrationBuilder);
|
||||
|
||||
// This was originally minidumps on Linux and full dumps on Windows
|
||||
var defaultValue = !new PlatformIdentifier().IsWindows;
|
||||
migrationBuilder.AddColumn<bool>(
|
||||
name: "Minidumps",
|
||||
table: "DreamDaemonSettings",
|
||||
type: "tinyint(1)",
|
||||
nullable: false,
|
||||
defaultValue: defaultValue);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(migrationBuilder);
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "Minidumps",
|
||||
table: "DreamDaemonSettings");
|
||||
}
|
||||
}
|
||||
}
|
||||
Generated
+1074
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,37 @@
|
||||
using System;
|
||||
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
using Tgstation.Server.Host.System;
|
||||
|
||||
namespace Tgstation.Server.Host.Database.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class PGAddMinidumpsOption : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(migrationBuilder);
|
||||
|
||||
// This was originally minidumps on Linux and full dumps on Windows
|
||||
var defaultValue = !new PlatformIdentifier().IsWindows;
|
||||
migrationBuilder.AddColumn<bool>(
|
||||
name: "Minidumps",
|
||||
table: "DreamDaemonSettings",
|
||||
type: "boolean",
|
||||
nullable: false,
|
||||
defaultValue: defaultValue);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(migrationBuilder);
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "Minidumps",
|
||||
table: "DreamDaemonSettings");
|
||||
}
|
||||
}
|
||||
}
|
||||
Generated
+1046
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,37 @@
|
||||
using System;
|
||||
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
using Tgstation.Server.Host.System;
|
||||
|
||||
namespace Tgstation.Server.Host.Database.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class SLAddMinidumpsOption : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(migrationBuilder);
|
||||
|
||||
// This was originally minidumps on Linux and full dumps on Windows
|
||||
var defaultValue = !new PlatformIdentifier().IsWindows;
|
||||
migrationBuilder.AddColumn<bool>(
|
||||
name: "Minidumps",
|
||||
table: "DreamDaemonSettings",
|
||||
type: "INTEGER",
|
||||
nullable: false,
|
||||
defaultValue: defaultValue);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(migrationBuilder);
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "Minidumps",
|
||||
table: "DreamDaemonSettings");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -13,7 +13,7 @@ namespace Tgstation.Server.Host.Database.Migrations
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "8.0.0")
|
||||
.HasAnnotation("ProductVersion", "8.0.1")
|
||||
.HasAnnotation("Relational:MaxIdentifierLength", 64);
|
||||
|
||||
modelBuilder.Entity("Tgstation.Server.Host.Models.ChatBot", b =>
|
||||
@@ -219,6 +219,10 @@ namespace Tgstation.Server.Host.Database.Migrations
|
||||
.IsRequired()
|
||||
.HasColumnType("int unsigned");
|
||||
|
||||
b.Property<bool?>("Minidumps")
|
||||
.IsRequired()
|
||||
.HasColumnType("tinyint(1)");
|
||||
|
||||
b.Property<ushort?>("Port")
|
||||
.IsRequired()
|
||||
.HasColumnType("smallint unsigned");
|
||||
|
||||
+5
-1
@@ -13,7 +13,7 @@ namespace Tgstation.Server.Host.Database.Migrations
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "8.0.0")
|
||||
.HasAnnotation("ProductVersion", "8.0.1")
|
||||
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
||||
|
||||
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
||||
@@ -209,6 +209,10 @@ namespace Tgstation.Server.Host.Database.Migrations
|
||||
b.Property<long>("MapThreads")
|
||||
.HasColumnType("bigint");
|
||||
|
||||
b.Property<bool?>("Minidumps")
|
||||
.IsRequired()
|
||||
.HasColumnType("boolean");
|
||||
|
||||
b.Property<int>("Port")
|
||||
.HasColumnType("integer");
|
||||
|
||||
|
||||
+5
-1
@@ -13,7 +13,7 @@ namespace Tgstation.Server.Host.Database.Migrations
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "8.0.0")
|
||||
.HasAnnotation("ProductVersion", "8.0.1")
|
||||
.HasAnnotation("Relational:MaxIdentifierLength", 128);
|
||||
|
||||
SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
|
||||
@@ -211,6 +211,10 @@ namespace Tgstation.Server.Host.Database.Migrations
|
||||
b.Property<long>("MapThreads")
|
||||
.HasColumnType("bigint");
|
||||
|
||||
b.Property<bool?>("Minidumps")
|
||||
.IsRequired()
|
||||
.HasColumnType("bit");
|
||||
|
||||
b.Property<int>("Port")
|
||||
.HasColumnType("int");
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace Tgstation.Server.Host.Database.Migrations
|
||||
protected override void BuildModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder.HasAnnotation("ProductVersion", "8.0.0");
|
||||
modelBuilder.HasAnnotation("ProductVersion", "8.0.1");
|
||||
|
||||
modelBuilder.Entity("Tgstation.Server.Host.Models.ChatBot", b =>
|
||||
{
|
||||
@@ -201,6 +201,10 @@ namespace Tgstation.Server.Host.Database.Migrations
|
||||
.IsRequired()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<bool?>("Minidumps")
|
||||
.IsRequired()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<ushort?>("Port")
|
||||
.IsRequired()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
using System;
|
||||
|
||||
using Tgstation.Server.Host.IO;
|
||||
using Tgstation.Server.Host.System;
|
||||
|
||||
namespace Tgstation.Server.Host.Extensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Extension methods for <see cref="IIOManager"/>.
|
||||
/// </summary>
|
||||
static class IOManagerExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the local application data folder used by TGS.
|
||||
/// </summary>
|
||||
/// <param name="ioManager">The <see cref="IIOManager"/> to use.</param>
|
||||
/// <param name="assemblyInformationProvider">The <see cref="IAssemblyInformationProvider"/> to use.</param>
|
||||
/// <returns>The path to the local application data directory used by TGS.</returns>
|
||||
public static string GetPathInLocalDirectory(this IIOManager ioManager, IAssemblyInformationProvider assemblyInformationProvider)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(ioManager);
|
||||
ArgumentNullException.ThrowIfNull(assemblyInformationProvider);
|
||||
|
||||
return ioManager.ConcatPath(
|
||||
Environment.GetFolderPath(
|
||||
Environment.SpecialFolder.LocalApplicationData, // we use local application data here instead of comman application data because we store stuff here we don't want other users interfering with
|
||||
Environment.SpecialFolderOption.DoNotVerify),
|
||||
assemblyInformationProvider.VersionPrefix);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Microsoft.Diagnostics.NETCore.Client;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Tgstation.Server.Host.System
|
||||
{
|
||||
/// <inheritdoc />
|
||||
sealed class DotnetDumpService : IDotnetDumpService
|
||||
{
|
||||
/// <summary>
|
||||
/// The <see cref="ILogger"/> for the <see cref="DotnetDumpService"/>.
|
||||
/// </summary>
|
||||
readonly ILogger<DotnetDumpService> logger;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="DotnetDumpService"/> class.
|
||||
/// </summary>
|
||||
/// <param name="logger">The value of <see cref="logger"/>.</param>
|
||||
public DotnetDumpService(
|
||||
ILogger<DotnetDumpService> logger)
|
||||
{
|
||||
this.logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async ValueTask Dump(IProcess process, string outputFile, bool minidump, CancellationToken cancellationToken)
|
||||
{
|
||||
// need to use an extra timeout here because if the process is truly deadlocked. A cooperative dump will hang forever
|
||||
using var cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
|
||||
|
||||
const int TimeoutMinutes = 5;
|
||||
cts.CancelAfter(TimeSpan.FromMinutes(TimeoutMinutes));
|
||||
cts.Token.Register(() =>
|
||||
{
|
||||
if (!cancellationToken.IsCancellationRequested)
|
||||
logger.LogError("dotnet-dump timed out after {minutes} minutes!", TimeoutMinutes);
|
||||
});
|
||||
|
||||
var pid = process.Id;
|
||||
logger.LogDebug("dotnet-dump requested for PID {pid}...", pid);
|
||||
var client = new DiagnosticsClient(pid);
|
||||
await client.WriteDumpAsync(
|
||||
minidump
|
||||
? DumpType.Normal
|
||||
: DumpType.Full,
|
||||
outputFile,
|
||||
false,
|
||||
cts.Token);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Tgstation.Server.Host.IO;
|
||||
|
||||
namespace Tgstation.Server.Host.System
|
||||
{
|
||||
/// <summary>
|
||||
/// Helper methods for working with the dotnet executable.
|
||||
/// </summary>
|
||||
static class DotnetHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// Locate a dotnet executable to use.
|
||||
/// </summary>
|
||||
/// <param name="platformIdentifier">The <see cref="IPlatformIdentifier"/> to use.</param>
|
||||
/// <param name="ioManager">The <see cref="IIOManager"/> to use.</param>
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation.</param>
|
||||
/// <returns>A <see cref="ValueTask{TResult}"/> resulting in a dotnet executable path to use on success, <see langword="null"/> otherwise.</returns>
|
||||
public static async ValueTask<string?> GetDotnetPath(IPlatformIdentifier platformIdentifier, IIOManager ioManager, CancellationToken cancellationToken)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(platformIdentifier);
|
||||
ArgumentNullException.ThrowIfNull(ioManager);
|
||||
|
||||
var dotnetPaths = Common.DotnetHelper.GetPotentialDotnetPaths(platformIdentifier.IsWindows)
|
||||
.ToList();
|
||||
var tasks = dotnetPaths
|
||||
.Select(path => ioManager.FileExists(path, cancellationToken))
|
||||
.ToList();
|
||||
|
||||
await Task.WhenAll(tasks);
|
||||
|
||||
var selectedPathIndex = tasks.FindIndex(pathValidTask => pathValidTask.Result);
|
||||
|
||||
if (selectedPathIndex == -1)
|
||||
return null;
|
||||
|
||||
var dotnetPath = dotnetPaths[selectedPathIndex];
|
||||
|
||||
return dotnetPath;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Tgstation.Server.Host.System
|
||||
{
|
||||
/// <summary>
|
||||
/// Service for managing the dotnet-dump installation.
|
||||
/// </summary>
|
||||
public interface IDotnetDumpService
|
||||
{
|
||||
/// <summary>
|
||||
/// Attempt to dump a given <paramref name="process"/>.
|
||||
/// </summary>
|
||||
/// <param name="process">The <see cref="IProcess"/> to dump.</param>
|
||||
/// <param name="outputFile">The path to the output dump file.</param>
|
||||
/// <param name="minidump">If a minidump should be taken as opposed to a full dump.</param>
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation.</param>
|
||||
/// <returns>A <see cref="ValueTask"/> representing the running operation.</returns>
|
||||
ValueTask Dump(IProcess process, string outputFile, bool minidump, CancellationToken cancellationToken);
|
||||
}
|
||||
}
|
||||
@@ -33,8 +33,9 @@ namespace Tgstation.Server.Host.System
|
||||
/// Create a dump file of the process.
|
||||
/// </summary>
|
||||
/// <param name="outputFile">The full path to the output file.</param>
|
||||
/// <param name="minidump">If a minidump should be taken as opposed to a full dump.</param>
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation.</param>
|
||||
/// <returns>A <see cref="ValueTask"/> representing the running operation.</returns>
|
||||
ValueTask CreateDump(string outputFile, CancellationToken cancellationToken);
|
||||
ValueTask CreateDump(string outputFile, bool minidump, CancellationToken cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
namespace Tgstation.Server.Host.System
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Tgstation.Server.Host.System
|
||||
{
|
||||
/// <summary>
|
||||
/// For launching <see cref="IProcess"/>'.
|
||||
@@ -11,6 +13,7 @@
|
||||
/// <param name="fileName">The full path to the executable file.</param>
|
||||
/// <param name="workingDirectory">The working directory for the <see cref="IProcess"/>.</param>
|
||||
/// <param name="arguments">The arguments for the <see cref="IProcess"/>.</param>
|
||||
/// <param name="environment">A <see cref="IReadOnlyDictionary{TKey, TValue}"/> of environment variables to set.</param>
|
||||
/// <param name="fileRedirect">File to write process output and error streams to. Requires <paramref name="readStandardHandles"/> to be <see langword="true"/>.</param>
|
||||
/// <param name="readStandardHandles">If the process output and error streams should be read.</param>
|
||||
/// <param name="noShellExecute">If shell execute should not be used. Must be set if <paramref name="readStandardHandles"/> is set.</param>
|
||||
@@ -19,6 +22,7 @@
|
||||
string fileName,
|
||||
string workingDirectory,
|
||||
string arguments,
|
||||
IReadOnlyDictionary<string, string>? environment = null,
|
||||
string? fileRedirect = null,
|
||||
bool readStandardHandles = false,
|
||||
bool noShellExecute = false);
|
||||
|
||||
@@ -32,8 +32,9 @@ namespace Tgstation.Server.Host.System
|
||||
/// </summary>
|
||||
/// <param name="process">The <see cref="Process"/> to dump.</param>
|
||||
/// <param name="outputFile">The full path to the output file.</param>
|
||||
/// <param name="minidump">If a minidump should be taken as opposed to a full dump.</param>
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation.</param>
|
||||
/// <returns>A <see cref="ValueTask"/> representing the running operation.</returns>
|
||||
ValueTask CreateDump(global::System.Diagnostics.Process process, string outputFile, CancellationToken cancellationToken);
|
||||
ValueTask CreateDump(global::System.Diagnostics.Process process, string outputFile, bool minidump, CancellationToken cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,7 +64,7 @@ namespace Tgstation.Server.Host.System
|
||||
=> throw new NotSupportedException();
|
||||
|
||||
/// <inheritdoc />
|
||||
public async ValueTask CreateDump(global::System.Diagnostics.Process process, string outputFile, CancellationToken cancellationToken)
|
||||
public async ValueTask CreateDump(global::System.Diagnostics.Process process, string outputFile, bool minidump, CancellationToken cancellationToken)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(process);
|
||||
ArgumentNullException.ThrowIfNull(outputFile);
|
||||
@@ -91,7 +91,7 @@ namespace Tgstation.Server.Host.System
|
||||
await using (var gcoreProc = lazyLoadedProcessExecutor.Value.LaunchProcess(
|
||||
GCorePath,
|
||||
Environment.CurrentDirectory,
|
||||
$"-o {outputFile} {process.Id}",
|
||||
$"{(!minidump ? "-a " : String.Empty)}-o {outputFile} {process.Id}",
|
||||
readStandardHandles: true,
|
||||
noShellExecute: true))
|
||||
{
|
||||
@@ -99,7 +99,7 @@ namespace Tgstation.Server.Host.System
|
||||
exitCode = (await gcoreProc.Lifetime).Value;
|
||||
|
||||
output = await gcoreProc.GetCombinedOutput(cancellationToken);
|
||||
logger.LogDebug("gcore output:{0}{1}", Environment.NewLine, output);
|
||||
logger.LogDebug("gcore output:{newline}{output}", Environment.NewLine, output);
|
||||
}
|
||||
|
||||
if (exitCode != 0)
|
||||
|
||||
@@ -224,13 +224,13 @@ namespace Tgstation.Server.Host.System
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public ValueTask CreateDump(string outputFile, CancellationToken cancellationToken)
|
||||
public ValueTask CreateDump(string outputFile, bool minidump, CancellationToken cancellationToken)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(outputFile);
|
||||
CheckDisposed();
|
||||
|
||||
logger.LogTrace("Dumping PID {pid} to {dumpFilePath}...", Id, outputFile);
|
||||
return processFeatures.CreateDump(handle, outputFile, cancellationToken);
|
||||
return processFeatures.CreateDump(handle, outputFile, minidump, cancellationToken);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Channels;
|
||||
@@ -107,6 +109,7 @@ namespace Tgstation.Server.Host.System
|
||||
string fileName,
|
||||
string workingDirectory,
|
||||
string arguments,
|
||||
IReadOnlyDictionary<string, string>? environment,
|
||||
string? fileRedirect,
|
||||
bool readStandardHandles,
|
||||
bool noShellExecute)
|
||||
@@ -115,24 +118,33 @@ namespace Tgstation.Server.Host.System
|
||||
ArgumentNullException.ThrowIfNull(workingDirectory);
|
||||
ArgumentNullException.ThrowIfNull(arguments);
|
||||
|
||||
var enviromentLogLines = environment == null
|
||||
? String.Empty
|
||||
: String.Concat(environment.Select(kvp => $"{Environment.NewLine}\t- {kvp.Key}={kvp.Value}"));
|
||||
if (noShellExecute)
|
||||
logger.LogDebug(
|
||||
"Launching process in {workingDirectory}: {exe} {arguments}",
|
||||
"Launching process in {workingDirectory}: {exe} {arguments}{environment}",
|
||||
workingDirectory,
|
||||
fileName,
|
||||
arguments);
|
||||
arguments,
|
||||
enviromentLogLines);
|
||||
else
|
||||
logger.LogDebug(
|
||||
"Shell launching process in {workingDirectory}: {exe} {arguments}",
|
||||
"Shell launching process in {workingDirectory}: {exe} {arguments}{environment}",
|
||||
workingDirectory,
|
||||
fileName,
|
||||
arguments);
|
||||
arguments,
|
||||
enviromentLogLines);
|
||||
|
||||
var handle = new global::System.Diagnostics.Process();
|
||||
try
|
||||
{
|
||||
handle.StartInfo.FileName = fileName;
|
||||
handle.StartInfo.Arguments = arguments;
|
||||
if (environment != null)
|
||||
foreach (var kvp in environment)
|
||||
handle.StartInfo.Environment.Add(kvp!);
|
||||
|
||||
handle.StartInfo.WorkingDirectory = workingDirectory;
|
||||
|
||||
handle.StartInfo.UseShellExecute = !noShellExecute;
|
||||
|
||||
@@ -120,7 +120,7 @@ namespace Tgstation.Server.Host.System
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async ValueTask CreateDump(global::System.Diagnostics.Process process, string outputFile, CancellationToken cancellationToken)
|
||||
public async ValueTask CreateDump(global::System.Diagnostics.Process process, string outputFile, bool minidump, CancellationToken cancellationToken)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -137,15 +137,19 @@ namespace Tgstation.Server.Host.System
|
||||
await Task.Factory.StartNew(
|
||||
() =>
|
||||
{
|
||||
var flags = NativeMethods.MiniDumpType.WithHandleData
|
||||
| NativeMethods.MiniDumpType.WithThreadInfo
|
||||
| NativeMethods.MiniDumpType.WithUnloadedModules;
|
||||
|
||||
if (!minidump)
|
||||
flags |= NativeMethods.MiniDumpType.WithDataSegs
|
||||
| NativeMethods.MiniDumpType.WithFullMemory;
|
||||
|
||||
if (!NativeMethods.MiniDumpWriteDump(
|
||||
process.Handle,
|
||||
(uint)process.Id,
|
||||
fileStream.SafeFileHandle,
|
||||
NativeMethods.MiniDumpType.WithDataSegs
|
||||
| NativeMethods.MiniDumpType.WithFullMemory
|
||||
| NativeMethods.MiniDumpType.WithHandleData
|
||||
| NativeMethods.MiniDumpType.WithThreadInfo
|
||||
| NativeMethods.MiniDumpType.WithUnloadedModules,
|
||||
flags,
|
||||
IntPtr.Zero,
|
||||
IntPtr.Zero,
|
||||
IntPtr.Zero))
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
<Import Project="../../build/SrcCommon.props" />
|
||||
|
||||
<PropertyGroup>
|
||||
@@ -69,6 +69,8 @@
|
||||
<PackageReference Include="Cyberboss.AspNetCore.AsyncInitializer" Version="1.2.0" />
|
||||
<!-- Usage: IRC interop -->
|
||||
<PackageReference Include="Cyberboss.SmartIrc4net.Standard" Version="0.4.7" />
|
||||
<!-- Usage: .env file parsing -->
|
||||
<PackageReference Include="DotEnv.Core" Version="3.0.0" />
|
||||
<!-- Usage: Text formatter for Elasticsearch logging plugin -->
|
||||
<PackageReference Include="Elastic.CommonSchema.Serilog" Version="8.6.1" />
|
||||
<!-- Usage: GitLab interop -->
|
||||
@@ -81,6 +83,8 @@
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="8.0.1" />
|
||||
<!-- Usage: Using target JSON serializer for API -->
|
||||
<PackageReference Include="Microsoft.AspNetCore.SignalR.Protocols.NewtonsoftJson" Version="8.0.1" />
|
||||
<!-- Usage: Generating dumps of dotnet engine processes -->
|
||||
<PackageReference Include="Microsoft.Diagnostics.NETCore.Client" Version="0.2.505301" />
|
||||
<!-- Usage: Database ORM -->
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.1" />
|
||||
<!-- Usage: Automatic migration generation using command line -->
|
||||
@@ -98,7 +102,7 @@
|
||||
<!-- Usage: PostgresSQL ORM plugin -->
|
||||
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="8.0.0" />
|
||||
<!-- Usage: GitHub.com interop -->
|
||||
<PackageReference Include="Octokit" Version="9.1.0" />
|
||||
<PackageReference Include="Octokit" Version="9.1.2" />
|
||||
<!-- Usage: MYSQL/MariaDB ORM plugin -->
|
||||
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="8.0.0-beta.2" />
|
||||
<!-- Usage: Discord interop -->
|
||||
@@ -124,7 +128,7 @@
|
||||
<!-- Usage: Temporary resolution to compatibility issues with EFCore 7 and .NET 8 -->
|
||||
<PackageReference Include="System.Security.Permissions" Version="8.0.0" />
|
||||
<!-- Usage: .DeleteAsync() support for IQueryable<T>s -->
|
||||
<PackageReference Include="Z.EntityFramework.Plus.EFCore" Version="8.101.1.3" />
|
||||
<PackageReference Include="Z.EntityFramework.Plus.EFCore" Version="8.101.2.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -22,6 +22,7 @@ General:
|
||||
Session:
|
||||
HighPriorityLiveDreamDaemon: false # If DreamDaemon instances should run as higher priority processes
|
||||
LowPriorityDeploymentProcesses: true # If TGS Deployments should run as lower priority processes
|
||||
DelayCleaningFailedDeployments: false # If true, deployments that fail will not be immediately cleaned up. They will be cleaned up the next time the instance is onlined
|
||||
FileLogging:
|
||||
Directory: # Directory in which log files are stored. Windows default: %PROGRAMDATA%/tgstation-server. Linux default: /var/log/tgstation-server
|
||||
Disable: true # Disable file logging entirely
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
cd /D "%~dp0"
|
||||
cd ../../Byond/%1
|
||||
echo # Comment > server.env
|
||||
echo NOTA=Real Comment>> server.env
|
||||
@@ -0,0 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
cd "../../Byond/$1"
|
||||
|
||||
echo -e '# This is a comment\nNOTA=Real Comment\n\n\n' > server.env
|
||||
@@ -90,7 +90,7 @@ namespace Tgstation.Server.Host.Components.Engine.Tests
|
||||
var installer = new PosixByondInstaller(mockPostWriteHandler.Object, mockIOManager.Object, mockFileDownloader, mockLogger.Object);
|
||||
|
||||
const string FakePath = "fake";
|
||||
await Assert.ThrowsExceptionAsync<ArgumentNullException>(() => installer.Install(null, null, default).AsTask());
|
||||
await Assert.ThrowsExceptionAsync<ArgumentNullException>(() => installer.Install(null, null, false, default).AsTask());
|
||||
|
||||
var byondVersion = new EngineVersion
|
||||
{
|
||||
@@ -98,10 +98,10 @@ namespace Tgstation.Server.Host.Components.Engine.Tests
|
||||
Version = new Version(123, 252345),
|
||||
};
|
||||
|
||||
await Assert.ThrowsExceptionAsync<ArgumentNullException>(() => installer.Install(byondVersion, null, default).AsTask());
|
||||
await Assert.ThrowsExceptionAsync<ArgumentNullException>(() => installer.Install(byondVersion, null, false, default).AsTask());
|
||||
|
||||
byondVersion.Version = new Version(511, 1385);
|
||||
await installer.Install(byondVersion, FakePath, default);
|
||||
await installer.Install(byondVersion, FakePath, false, default);
|
||||
|
||||
mockPostWriteHandler.Verify(x => x.HandleWrite(It.IsAny<string>()), Times.Exactly(4));
|
||||
}
|
||||
|
||||
@@ -69,6 +69,7 @@ namespace Tgstation.Server.Host.System.Tests
|
||||
pathToSignalTestApp,
|
||||
$"run -c {CurrentConfig} --no-build",
|
||||
null,
|
||||
null,
|
||||
true,
|
||||
true);
|
||||
|
||||
|
||||
@@ -118,18 +118,24 @@ namespace Tgstation.Server.Tests.Live.Instance
|
||||
await using var memoryStream2 = new MemoryStream(Encoding.UTF8.GetBytes("bbb"));
|
||||
await configurationClient.Write(staticFile2, memoryStream2, cancellationToken);
|
||||
|
||||
var shellScriptExtension = new PlatformIdentifier().IsWindows ? ".bat" : ".sh";
|
||||
var scriptName = $"PreCompile-GenerateRandomResource{shellScriptExtension}";
|
||||
var resourcingScript = new ConfigurationFileRequest
|
||||
async ValueTask UploadScript(string scriptId)
|
||||
{
|
||||
Path = $"/EventScripts/{scriptName}"
|
||||
};
|
||||
var shellScriptExtension = new PlatformIdentifier().IsWindows ? ".bat" : ".sh";
|
||||
var scriptName = $"{scriptId}{shellScriptExtension}";
|
||||
var resourcingScript = new ConfigurationFileRequest
|
||||
{
|
||||
Path = $"/EventScripts/{scriptName}"
|
||||
};
|
||||
|
||||
await using var readStream = ioManager.GetFileStream($"../../../../DMAPI/LongRunning/{scriptName}", false);
|
||||
await configurationClient.Write(
|
||||
resourcingScript,
|
||||
readStream,
|
||||
cancellationToken);
|
||||
await using var readStream = ioManager.GetFileStream($"../../../../DMAPI/LongRunning/{scriptName}", false);
|
||||
await configurationClient.Write(
|
||||
resourcingScript,
|
||||
readStream,
|
||||
cancellationToken);
|
||||
}
|
||||
|
||||
await UploadScript("PreCompile-GenerateRandomResource");
|
||||
await UploadScript("EngineActiveVersionChange-SetupEnv");
|
||||
}
|
||||
|
||||
return ValueTaskExtensions.WhenAll(
|
||||
|
||||
@@ -351,13 +351,11 @@ namespace Tgstation.Server.Tests.Live.Instance
|
||||
|
||||
var deleteJob = await deleteJobTask;
|
||||
|
||||
// And this freezes DD
|
||||
await DumpTests(cancellationToken);
|
||||
// And this freezes DD (also restarts it)
|
||||
await DumpTests(false, cancellationToken);
|
||||
await DumpTests(true, cancellationToken);
|
||||
|
||||
// Restart to unlock previous BYOND version
|
||||
var restartJob = await instanceClient.DreamDaemon.Restart(cancellationToken);
|
||||
await WaitForJob(deleteJob, 15, false, null, cancellationToken);
|
||||
await WaitForJob(restartJob, 15, false, null, cancellationToken);
|
||||
}
|
||||
|
||||
async ValueTask RegressionTest1550(CancellationToken cancellationToken)
|
||||
@@ -519,14 +517,19 @@ namespace Tgstation.Server.Tests.Live.Instance
|
||||
Assert.AreEqual("sent", topicRequestResult.StringData);
|
||||
}
|
||||
|
||||
async Task DumpTests(CancellationToken cancellationToken)
|
||||
async Task DumpTests(bool mini, CancellationToken cancellationToken)
|
||||
{
|
||||
System.Console.WriteLine("TEST: WATCHDOG DUMP TESTS");
|
||||
var updated = await instanceClient.DreamDaemon.Update(new DreamDaemonRequest
|
||||
{
|
||||
Minidumps = mini,
|
||||
}, cancellationToken);
|
||||
Assert.AreEqual(mini, updated.Minidumps);
|
||||
var dumpJob = await instanceClient.DreamDaemon.CreateDump(cancellationToken);
|
||||
await WaitForJob(dumpJob, 30, false, null, cancellationToken);
|
||||
|
||||
var dumpFiles = Directory.GetFiles(Path.Combine(
|
||||
instanceClient.Metadata.Path, "Diagnostics", "ProcessDumps"), "*.dmp");
|
||||
instanceClient.Metadata.Path, "Diagnostics", "ProcessDumps"), testVersion.Engine == EngineType.OpenDream ? "*.net.dmp" : "*.dmp");
|
||||
Assert.AreEqual(1, dumpFiles.Length);
|
||||
File.Delete(dumpFiles.Single());
|
||||
|
||||
@@ -813,7 +816,21 @@ namespace Tgstation.Server.Tests.Live.Instance
|
||||
ourProcessHandler.SuspendProcess();
|
||||
global::System.Console.WriteLine($"WATCHDOG TEST {instanceClient.Metadata.Id}: FINISH PROCESS SUSPEND FOR HEALTH CHECK DEATH. WAITING FOR LIFETIME {ourProcessHandler.Id}.");
|
||||
|
||||
if (testVersion.Engine == EngineType.OpenDream && checkDump)
|
||||
{
|
||||
// because dotnet diagnostics relies on the engine process to write its own dump, we actually have to unpause it after the watchdog has decided to kill it
|
||||
// incredibly cursed, because we don't have the means to accurately tell when that will happen. ESP in CI
|
||||
return; // CBA rn
|
||||
/*
|
||||
await Task.Delay(TimeSpan.FromSeconds(30), cancellationToken);
|
||||
ourProcessHandler.ResumeProcess();
|
||||
global::System.Console.WriteLine($"WATCHDOG TEST {instanceClient.Metadata.Id}: PROCESS RESUMING FOR DOTNET DUMP. WAITING FOR LIFETIME {ourProcessHandler.Id}.");*/
|
||||
}
|
||||
|
||||
await Task.WhenAny(ourProcessHandler.Lifetime, Task.Delay(TimeSpan.FromMinutes(4), cancellationToken));
|
||||
if (testVersion.Engine == EngineType.OpenDream && checkDump && !ourProcessHandler.Lifetime.IsCompleted)
|
||||
return;
|
||||
|
||||
Assert.IsTrue(ourProcessHandler.Lifetime.IsCompleted);
|
||||
|
||||
var timeout = 20;
|
||||
|
||||
@@ -1105,6 +1105,7 @@ namespace Tgstation.Server.Tests.Live
|
||||
repoPath,
|
||||
args,
|
||||
null,
|
||||
null,
|
||||
true,
|
||||
true);
|
||||
|
||||
|
||||
@@ -122,6 +122,7 @@ namespace Tgstation.Server.Tests
|
||||
StartProfiler = false,
|
||||
LogOutput = true,
|
||||
MapThreads = 69,
|
||||
Minidumps = true,
|
||||
},
|
||||
DreamMakerSettings = new Host.Models.DreamMakerSettings
|
||||
{
|
||||
|
||||
@@ -28,7 +28,7 @@ namespace Tgstation.Server.Tests
|
||||
Mock.Of<ILogger<ProcessExecutor>>(),
|
||||
loggerFactory);
|
||||
|
||||
await using var process = processExecutor.LaunchProcess("test." + platformIdentifier.ScriptFileExtension, ".", string.Empty, null, true, true);
|
||||
await using var process = processExecutor.LaunchProcess("test." + platformIdentifier.ScriptFileExtension, ".", string.Empty, null, null, true, true);
|
||||
using var cts = new CancellationTokenSource();
|
||||
cts.CancelAfter(3000);
|
||||
var exitCode = await process.Lifetime.WaitAsync(cts.Token);
|
||||
@@ -63,7 +63,7 @@ namespace Tgstation.Server.Tests
|
||||
File.Delete(tempFile);
|
||||
try
|
||||
{
|
||||
await using (var process = processExecutor.LaunchProcess("test." + platformIdentifier.ScriptFileExtension, ".", string.Empty, tempFile, true, true))
|
||||
await using (var process = processExecutor.LaunchProcess("test." + platformIdentifier.ScriptFileExtension, ".", string.Empty, null, tempFile, true, true))
|
||||
{
|
||||
using var cts = new CancellationTokenSource();
|
||||
cts.CancelAfter(3000);
|
||||
|
||||
@@ -477,7 +477,7 @@ namespace Tgstation.Server.Tests
|
||||
if (byondInstaller is WindowsByondInstaller)
|
||||
typeof(WindowsByondInstaller).GetField("installedDirectX", BindingFlags.Instance | BindingFlags.NonPublic).SetValue(byondInstaller, true);
|
||||
|
||||
await byondInstaller.Install(engineVersion, tempPath, default);
|
||||
await byondInstaller.Install(engineVersion, tempPath, false, default);
|
||||
|
||||
var binPath = (string)typeof(ByondInstallerBase).GetField("ByondBinPath", BindingFlags.Static | BindingFlags.NonPublic).GetValue(null);
|
||||
var ddNameFunc = installerType.GetMethod("GetDreamDaemonName", BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
@@ -503,6 +503,7 @@ namespace Tgstation.Server.Tests
|
||||
Environment.CurrentDirectory,
|
||||
"fake.dmb -map-threads 3 -close",
|
||||
null,
|
||||
null,
|
||||
true,
|
||||
true);
|
||||
|
||||
|
||||
@@ -155,6 +155,8 @@ EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "LongRunning", "LongRunning", "{EB1DDE8C-CA6F-4BE3-947B-597CA8EABEA5}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
tests\DMAPI\LongRunning\Config.dm = tests\DMAPI\LongRunning\Config.dm
|
||||
tests\DMAPI\LongRunning\EngineActiveVersionChange-SetupEnv.bat = tests\DMAPI\LongRunning\EngineActiveVersionChange-SetupEnv.bat
|
||||
tests\DMAPI\LongRunning\EngineActiveVersionChange-SetupEnv.sh = tests\DMAPI\LongRunning\EngineActiveVersionChange-SetupEnv.sh
|
||||
tests\DMAPI\LongRunning\long_running_test.dme = tests\DMAPI\LongRunning\long_running_test.dme
|
||||
tests\DMAPI\LongRunning\long_running_test_copy.dme = tests\DMAPI\LongRunning\long_running_test_copy.dme
|
||||
tests\DMAPI\LongRunning\long_running_test_rooted.dme = tests\DMAPI\LongRunning\long_running_test_rooted.dme
|
||||
@@ -171,8 +173,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ApiFree", "ApiFree", "{7B8F
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "BasicOperation", "BasicOperation", "{F32B9514-AAD9-429D-841A-ED810FC2598C}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
tests\DMAPI\BasicOperation\Config.dm = tests\DMAPI\BasicOperation\Config.dm
|
||||
tests\DMAPI\BasicOperation\basic operation_test.dme = tests\DMAPI\BasicOperation\basic operation_test.dme
|
||||
tests\DMAPI\BasicOperation\Config.dm = tests\DMAPI\BasicOperation\Config.dm
|
||||
tests\DMAPI\BasicOperation\Test.dm = tests\DMAPI\BasicOperation\Test.dm
|
||||
EndProjectSection
|
||||
EndProject
|
||||
|
||||
Reference in New Issue
Block a user