Merge pull request #1774 from tgstation/1773-ActiveNotMinimum [TGSDeploy]

v6.1.3: Fix aggressive hardlinking
This commit is contained in:
Jordan Dominion
2024-01-20 12:01:55 -05:00
committed by GitHub
7 changed files with 26 additions and 17 deletions
+1 -1
View File
@@ -3,7 +3,7 @@
<!-- Integration tests will ensure they match across the board -->
<Import Project="WebpanelVersion.props" />
<PropertyGroup>
<TgsCoreVersion>6.1.2</TgsCoreVersion>
<TgsCoreVersion>6.1.3</TgsCoreVersion>
<TgsConfigVersion>5.0.0</TgsConfigVersion>
<TgsApiVersion>10.0.0</TgsApiVersion>
<TgsCommonLibraryVersion>7.0.0</TgsCommonLibraryVersion>
+3 -3
View File
@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<RuleSet Name="myrules" Description="My rule set" ToolsVersion="17.0">
<Rules AnalyzerId="AsyncUsageAnalyzers" RuleNamespace="AsyncUsageAnalyzers">
<Rule Id="UseConfigureAwait" Action="Warning" />
@@ -6,7 +6,7 @@
<Rules AnalyzerId="Microsoft.Analyzers.ManagedCodeAnalysis" RuleNamespace="Microsoft.Rules.Managed">
<Rule Id="CA1000" Action="Warning" />
<Rule Id="CA1001" Action="Warning" />
<Rule Id="CA1002" Action="Warning" />
<Rule Id="CA1002" Action="None" />
<Rule Id="CA1003" Action="Warning" />
<Rule Id="CA1004" Action="Warning" />
<Rule Id="CA1005" Action="Warning" />
@@ -1048,4 +1048,4 @@
<Rules AnalyzerId="Text.CSharp.Analyzers" RuleNamespace="Text.CSharp.Analyzers">
<Rule Id="CA1704" Action="Warning" />
</Rules>
</RuleSet>
</RuleSet>
@@ -46,12 +46,14 @@ namespace Tgstation.Server.Host.Components.Deployment
/// <param name="linkFactory">The <see cref="IFilesystemLinkFactory"/> for the <see cref="SwappableDmbProvider"/>.</param>
/// <param name="logger">The value of <see cref="logger"/>.</param>
/// <param name="generalConfiguration">The <see cref="GeneralConfiguration"/> for the <see cref="HardLinkDmbProvider"/>.</param>
/// <param name="securityLevel">The launch <see cref="DreamDaemonSecurity"/> level.</param>
public HardLinkDmbProvider(
IDmbProvider baseProvider,
IIOManager ioManager,
IFilesystemLinkFactory linkFactory,
ILogger logger,
GeneralConfiguration generalConfiguration)
GeneralConfiguration generalConfiguration,
DreamDaemonSecurity securityLevel)
: base(
baseProvider,
ioManager,
@@ -61,7 +63,7 @@ namespace Tgstation.Server.Host.Components.Deployment
cancellationTokenSource = new CancellationTokenSource();
try
{
mirroringTask = MirrorSourceDirectory(generalConfiguration.GetCopyDirectoryTaskThrottle(), cancellationTokenSource.Token);
mirroringTask = MirrorSourceDirectory(generalConfiguration.GetCopyDirectoryTaskThrottle(), securityLevel, cancellationTokenSource.Token);
}
catch
{
@@ -143,9 +145,10 @@ namespace Tgstation.Server.Host.Components.Deployment
/// Mirror the <see cref="Models.CompileJob"/>.
/// </summary>
/// <param name="taskThrottle">The optional maximum number of simultaneous tasks allowed to execute.</param>
/// <param name="securityLevel">The launch <see cref="DreamDaemonSecurity"/> level.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation.</param>
/// <returns>A <see cref="Task{TResult}"/> resulting in the full path to the mirrored directory.</returns>
async Task<string> MirrorSourceDirectory(int? taskThrottle, CancellationToken cancellationToken)
async Task<string> MirrorSourceDirectory(int? taskThrottle, DreamDaemonSecurity securityLevel, CancellationToken cancellationToken)
{
var stopwatch = Stopwatch.StartNew();
var mirrorGuid = Guid.NewGuid();
@@ -157,7 +160,12 @@ namespace Tgstation.Server.Host.Components.Deployment
var dest = IOManager.ResolvePath(mirrorGuid.ToString());
using var semaphore = taskThrottle.HasValue ? new SemaphoreSlim(taskThrottle.Value) : null;
await Task.WhenAll(MirrorDirectoryImpl(src, dest, semaphore, cancellationToken));
await Task.WhenAll(MirrorDirectoryImpl(
src,
dest,
semaphore,
securityLevel,
cancellationToken));
stopwatch.Stop();
logger.LogDebug(
@@ -175,14 +183,15 @@ namespace Tgstation.Server.Host.Components.Deployment
/// <param name="src">The source directory path.</param>
/// <param name="dest">The destination directory path.</param>
/// <param name="semaphore">Optional <see cref="SemaphoreSlim"/> used to limit degree of parallelism.</param>
/// <param name="securityLevel">The launch <see cref="DreamDaemonSecurity"/> level.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation.</param>
/// <returns>A <see cref="IEnumerable{T}"/> of <see cref="Task"/>s representing the running operations. The first <see cref="Task"/> returned is always the necessary call to <see cref="IIOManager.CreateDirectory(string, CancellationToken)"/>.</returns>
/// <remarks>I genuinely don't know how this will work with symlinked files. Waiting for the issue report I guess.</remarks>
IEnumerable<Task> MirrorDirectoryImpl(string src, string dest, SemaphoreSlim? semaphore, CancellationToken cancellationToken)
IEnumerable<Task> MirrorDirectoryImpl(string src, string dest, SemaphoreSlim? semaphore, DreamDaemonSecurity securityLevel, CancellationToken cancellationToken)
{
var dir = new DirectoryInfo(src);
Task? subdirCreationTask = null;
var dreamDaemonWillAcceptOutOfDirectorySymlinks = CompileJob.MinimumSecurityLevel == DreamDaemonSecurity.Trusted;
var dreamDaemonWillAcceptOutOfDirectorySymlinks = securityLevel == DreamDaemonSecurity.Trusted;
foreach (var subDirectory in dir.EnumerateDirectories())
{
var mirroredName = Path.Combine(dest, subDirectory.Name);
@@ -216,7 +225,7 @@ namespace Tgstation.Server.Host.Components.Deployment
logger.LogDebug("Recreating symlinked directory {name} as hard links...", subDirectory.Name);
var checkingSubdirCreationTask = true;
foreach (var copyTask in MirrorDirectoryImpl(subDirectory.FullName, mirroredName, semaphore, cancellationToken))
foreach (var copyTask in MirrorDirectoryImpl(subDirectory.FullName, mirroredName, semaphore, securityLevel, cancellationToken))
{
if (subdirCreationTask == null)
{
@@ -95,6 +95,6 @@ namespace Tgstation.Server.Host.Components.Watchdog
/// <inheritdoc />
protected override SwappableDmbProvider CreateSwappableDmbProvider(IDmbProvider dmbProvider)
=> new HardLinkDmbProvider(dmbProvider, GameIOManager, LinkFactory, Logger, generalConfiguration);
=> new HardLinkDmbProvider(dmbProvider, GameIOManager, LinkFactory, Logger, generalConfiguration, ActiveLaunchParameters.SecurityLevel!.Value);
}
}
@@ -47,7 +47,7 @@ namespace Tgstation.Server.Host.Security
{
this.identity = identity ?? throw new ArgumentNullException(nameof(identity));
if (identity.IsAnonymous)
throw new InvalidOperationException($"Cannot use anonymous {nameof(WindowsIdentity)} as a {nameof(WindowsSystemIdentity)}!");
throw new ArgumentException($"Cannot use anonymous {nameof(WindowsIdentity)} as a {nameof(WindowsSystemIdentity)}!", nameof(identity));
canCreateSymlinks = new WindowsPrincipal(identity).IsInRole(WindowsBuiltInRole.Administrator);
}
@@ -86,7 +86,7 @@ namespace Tgstation.Server.Host.Security
}
// can't clone a UP, shouldn't be trying to anyway, cloning is for impersonation
throw new InvalidOperationException("Cannot clone a UserPrincipal based WindowsSystemIdentity!");
throw new NotSupportedException("Cannot clone a UserPrincipal based WindowsSystemIdentity!");
}
/// <inheritdoc />
@@ -95,7 +95,7 @@ namespace Tgstation.Server.Host.Security
{
ArgumentNullException.ThrowIfNull(action);
if (identity == null)
throw new InvalidOperationException("Impersonate using a UserPrincipal based WindowsSystemIdentity!");
throw new NotSupportedException("Impersonate using a UserPrincipal based WindowsSystemIdentity!");
WindowsIdentity.RunImpersonated(identity.AccessToken, action);
},
cancellationToken,
@@ -38,6 +38,6 @@ namespace Tgstation.Server.Host.Swarm
/// Gets the list of <see cref="SwarmServerResponse"/>s in the swarm, including the current one.
/// </summary>
/// <returns>A <see cref="List{T}"/> of <see cref="SwarmServerResponse"/>s in the swarm. If the server is not part of a swarm, <see langword="null"/> will be returned.</returns>
ICollection<SwarmServerResponse>? GetSwarmServers();
List<SwarmServerResponse>? GetSwarmServers();
}
}
@@ -349,7 +349,7 @@ namespace Tgstation.Server.Host.Swarm
}
/// <inheritdoc />
public ICollection<SwarmServerResponse>? GetSwarmServers()
public List<SwarmServerResponse>? GetSwarmServers()
{
if (!SwarmMode)
return null;