Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions src/Aspire.Hosting/DistributedApplicationBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -128,14 +128,16 @@ private DistributedApplicationExecutionContextOptions BuildExecutionContextOptio
{
"publish" => DistributedApplicationOperation.Publish,
"run" => DistributedApplicationOperation.Run,
_ => throw new DistributedApplicationException("Invalid operation specified. Valid operations are 'publish' or 'run'.")
"inspect" => DistributedApplicationOperation.Inspect,
_ => throw new DistributedApplicationException("Invalid operation specified. Valid operations are 'publish', 'run', or 'inspect'.")
};

return operation switch
{
DistributedApplicationOperation.Run => new DistributedApplicationExecutionContextOptions(operation),
DistributedApplicationOperation.Publish => new DistributedApplicationExecutionContextOptions(operation, _innerBuilder.Configuration["Publishing:Publisher"] ?? "manifest"),
_ => throw new DistributedApplicationException("Invalid operation specified. Valid operations are 'publish' or 'run'.")
DistributedApplicationOperation.Inspect => new DistributedApplicationExecutionContextOptions(operation),
_ => throw new DistributedApplicationException("Invalid operation specified. Valid operations are 'publish', 'run', or 'inspect'.")
};
}

Expand Down Expand Up @@ -477,9 +479,9 @@ private void ConfigureHealthChecks()
{
return new ConfigureOptions<HealthCheckPublisherOptions>(options =>
{
if (ExecutionContext.IsPublishMode)
if (ExecutionContext.IsPublishMode || ExecutionContext.IsInspectMode)
{
// In publish mode we don't run any checks.
// In publish mode and inspect mode we don't run any checks.
options.Predicate = (check) => false;
}
});
Expand Down
5 changes: 5 additions & 0 deletions src/Aspire.Hosting/DistributedApplicationExecutionContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -85,4 +85,9 @@ public IServiceProvider ServiceProvider
/// Returns true if the current operation is running.
/// </summary>
public bool IsRunMode => Operation == DistributedApplicationOperation.Run;

/// <summary>
/// Returns true if the current operation is inspect mode.
/// </summary>
public bool IsInspectMode => Operation == DistributedApplicationOperation.Inspect;
}
7 changes: 6 additions & 1 deletion src/Aspire.Hosting/DistributedApplicationOperation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,10 @@ public enum DistributedApplicationOperation
/// <summary>
/// AppHost is being run for the purpose of publishing a manifest for deployment.
/// </summary>
Publish
Publish,

/// <summary>
/// AppHost is being run in inspect mode for introspection without activating DCP or Publishers.
/// </summary>
Inspect
}
2 changes: 1 addition & 1 deletion src/Aspire.Hosting/Orchestrator/OrchestratorHostService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public OrchestratorHostService(
_dcpHost = dcpHost;
}

private bool IsSupported => !_executionContext.IsPublishMode;
private bool IsSupported => _executionContext.IsRunMode;

public async Task StartAsync(CancellationToken cancellationToken = default)
{
Expand Down
89 changes: 89 additions & 0 deletions tests/Aspire.Hosting.Tests/OperationModesTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#pragma warning disable ASPIREPUBLISHERS001

using Aspire.Hosting.Publishing;
using Aspire.Hosting.Utils;
using Microsoft.AspNetCore.InternalTesting;
using Microsoft.Extensions.DependencyInjection;
Expand Down Expand Up @@ -138,4 +139,92 @@ public void VerifyExplicitPublishModeInvocation()
.WithTestAndResourceLogging(outputHelper);
Assert.Equal(DistributedApplicationOperation.Publish, builder.ExecutionContext.Operation);
}

[Fact]
public void VerifyExplicitInspectModeParsingOnly()
{
// The purpose of this test is to verify that the apphost executable will enter
// inspect mode if executed with the "--operation inspect" argument.

using var builder = TestDistributedApplicationBuilder
.Create(["--operation", "inspect"])
.WithTestAndResourceLogging(outputHelper);

Assert.Equal(DistributedApplicationOperation.Inspect, builder.ExecutionContext.Operation);
Assert.True(builder.ExecutionContext.IsInspectMode);
Assert.False(builder.ExecutionContext.IsRunMode);
Assert.False(builder.ExecutionContext.IsPublishMode);
}

[Fact]
public async Task VerifyExplicitInspectModeInvocation()
{
// The purpose of this test is to verify that the apphost executable will enter
// inspect mode if executed with the "--operation inspect" argument.

using var builder = TestDistributedApplicationBuilder
.Create(["--operation", "inspect"])
.WithTestAndResourceLogging(outputHelper);

var tcs = new TaskCompletionSource<DistributedApplicationExecutionContext>();
builder.Eventing.Subscribe<AfterResourcesCreatedEvent>((e, ct) => {
var context = e.Services.GetRequiredService<DistributedApplicationExecutionContext>();
tcs.SetResult(context);
return Task.CompletedTask;
});

using var app = builder.Build();

await app.StartAsync().WaitAsync(TestConstants.DefaultTimeoutTimeSpan);

var context = await tcs.Task.WaitAsync(TestConstants.DefaultTimeoutTimeSpan);

await app.StopAsync().WaitAsync(TestConstants.DefaultTimeoutTimeSpan);

Assert.Equal(DistributedApplicationOperation.Inspect, context.Operation);
Assert.True(context.IsInspectMode);
Assert.False(context.IsRunMode);
Assert.False(context.IsPublishMode);
}

[Fact]
public void VerifyInspectModeDoesNotRegisterDcp()
{
// Verify that DCP services are not registered in inspect mode
using var builder = TestDistributedApplicationBuilder
.Create(["--operation", "inspect"])
.WithTestAndResourceLogging(outputHelper);

Assert.Equal(DistributedApplicationOperation.Inspect, builder.ExecutionContext.Operation);

using var app = builder.Build();

// Verify DCP-related services are not registered
Assert.Null(app.Services.GetService<Aspire.Hosting.Dcp.DcpHost>());
Assert.Null(app.Services.GetService<Aspire.Hosting.Dcp.IDcpExecutor>());
Assert.Null(app.Services.GetService<Aspire.Hosting.Orchestrator.ApplicationOrchestrator>());
}

[Fact]
public async Task VerifyInspectModeDoesNotExecutePublisher()
{
// Verify that publishers are not executed in inspect mode
using var builder = TestDistributedApplicationBuilder
.Create(["--operation", "inspect"])
.WithTestAndResourceLogging(outputHelper);

var publisherExecuted = false;
builder.Eventing.Subscribe<BeforePublishEvent>((e, ct) => {
publisherExecuted = true;
return Task.CompletedTask;
});

using var app = builder.Build();

await app.StartAsync().WaitAsync(TestConstants.DefaultTimeoutTimeSpan);
await app.StopAsync().WaitAsync(TestConstants.DefaultTimeoutTimeSpan);

// Publisher should not have executed
Assert.False(publisherExecuted);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ public static IDistributedApplicationTestingBuilder Create(DistributedApplicatio
{
DistributedApplicationOperation.Run => (string[])[],
DistributedApplicationOperation.Publish => [$"Publishing:Publisher={publisher}", $"Publishing:OutputPath={outputPath}", $"Publishing:Deploy={isDeploy}"],
DistributedApplicationOperation.Inspect => ["--operation", "inspect"],
_ => throw new ArgumentOutOfRangeException(nameof(operation))
};

Expand Down
Loading