feat(managementservice): MgmtDeployArea — Deployer-only, scoped by the area's owning site (fail-closed on an unknown area), long-running like MgmtDeploySite (Gitea #40)
This commit is contained in:
@@ -343,7 +343,8 @@ public class ManagementActor : ReceiveActor
|
||||
PreviewBundleCommand or ImportBundleCommand => AdminOnly,
|
||||
|
||||
// Deployer operations
|
||||
CreateInstanceCommand or MgmtDeployInstanceCommand or MgmtDeploySiteCommand or MgmtEnableInstanceCommand
|
||||
CreateInstanceCommand or MgmtDeployInstanceCommand or MgmtDeploySiteCommand or MgmtDeployAreaCommand
|
||||
or MgmtEnableInstanceCommand
|
||||
or MgmtDisableInstanceCommand or MgmtDeleteInstanceCommand
|
||||
or SetConnectionBindingsCommand or SetInstanceOverridesCommand or SetInstanceAreaCommand
|
||||
or SetInstanceAlarmOverrideCommand or DeleteInstanceAlarmOverrideCommand
|
||||
@@ -431,6 +432,7 @@ public class ManagementActor : ReceiveActor
|
||||
CreateInstanceCommand cmd => await HandleCreateInstance(sp, cmd, user),
|
||||
MgmtDeployInstanceCommand cmd => await HandleDeployInstance(sp, cmd, user),
|
||||
MgmtDeploySiteCommand cmd => await HandleDeploySite(sp, cmd, user),
|
||||
MgmtDeployAreaCommand cmd => await HandleDeployArea(sp, cmd, user),
|
||||
MgmtEnableInstanceCommand cmd => await HandleEnableInstance(sp, cmd, user),
|
||||
MgmtDisableInstanceCommand cmd => await HandleDisableInstance(sp, cmd, user),
|
||||
MgmtDeleteInstanceCommand cmd => await HandleDeleteInstance(sp, cmd, user),
|
||||
@@ -1051,6 +1053,43 @@ public class ManagementActor : ReceiveActor
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Bulk-deploys every deployable instance in an area subtree (Gitea #40) —
|
||||
/// <see cref="HandleDeploySite"/> narrowed to one area and its descendants.
|
||||
///
|
||||
/// <para>
|
||||
/// Site scope is enforced on the area's OWNING site, the only site the batch
|
||||
/// can touch. An area that does not resolve fails CLOSED for a site-scoped
|
||||
/// caller (the same denial as an out-of-scope one, so the gate is not an
|
||||
/// existence oracle — register row 98); a system-wide caller gets a plain
|
||||
/// "not found" error. Same overall deadline and <c>BULK_DEPLOY_TIMEOUT</c>
|
||||
/// mapping as the site deploy.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
private static async Task<object?> HandleDeployArea(IServiceProvider sp, MgmtDeployAreaCommand cmd, AuthenticatedUser user)
|
||||
{
|
||||
var area = await sp.GetRequiredService<ITemplateEngineRepository>().GetAreaByIdAsync(cmd.AreaId);
|
||||
if (area is null)
|
||||
{
|
||||
DenyUnresolvedTargetIfScoped(user, $"area {cmd.AreaId}");
|
||||
throw new ManagementCommandException($"Area with ID {cmd.AreaId} not found.");
|
||||
}
|
||||
|
||||
EnforceSiteScope(user, area.SiteId);
|
||||
var svc = sp.GetRequiredService<DeploymentService>();
|
||||
var timeout = sp.GetService<Microsoft.Extensions.Options.IOptions<ManagementServiceOptions>>()?.Value.LongRunningCommandTimeout ?? TimeSpan.FromMinutes(5);
|
||||
using var deadline = new CancellationTokenSource(timeout);
|
||||
try
|
||||
{
|
||||
var result = await svc.DeployAreaAsync(cmd.AreaId, user.Username, cmd.Force, deadline.Token);
|
||||
return result.IsSuccess ? result.Value : throw new ManagementCommandException(result.Error);
|
||||
}
|
||||
catch (OperationCanceledException) when (deadline.IsCancellationRequested)
|
||||
{
|
||||
throw new ManagementCommandException("Overall bulk deployment deadline exceeded before further apply could be scheduled.", "BULK_DEPLOY_TIMEOUT");
|
||||
}
|
||||
}
|
||||
|
||||
private static async Task<object?> HandleEnableInstance(IServiceProvider sp, MgmtEnableInstanceCommand cmd, AuthenticatedUser user)
|
||||
{
|
||||
await EnforceSiteScopeForInstance(sp, user, cmd.InstanceId);
|
||||
|
||||
Reference in New Issue
Block a user