Skip to content

Commit

Permalink
Merge pull request #2032 from tgstation/FixDotnetOD
Browse files Browse the repository at this point in the history
Fix OD with Nix
  • Loading branch information
Cyberboss authored Nov 30, 2024
2 parents 79cd074 + 9bb0419 commit 179572f
Show file tree
Hide file tree
Showing 10 changed files with 177 additions and 124 deletions.
8 changes: 5 additions & 3 deletions build/package/nix/package.nix
Original file line number Diff line number Diff line change
Expand Up @@ -78,12 +78,13 @@ stdenv.mkDerivation {
};

buildInputs = with pkgs; [
dotnetCorePackages.aspnetcore_8_0
dotnetCorePackages.sdk_8_0
gdb
systemd
zlib
gcc_multi
glibc
bash
];
nativeBuildInputs = with pkgs; [
makeWrapper
Expand All @@ -98,12 +99,13 @@ stdenv.mkDerivation {
mkdir -p $out/bin
unzip "${fixedOutput}/ServerConsole.zip" -d $out/bin
rm -rf $out/bin/lib
makeWrapper ${pkgs.dotnetCorePackages.aspnetcore_8_0}/dotnet $out/bin/tgstation-server --suffix PATH : ${
makeWrapper ${pkgs.dotnetCorePackages.sdk_8_0}/dotnet $out/bin/tgstation-server --suffix PATH : ${
lib.makeBinPath (
with pkgs;
[
dotnetCorePackages.aspnetcore_8_0
dotnetCorePackages.sdk_8_0
gdb
bash
]
)
} --suffix LD_LIBRARY_PATH : ${
Expand Down
11 changes: 11 additions & 0 deletions build/package/nix/tgstation-server.nix
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,12 @@ let
];

byond-patcher = pkgs-i686.writeShellScriptBin "EngineInstallComplete-050-TgsPatchELFByond.sh" ''
# If the file doesn't exist, assume OD
if [[ ! -f ../../Byond/$1/byond/bin/DreamDaemon ]] ; then
echo "DreamDaemon doesn't appear to exist. Assuming OD install"
exit
fi
BYOND_PATH=$(realpath ../../Byond/$1/byond/bin/)
${pkgs.patchelf}/bin/patchelf --set-interpreter "$(cat ${stdenv.cc}/nix-support/dynamic-linker)" \
Expand Down Expand Up @@ -109,6 +115,11 @@ in
group = cfg.groupname;
mode = "0640";
};
"tgstation-server.d/EventScripts/README.txt" = {
text = "TGS event scripts placed here will be executed by all online instances";
group = cfg.groupname;
mode = "0640";
};
};

systemd.services.tgstation-server = {
Expand Down
35 changes: 18 additions & 17 deletions src/Tgstation.Server.Host/Components/Engine/ByondInstallerBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -74,29 +74,30 @@ protected ByondInstallerBase(IIOManager ioManager, ILogger<ByondInstallerBase> l
}

/// <inheritdoc />
public override IEngineInstallation CreateInstallation(EngineVersion version, string path, Task installationTask)
public override ValueTask<IEngineInstallation> CreateInstallation(EngineVersion version, string path, Task installationTask, CancellationToken cancellationToken)
{
CheckVersionValidity(version);

var installationIOManager = new ResolvingIOManager(IOManager, path);
var supportsMapThreads = version.Version >= MapThreadsVersion;

return new ByondInstallation(
installationIOManager,
installationTask,
version,
installationIOManager.ResolvePath(
installationIOManager.ConcatPath(
ByondBinPath,
GetDreamDaemonName(
version.Version!,
out var supportsCli))),
installationIOManager.ResolvePath(
installationIOManager.ConcatPath(
ByondBinPath,
DreamMakerName)),
supportsCli,
supportsMapThreads);
return ValueTask.FromResult<IEngineInstallation>(
new ByondInstallation(
installationIOManager,
installationTask,
version,
installationIOManager.ResolvePath(
installationIOManager.ConcatPath(
ByondBinPath,
GetDreamDaemonName(
version.Version!,
out var supportsCli))),
installationIOManager.ResolvePath(
installationIOManager.ConcatPath(
ByondBinPath,
DreamMakerName)),
supportsCli,
supportsMapThreads));
}

/// <inheritdoc />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ public Task CleanCache(CancellationToken cancellationToken)
=> Task.WhenAll(delegatedInstallers.Values.Select(installer => installer.CleanCache(cancellationToken)));

/// <inheritdoc />
public IEngineInstallation CreateInstallation(EngineVersion version, string path, Task installationTask)
=> DelegateCall(version, installer => installer.CreateInstallation(version, path, installationTask));
public ValueTask<IEngineInstallation> CreateInstallation(EngineVersion version, string path, Task installationTask, CancellationToken cancellationToken)
=> DelegateCall(version, installer => installer.CreateInstallation(version, path, installationTask, cancellationToken));

/// <inheritdoc />
public ValueTask<IEngineInstallationData> DownloadVersion(EngineVersion version, JobProgressReporter jobProgressReporter, CancellationToken cancellationToken)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ protected EngineInstallerBase(IIOManager ioManager, ILogger<EngineInstallerBase>
}

/// <inheritdoc />
public abstract IEngineInstallation CreateInstallation(EngineVersion version, string path, Task installationTask);
public abstract ValueTask<IEngineInstallation> CreateInstallation(EngineVersion version, string path, Task installationTask, CancellationToken cancellationToken);

/// <inheritdoc />
public abstract Task CleanCache(CancellationToken cancellationToken);
Expand Down
175 changes: 93 additions & 82 deletions src/Tgstation.Server.Host/Components/Engine/EngineManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -337,7 +337,8 @@ async ValueTask ReadVersion(string path)

try
{
AddInstallationContainer(version, path, Task.CompletedTask);
var installation = await engineInstaller.CreateInstallation(version, path, Task.CompletedTask, cancellationToken);
AddInstallationContainer(installation);
logger.LogDebug("Added detected BYOND version {versionKey}...", version);
}
catch (Exception ex)
Expand Down Expand Up @@ -410,107 +411,121 @@ async ValueTask<EngineExecutableLock> AssertAndLockVersion(
IEngineInstallation installation;
EngineExecutableLock installLock;
bool installedOrInstalling;
lock (installedVersions)

// loop is because of the race condition with potentialInstallation, installedVersions, and CustomIteration selection
while (true)
{
if (customVersionStream != null)
lock (installedVersions)
{
var customInstallationNumber = 1;
do
if (customVersionStream != null)
{
version.CustomIteration = customInstallationNumber++;
var customInstallationNumber = 1;
do
{
version.CustomIteration = customInstallationNumber++;
}
while (installedVersions.ContainsKey(version));
}
while (installedVersions.ContainsKey(version));
}

installedOrInstalling = installedVersions.TryGetValue(version, out var installationContainerNullable);
ReferenceCountingContainer<IEngineInstallation, EngineExecutableLock> installationContainer;
if (!installedOrInstalling)
{
if (!allowInstallation)
throw new InvalidOperationException($"Engine version {version} not installed!");

installationContainer = AddInstallationContainer(
version,
ioManager.ResolvePath(version.ToString()),
ourTcs.Task);
}
else
installationContainer = installationContainerNullable!;

installation = installationContainer.Instance;
installLock = installationContainer.AddReference();
}
var potentialInstallation = await engineInstaller.CreateInstallation(
version,
ioManager.ResolvePath(version.ToString()),
ourTcs.Task,
cancellationToken);

var deploymentPipelineProcesses = !neededForLock;
try
{
if (installedOrInstalling)
lock (installedVersions)
{
progressReporter.StageName = "Waiting for existing installation job...";
if (customVersionStream != null && installedVersions.ContainsKey(version))
continue;

if (neededForLock && !installation.InstallationTask.IsCompleted)
logger.LogWarning("The required engine version ({version}) is not readily available! We will have to wait for it to install.", version);
installedOrInstalling = installedVersions.TryGetValue(version, out var installationContainerNullable);
ReferenceCountingContainer<IEngineInstallation, EngineExecutableLock> installationContainer;
if (!installedOrInstalling)
{
if (!allowInstallation)
throw new InvalidOperationException($"Engine version {version} not installed!");

await installation.InstallationTask.WaitAsync(cancellationToken);
return installLock;
installationContainer = AddInstallationContainer(potentialInstallation);
}
else
installationContainer = installationContainerNullable!;

installation = installationContainer.Instance;
installLock = installationContainer.AddReference();
}

// okay up to us to install it then
string? installPath = null;
var deploymentPipelineProcesses = !neededForLock;
try
{
if (customVersionStream != null)
logger.LogInformation("Installing custom engine version as {version}...", version);
else if (neededForLock)
if (installedOrInstalling)
{
if (version.CustomIteration.HasValue)
throw new JobException(ErrorCode.EngineNonExistentCustomVersion);
progressReporter.StageName = "Waiting for existing installation job...";

if (neededForLock && !installation.InstallationTask.IsCompleted)
logger.LogWarning("The required engine version ({version}) is not readily available! We will have to wait for it to install.", version);

logger.LogWarning("The required engine version ({version}) is not readily available! We will have to install it.", version);
await installation.InstallationTask.WaitAsync(cancellationToken);
return installLock;
}
else
logger.LogInformation("Requested engine version {version} not currently installed. Doing so now...", version);

progressReporter.StageName = "Running event";
// okay up to us to install it then
string? installPath = null;
try
{
if (customVersionStream != null)
logger.LogInformation("Installing custom engine version as {version}...", version);
else if (neededForLock)
{
if (version.CustomIteration.HasValue)
throw new JobException(ErrorCode.EngineNonExistentCustomVersion);

logger.LogWarning("The required engine version ({version}) is not readily available! We will have to install it.", version);
}
else
logger.LogInformation("Requested engine version {version} not currently installed. Doing so now...", version);

var versionString = version.ToString();
await eventConsumer.HandleEvent(EventType.EngineInstallStart, new List<string> { versionString }, deploymentPipelineProcesses, cancellationToken);
progressReporter.StageName = "Running event";

installPath = await InstallVersionFiles(progressReporter, version, customVersionStream, deploymentPipelineProcesses, cancellationToken);
await eventConsumer.HandleEvent(EventType.EngineInstallComplete, new List<string> { versionString }, deploymentPipelineProcesses, cancellationToken);
var versionString = version.ToString();
await eventConsumer.HandleEvent(EventType.EngineInstallStart, new List<string> { versionString }, deploymentPipelineProcesses, cancellationToken);

ourTcs.SetResult();
}
catch (Exception ex)
{
if (installPath != null)
installPath = await InstallVersionFiles(progressReporter, version, customVersionStream, deploymentPipelineProcesses, cancellationToken);
await eventConsumer.HandleEvent(EventType.EngineInstallComplete, new List<string> { versionString }, deploymentPipelineProcesses, cancellationToken);

ourTcs.SetResult();
}
catch (Exception ex)
{
try
if (installPath != null)
{
logger.LogDebug("Cleaning up failed installation at {path}...", installPath);
await ioManager.DeleteDirectory(installPath, cancellationToken);
}
catch (Exception ex2)
{
logger.LogError(ex2, "Error cleaning up failed installation!");
try
{
logger.LogDebug("Cleaning up failed installation at {path}...", installPath);
await ioManager.DeleteDirectory(installPath, cancellationToken);
}
catch (Exception ex2)
{
logger.LogError(ex2, "Error cleaning up failed installation!");
}
}
}
else if (ex is not OperationCanceledException)
await eventConsumer.HandleEvent(EventType.EngineInstallFail, new List<string> { ex.Message }, deploymentPipelineProcesses, cancellationToken);
else if (ex is not OperationCanceledException)
await eventConsumer.HandleEvent(EventType.EngineInstallFail, new List<string> { ex.Message }, deploymentPipelineProcesses, cancellationToken);

lock (installedVersions)
installedVersions.Remove(version);
lock (installedVersions)
installedVersions.Remove(version);

ourTcs.SetException(ex);
ourTcs.SetException(ex);
throw;
}

return installLock;
}
catch
{
installLock.Dispose();
throw;
}

return installLock;
}
catch
{
installLock.Dispose();
throw;
}
}

Expand Down Expand Up @@ -616,18 +631,14 @@ await ioManager.WriteAllBytes(
/// <summary>
/// Create and add a new <see cref="IEngineInstallation"/> to <see cref="installedVersions"/>.
/// </summary>
/// <param name="version">The <see cref="Version"/> being added.</param>
/// <param name="installPath">The path to the installation.</param>
/// <param name="installationTask">The <see cref="ValueTask"/> representing the installation process.</param>
/// <returns>The new <see cref="IEngineInstallation"/>.</returns>
ReferenceCountingContainer<IEngineInstallation, EngineExecutableLock> AddInstallationContainer(EngineVersion version, string installPath, Task installationTask)
/// <param name="installation">The <see cref="IEngineInstallation"/> being added.</param>
/// <returns>A new <see cref="ReferenceCountingContainer{TWrapped, TReference}"/> for the <see cref="IEngineInstallation"/>/<see cref="EngineExecutableLock"/>.</returns>
ReferenceCountingContainer<IEngineInstallation, EngineExecutableLock> AddInstallationContainer(IEngineInstallation installation)
{
var installation = engineInstaller.CreateInstallation(version, installPath, installationTask);

var installationContainer = new ReferenceCountingContainer<IEngineInstallation, EngineExecutableLock>(installation);

lock (installedVersions)
installedVersions.Add(version, installationContainer);
installedVersions.Add(installation.Version, installationContainer);

return installationContainer;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,9 @@ interface IEngineInstaller
/// <param name="version">The <see cref="EngineVersion"/> of the installation.</param>
/// <param name="path">The path to the installation.</param>
/// <param name="installationTask">The <see cref="Task"/> representing the installation process for the installation.</param>
/// <returns>The <see cref="IEngineInstallation"/>.</returns>
IEngineInstallation CreateInstallation(EngineVersion version, string path, Task installationTask);
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation.</param>
/// <returns>A <see cref="ValueTask{TResult}"/> resulting in the <see cref="IEngineInstallation"/>.</returns>
ValueTask<IEngineInstallation> CreateInstallation(EngineVersion version, string path, Task installationTask, CancellationToken cancellationToken);

/// <summary>
/// Download a given engine <paramref name="version"/>.
Expand Down
Loading

0 comments on commit 179572f

Please sign in to comment.