mirror of
https://github.com/tgstation/tgstation-server.git
synced 2026-08-27 23:17:20 +01:00
Remove support for Ultrasafe configurations due to the fucking file read prompts
This commit is contained in:
@@ -32,6 +32,10 @@
|
||||
/// </summary>
|
||||
Verifying,
|
||||
/// <summary>
|
||||
/// Post-compile scripts are running
|
||||
/// </summary>
|
||||
PostCompile,
|
||||
/// <summary>
|
||||
/// The compile results are being duplicated
|
||||
/// </summary>
|
||||
Duplicating,
|
||||
@@ -40,10 +44,6 @@
|
||||
/// </summary>
|
||||
Symlinking,
|
||||
/// <summary>
|
||||
/// Post-compile scripts are running
|
||||
/// </summary>
|
||||
PostCompile,
|
||||
/// <summary>
|
||||
/// A failed compile job is being erased
|
||||
/// </summary>
|
||||
Cleanup
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
/// </summary>
|
||||
Safe,
|
||||
/// <summary>
|
||||
/// Server will not be able to run shell commands or access anything but temporary files
|
||||
/// Server will not be able to run shell commands or access anything but temporary files. Currently unsupported!
|
||||
/// </summary>
|
||||
Ultrasafe
|
||||
}
|
||||
|
||||
@@ -100,22 +100,24 @@ namespace Tgstation.Server.Host.Components.Compiler
|
||||
/// Run a quick DD instance to test the DMAPI is installed on the target code
|
||||
/// </summary>
|
||||
/// <param name="timeout">The timeout in seconds for validation</param>
|
||||
/// <param name="securityLevel">The <see cref="DreamDaemonSecurity"/> level to use to validate the API</param>
|
||||
/// <param name="job">The <see cref="Models.CompileJob"/> for the operation</param>
|
||||
/// <param name="byondLock">The current <see cref="IByondExecutableLock"/></param>
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation</param>
|
||||
/// <returns>A <see cref="Task{TResult}"/> resulting in <see langword="true"/> if the DMAPI was successfully validated, <see langword="false"/> otherwise</returns>
|
||||
async Task<bool> VerifyApi(uint timeout, Models.CompileJob job, IByondExecutableLock byondLock, CancellationToken cancellationToken)
|
||||
async Task<bool> VerifyApi(uint timeout, DreamDaemonSecurity securityLevel, Models.CompileJob job, IByondExecutableLock byondLock, CancellationToken cancellationToken)
|
||||
{
|
||||
logger.LogTrace("Verifying DMAPI...");
|
||||
var launchParameters = new DreamDaemonLaunchParameters
|
||||
{
|
||||
AllowWebClient = false,
|
||||
PrimaryPort = 0, //pick any port
|
||||
SecurityLevel = DreamDaemonSecurity.Safe, //all it needs to read the file and exit
|
||||
SecurityLevel = securityLevel, //all it needs to read the file and exit
|
||||
StartupTimeout = timeout
|
||||
};
|
||||
|
||||
var dirA = ioManager.ConcatPath(job.DirectoryName.ToString(), ADirectoryName);
|
||||
var provider = new TemporaryDmbProvider(ioManager.ResolvePath(dirA), String.Join('.', job.DmeName, DmbExtension), job);
|
||||
var provider = new TemporaryDmbProvider(ioManager.ResolvePath(dirA), String.Concat(job.DmeName, DmbExtension), job);
|
||||
|
||||
var timeoutAt = DateTimeOffset.Now.AddSeconds(timeout);
|
||||
using (var controller = await sessionControllerFactory.LaunchNew(launchParameters, provider, byondLock, true, true, true, cancellationToken).ConfigureAwait(false))
|
||||
@@ -129,9 +131,14 @@ namespace Tgstation.Server.Host.Components.Compiler
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
}
|
||||
if (!controller.Lifetime.IsCompleted)
|
||||
{
|
||||
logger.LogDebug("API validation timed out!");
|
||||
return false;
|
||||
}
|
||||
|
||||
return controller.ApiValidated;
|
||||
var validated = controller.ApiValidated;
|
||||
logger.LogTrace("API valid: {0}", validated);
|
||||
return validated;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -167,6 +174,7 @@ namespace Tgstation.Server.Host.Components.Compiler
|
||||
var dmTcs = new TaskCompletionSource<object>();
|
||||
dm.Exited += (a, b) => dmTcs.TrySetResult(null);
|
||||
|
||||
logger.LogTrace("Running DreamMaker...");
|
||||
dm.Start();
|
||||
dm.BeginOutputReadLine();
|
||||
dm.BeginErrorReadLine();
|
||||
@@ -184,8 +192,10 @@ namespace Tgstation.Server.Host.Components.Compiler
|
||||
}
|
||||
}
|
||||
|
||||
job.Output = OutputList.ToString();
|
||||
job.ExitCode = dm.ExitCode;
|
||||
logger.LogDebug("DreamMaker exit code: {0}", job.ExitCode);
|
||||
job.Output = OutputList.ToString();
|
||||
logger.LogTrace("DreamMaker output: {0}", job.Output);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -209,7 +219,18 @@ namespace Tgstation.Server.Host.Components.Compiler
|
||||
var dmeModifications = await dmeModificationsTask.ConfigureAwait(false);
|
||||
|
||||
if (dmeModifications == null || dmeModifications.TotalDmeOverwrite)
|
||||
{
|
||||
if (dmeModifications != null)
|
||||
logger.LogDebug(".dme replacement configured!");
|
||||
else
|
||||
logger.LogTrace("No .dme modifications required.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (dmeModifications.HeadIncludeLine != null)
|
||||
logger.LogDebug("Head .dme include line: {0}", dmeModifications.HeadIncludeLine);
|
||||
if (dmeModifications.TailIncludeLine != null)
|
||||
logger.LogDebug("Tail .dme include line: {0}", dmeModifications.TailIncludeLine);
|
||||
|
||||
var dmeLines = new List<string>(dme.Split(new[] { Environment.NewLine }, StringSplitOptions.None));
|
||||
for (var I = 0; I < dmeLines.Count; ++I)
|
||||
@@ -232,8 +253,14 @@ namespace Tgstation.Server.Host.Components.Compiler
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<Models.CompileJob> Compile(string projectName, uint apiValidateTimeout, IRepository repository, CancellationToken cancellationToken)
|
||||
public async Task<Models.CompileJob> Compile(string projectName, DreamDaemonSecurity securityLevel, uint apiValidateTimeout, IRepository repository, CancellationToken cancellationToken)
|
||||
{
|
||||
if (repository == null)
|
||||
throw new ArgumentNullException(nameof(repository));
|
||||
|
||||
if (securityLevel == DreamDaemonSecurity.Ultrasafe)
|
||||
throw new ArgumentOutOfRangeException(nameof(securityLevel), securityLevel, "Cannot compile with ultrasafe security!");
|
||||
|
||||
logger.LogTrace("Begin Compile");
|
||||
|
||||
var job = new Models.CompileJob
|
||||
@@ -242,11 +269,14 @@ namespace Tgstation.Server.Host.Components.Compiler
|
||||
DmeName = projectName
|
||||
};
|
||||
|
||||
logger.LogTrace("Compile output GUID: {0}", job.DirectoryName);
|
||||
|
||||
lock (this)
|
||||
{
|
||||
if(Status != CompilerStatus.Idle)
|
||||
{
|
||||
job.Output = "There is already a compile in progress!";
|
||||
logger.LogInformation(job.Output);
|
||||
return job;
|
||||
}
|
||||
|
||||
@@ -260,6 +290,7 @@ namespace Tgstation.Server.Host.Components.Compiler
|
||||
|
||||
async Task CleanupFailedCompile()
|
||||
{
|
||||
logger.LogTrace("Cleaning compile directory...");
|
||||
Status = CompilerStatus.Cleanup;
|
||||
try
|
||||
{
|
||||
@@ -273,6 +304,7 @@ namespace Tgstation.Server.Host.Components.Compiler
|
||||
|
||||
try
|
||||
{
|
||||
logger.LogTrace("Copying repository to game directory...");
|
||||
//copy the repository
|
||||
var fullDirA = ioManager.ResolvePath(dirA);
|
||||
var repoOrigin = repository.Origin;
|
||||
@@ -287,16 +319,20 @@ namespace Tgstation.Server.Host.Components.Compiler
|
||||
|
||||
if (job.DmeName == null)
|
||||
{
|
||||
logger.LogTrace("Searching for available .dmes...");
|
||||
var path = (await ioManager.GetFilesWithExtension(dirA, DmeExtension, cancellationToken).ConfigureAwait(false)).FirstOrDefault();
|
||||
if (path == default)
|
||||
{
|
||||
job.Output = "Unable to find any .dme!";
|
||||
logger.LogWarning(job.Output);
|
||||
return job;
|
||||
}
|
||||
var dmeWithExtension = ioManager.GetFileName(path);
|
||||
job.DmeName = dmeWithExtension.Substring(0, dmeWithExtension.Length - DmeExtension.Length - 1);
|
||||
}
|
||||
|
||||
logger.LogDebug("Selected {0}.dme for compilation!", job.DmeName);
|
||||
|
||||
await ModifyDme(job, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
Status = CompilerStatus.Compiling;
|
||||
@@ -311,7 +347,7 @@ namespace Tgstation.Server.Host.Components.Compiler
|
||||
|
||||
Status = CompilerStatus.Verifying;
|
||||
|
||||
ddVerified = job.ExitCode == 0 && await VerifyApi(apiValidateTimeout, job, byondLock, cancellationToken).ConfigureAwait(false);
|
||||
ddVerified = job.ExitCode == 0 && await VerifyApi(apiValidateTimeout, securityLevel, job, byondLock, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
if (!ddVerified)
|
||||
@@ -324,11 +360,17 @@ namespace Tgstation.Server.Host.Components.Compiler
|
||||
{
|
||||
job.DMApiValidated = true;
|
||||
|
||||
logger.LogTrace("Running post compile event...");
|
||||
Status = CompilerStatus.PostCompile;
|
||||
await eventConsumer.HandleEvent(EventType.CompileComplete, new List<string> { ioManager.ResolvePath(ioManager.ConcatPath(job.DirectoryName.ToString(), ADirectoryName)) }, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
logger.LogTrace("Duplicating compiled game...");
|
||||
Status = CompilerStatus.Duplicating;
|
||||
|
||||
//duplicate the dmb et al
|
||||
await ioManager.CopyDirectory(dirA, dirB, null, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
logger.LogTrace("Applying static game file symlinks...");
|
||||
Status = CompilerStatus.Symlinking;
|
||||
|
||||
//symlink in the static data
|
||||
@@ -336,8 +378,8 @@ namespace Tgstation.Server.Host.Components.Compiler
|
||||
var symBTask = configuration.SymlinkStaticFilesTo(ioManager.ResolvePath(dirB), cancellationToken);
|
||||
|
||||
await Task.WhenAll(symATask, symBTask).ConfigureAwait(false);
|
||||
Status = CompilerStatus.PostCompile;
|
||||
await eventConsumer.HandleEvent(EventType.CompileComplete, null, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
logger.LogDebug("Compile complete!");
|
||||
}
|
||||
return job;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Tgstation.Server.Api.Models;
|
||||
using Tgstation.Server.Host.Components.Repository;
|
||||
using Tgstation.Server.Host.Models;
|
||||
|
||||
namespace Tgstation.Server.Host.Components.Compiler
|
||||
{
|
||||
@@ -19,10 +19,11 @@ namespace Tgstation.Server.Host.Components.Compiler
|
||||
/// Starts a compile
|
||||
/// </summary>
|
||||
/// <param name="projectName">The optional name of the .dme to compile without the extension if not pre</param>
|
||||
/// <param name="securityLevel">The <see cref="DreamDaemonSecurity"/> level allowed for API validation</param>
|
||||
/// <param name="apiValidateTimeout">The time in seconds to wait while validating the API</param>
|
||||
/// <param name="repository">The <see cref="IRepository"/> to copy from</param>
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation</param>
|
||||
/// <returns>A <see cref="Task{TResult}"/> resulting in the partially populated <see cref="CompileJob"/> for the operation. In particular, note the <see cref="CompileJob.RevisionInformation"/> field will only have it's <see cref="Api.Models.Internal.RevisionInformation.CommitSha"/> field populated</returns>
|
||||
Task<CompileJob> Compile(string projectName, uint apiValidateTimeout, IRepository repository, CancellationToken cancellationToken);
|
||||
Task<Models.CompileJob> Compile(string projectName, DreamDaemonSecurity securityLevel, uint apiValidateTimeout, IRepository repository, CancellationToken cancellationToken);
|
||||
}
|
||||
}
|
||||
@@ -51,7 +51,7 @@
|
||||
/// </summary>
|
||||
CompileFailure = 10,
|
||||
/// <summary>
|
||||
/// No parameters
|
||||
/// Parameters: Game directory path
|
||||
/// </summary>
|
||||
CompileComplete = 11,
|
||||
|
||||
|
||||
@@ -122,15 +122,19 @@ namespace Tgstation.Server.Host.Components
|
||||
|
||||
RepositorySettings repositorySettings = null;
|
||||
string projectName = null;
|
||||
uint timeout = 0;
|
||||
DreamDaemonSettings ddSettings = null;
|
||||
var dbTask = databaseContextFactory.UseContext(async (db) =>
|
||||
{
|
||||
var instanceQuery = db.Instances.Where(x => x.Id == metadata.Id);
|
||||
var timeoutTask = instanceQuery.Select(x => x.DreamDaemonSettings.StartupTimeout).FirstAsync(cancellationToken);
|
||||
var ddSettingsTask = instanceQuery.Select(x => x.DreamDaemonSettings).Select(x => new DreamDaemonSettings
|
||||
{
|
||||
StartupTimeout = x.StartupTimeout,
|
||||
SecurityLevel = x.SecurityLevel
|
||||
}).FirstAsync(cancellationToken);
|
||||
var projectNameTask = instanceQuery.Select(x => x.DreamMakerSettings.ProjectName).FirstOrDefaultAsync(cancellationToken);
|
||||
repositorySettings = await instanceQuery.Select(x => x.RepositorySettings).FirstOrDefaultAsync(cancellationToken).ConfigureAwait(false);
|
||||
projectName = await projectNameTask.ConfigureAwait(false);
|
||||
timeout = (await timeoutTask.ConfigureAwait(false)).Value;
|
||||
ddSettings = await ddSettingsTask.ConfigureAwait(false);
|
||||
});
|
||||
using (var repo = await RepositoryManager.LoadRepository(cancellationToken).ConfigureAwait(false))
|
||||
{
|
||||
@@ -170,7 +174,7 @@ namespace Tgstation.Server.Host.Components
|
||||
if (repositorySettings.AutoUpdatesSynchronize.Value && startSha != repo.Head)
|
||||
await repo.Sychronize(repositorySettings.AccessUser, repositorySettings.AccessToken, shouldSyncTracked, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
var job = await DreamMaker.Compile(projectName, timeout, repo, cancellationToken).ConfigureAwait(false);
|
||||
var job = await DreamMaker.Compile(projectName, ddSettings.SecurityLevel.Value, ddSettings.StartupTimeout.Value, repo, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
catch (OperationCanceledException) { }
|
||||
|
||||
@@ -169,6 +169,9 @@ namespace Tgstation.Server.Host.Controllers
|
||||
|| !CheckModified(x => x.SoftShutdown, DreamDaemonRights.SoftShutdown)
|
||||
|| !CheckModified(x => x.StartupTimeout, DreamDaemonRights.SetStartupTimeout))
|
||||
return Forbid();
|
||||
|
||||
if (current.SecurityLevel == DreamDaemonSecurity.Ultrasafe)
|
||||
return BadRequest(new ErrorMessage { Message = "TGS does not support the ultrasafe DreamDaemon configuration!" });
|
||||
|
||||
var wd = instanceManager.GetInstance(Instance).Watchdog;
|
||||
|
||||
|
||||
@@ -101,9 +101,12 @@ namespace Tgstation.Server.Host.Controllers
|
||||
var instanceManager = serviceProvider.GetRequiredService<IInstanceManager>();
|
||||
var databaseContext = serviceProvider.GetRequiredService<IDatabaseContext>();
|
||||
|
||||
var timeoutTask = databaseContext.DreamDaemonSettings.Where(x => x.InstanceId == instanceModel.Id).Select(x => x.StartupTimeout).FirstOrDefaultAsync(cancellationToken);
|
||||
var ddSettingsTask = databaseContext.DreamDaemonSettings.Where(x => x.InstanceId == instanceModel.Id).Select(x => new DreamDaemonSettings{
|
||||
StartupTimeout = x.StartupTimeout,
|
||||
SecurityLevel = x.SecurityLevel
|
||||
}).FirstOrDefaultAsync(cancellationToken);
|
||||
var projectName = await databaseContext.DreamMakerSettings.Where(x => x.InstanceId == instanceModel.Id).Select(x => x.ProjectName).FirstOrDefaultAsync(cancellationToken).ConfigureAwait(false);
|
||||
var timeout = await timeoutTask.ConfigureAwait(false);
|
||||
var ddSettings = await ddSettingsTask.ConfigureAwait(false);
|
||||
|
||||
var instance = instanceManager.GetInstance(instanceModel);
|
||||
|
||||
@@ -119,7 +122,7 @@ namespace Tgstation.Server.Host.Controllers
|
||||
}
|
||||
repoSha = repo.Head;
|
||||
revInfoTask = databaseContext.RevisionInformations.Where(x => x.CommitSha == repoSha).Select(x => new RevisionInformation { Id = x.Id }).FirstOrDefaultAsync();
|
||||
compileJob = await instance.DreamMaker.Compile(projectName, timeout.Value, repo, cancellationToken).ConfigureAwait(false);
|
||||
compileJob = await instance.DreamMaker.Compile(projectName, ddSettings.SecurityLevel.Value, ddSettings.StartupTimeout.Value, repo, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
if (compileJob.DMApiValidated != true)
|
||||
|
||||
@@ -117,7 +117,7 @@ namespace Tgstation.Server.Host.Controllers
|
||||
AutoStart = false,
|
||||
PrimaryPort = 1337,
|
||||
SecondaryPort = 1338,
|
||||
SecurityLevel = DreamDaemonSecurity.Ultrasafe,
|
||||
SecurityLevel = DreamDaemonSecurity.Safe,
|
||||
SoftRestart = false,
|
||||
SoftShutdown = false,
|
||||
StartupTimeout = 20
|
||||
|
||||
Reference in New Issue
Block a user