Skip to content

Commit

Permalink
Don't wait until after we've started the entire app to print the token (
Browse files Browse the repository at this point in the history
#3472)

- Print it right after we print the dashboard url
- Refactored the dashboard resource to use DashboardOptions instead of DcpOptions
  • Loading branch information
davidfowl authored Apr 8, 2024
1 parent b2b9257 commit 29e2b57
Show file tree
Hide file tree
Showing 5 changed files with 87 additions and 24 deletions.
35 changes: 20 additions & 15 deletions src/Aspire.Hosting/Dashboard/DashboardLifecycleHook.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
namespace Aspire.Hosting.Dashboard;

internal sealed class DashboardLifecycleHook(IConfiguration configuration,
IOptions<DcpOptions> dcpOptions,
IOptions<DashboardOptions> dashboardOptions,
ILogger<DistributedApplication> distributedApplicationLogger,
IDashboardEndpointProvider dashboardEndpointProvider,
DistributedApplicationExecutionContext executionContext) : IDistributedApplicationLifecycleHook
Expand All @@ -41,7 +41,7 @@ public Task BeforeStartAsync(DistributedApplicationModel model, CancellationToke

private void AddDashboardResource(DistributedApplicationModel model)
{
if (dcpOptions.Value.DashboardPath is not { } dashboardPath)
if (dashboardOptions.Value.DashboardPath is not { } dashboardPath)
{
throw new DistributedApplicationException("Dashboard path empty or file does not exist.");
}
Expand Down Expand Up @@ -99,29 +99,29 @@ private void ConfigureAspireDashboardResource(IResource dashboardResource)

dashboardResource.Annotations.Add(new EnvironmentCallbackAnnotation(async context =>
{
var dashboardUrls = configuration["ASPNETCORE_URLS"];
var options = dashboardOptions.Value;
if (string.IsNullOrEmpty(dashboardUrls))
{
throw new DistributedApplicationException("Failed to configure dashboard resource because ASPNETCORE_URLS environment variable was not set.");
}
// Options should have been validated these should not be null
if (configuration["DOTNET_DASHBOARD_OTLP_ENDPOINT_URL"] is not { } otlpEndpointUrl)
{
throw new DistributedApplicationException("Failed to configure dashboard resource because DOTNET_DASHBOARD_OTLP_ENDPOINT_URL environment variable was not set.");
}
Debug.Assert(options.DashboardUrl is not null, "DashboardUrl should not be null");
Debug.Assert(options.OtlpEndpointUrl is not null, "OtlpEndpointUrl should not be null");
var resourceServiceUrl = await dashboardEndpointProvider.GetResourceServiceUriAsync(context.CancellationToken).ConfigureAwait(false);
var dashboardUrls = options.DashboardUrl;
var otlpEndpointUrl = options.OtlpEndpointUrl;
var environment = configuration["ASPNETCORE_ENVIRONMENT"] ?? "Production";
var environment = options.AspNetCoreEnvironment;
var browserToken = options.DashboardToken;
var otlpApiKey = options.OtlpApiKey;
var resourceServiceUrl = await dashboardEndpointProvider.GetResourceServiceUriAsync(context.CancellationToken).ConfigureAwait(false);
context.EnvironmentVariables["ASPNETCORE_ENVIRONMENT"] = environment;
context.EnvironmentVariables[DashboardConfigNames.DashboardFrontendUrlName.EnvVarName] = dashboardUrls;
context.EnvironmentVariables[DashboardConfigNames.ResourceServiceUrlName.EnvVarName] = resourceServiceUrl;
context.EnvironmentVariables[DashboardConfigNames.DashboardOtlpUrlName.EnvVarName] = otlpEndpointUrl;
context.EnvironmentVariables[DashboardConfigNames.ResourceServiceAuthModeName.EnvVarName] = "Unsecured";
if (configuration["AppHost:BrowserToken"] is { Length: > 0 } browserToken)
if (!string.IsNullOrEmpty(browserToken))
{
context.EnvironmentVariables[DashboardConfigNames.DashboardFrontendAuthModeName.EnvVarName] = "BrowserToken";
context.EnvironmentVariables[DashboardConfigNames.DashboardFrontendBrowserTokenName.EnvVarName] = browserToken;
Expand All @@ -131,7 +131,7 @@ private void ConfigureAspireDashboardResource(IResource dashboardResource)
context.EnvironmentVariables[DashboardConfigNames.DashboardFrontendAuthModeName.EnvVarName] = "Unsecured";
}
if (configuration["AppHost:OtlpApiKey"] is { Length: > 0 } otlpApiKey)
if (!string.IsNullOrEmpty(otlpApiKey))
{
context.EnvironmentVariables[DashboardConfigNames.DashboardOtlpAuthModeName.EnvVarName] = "ApiKey";
context.EnvironmentVariables[DashboardConfigNames.DashboardOtlpPrimaryApiKeyName.EnvVarName] = otlpApiKey;
Expand All @@ -147,6 +147,11 @@ private void ConfigureAspireDashboardResource(IResource dashboardResource)
{
distributedApplicationLogger.LogInformation("Now listening on: {DashboardUrl}", firstDashboardUrl.ToString().TrimEnd('/'));
}
if (!string.IsNullOrEmpty(browserToken))
{
LoggingHelpers.WriteDashboardUrl(distributedApplicationLogger, dashboardUrls, browserToken);
}
}));
}
}
53 changes: 53 additions & 0 deletions src/Aspire.Hosting/Dashboard/DashboardOptions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using Aspire.Hosting.Dcp;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Options;

namespace Aspire.Hosting.Dashboard;

internal class DashboardOptions
{
public string? DashboardPath { get; set; }
public string? DashboardUrl { get; set; }
public string? DashboardToken { get; set; }
public string? OtlpEndpointUrl { get; set; }
public string? OtlpApiKey { get; set; }
public string AspNetCoreEnvironment { get; set; } = "Production";
}

internal class ConfigureDefaultDashboardOptions(IConfiguration configuration, IOptions<DcpOptions> dcpOptions) : IConfigureOptions<DashboardOptions>
{
public void Configure(DashboardOptions options)
{
options.DashboardPath = dcpOptions.Value.DashboardPath;
options.DashboardUrl = configuration["ASPNETCORE_URLS"];
options.DashboardToken = configuration["AppHost:BrowserToken"];

options.OtlpEndpointUrl = configuration["DOTNET_DASHBOARD_OTLP_ENDPOINT_URL"];
options.OtlpApiKey = configuration["AppHost:OtlpApiKey"];

options.AspNetCoreEnvironment = configuration["ASPNETCORE_ENVIRONMENT"] ?? "Production";
}
}

internal class ValidateDashboardOptions : IValidateOptions<DashboardOptions>
{
public ValidateOptionsResult Validate(string? name, DashboardOptions options)
{
var builder = new ValidateOptionsResultBuilder();

if (string.IsNullOrEmpty(options.DashboardUrl))
{
builder.AddError("Failed to configure dashboard resource because ASPNETCORE_URLS environment variable was not set.");
}

if (string.IsNullOrEmpty(options.OtlpEndpointUrl))
{
builder.AddError("Failed to configure dashboard resource because DOTNET_DASHBOARD_OTLP_ENDPOINT_URL environment variable was not set.");
}

return builder.Build();
}
}
2 changes: 2 additions & 0 deletions src/Aspire.Hosting/DistributedApplicationBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,8 @@ public DistributedApplicationBuilder(DistributedApplicationOptions options)
_innerBuilder.Services.AddSingleton<DashboardServiceHost>();
_innerBuilder.Services.AddHostedService(sp => sp.GetRequiredService<DashboardServiceHost>());
_innerBuilder.Services.AddLifecycleHook<DashboardLifecycleHook>();
_innerBuilder.Services.TryAddEnumerable(ServiceDescriptor.Singleton<IConfigureOptions<DashboardOptions>, ConfigureDefaultDashboardOptions>());
_innerBuilder.Services.TryAddEnumerable(ServiceDescriptor.Singleton<IValidateOptions<DashboardOptions>, ValidateDashboardOptions>());
}

// DCP stuff
Expand Down
8 changes: 1 addition & 7 deletions src/Aspire.Hosting/DistributedApplicationLifecycle.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,7 @@ namespace Aspire.Hosting;
internal sealed class DistributedApplicationLifecycle(
ILogger<DistributedApplication> logger,
IConfiguration configuration,
DistributedApplicationExecutionContext executionContext,
DistributedApplicationOptions distributedApplicationOptions) : IHostedLifecycleService
DistributedApplicationExecutionContext executionContext) : IHostedLifecycleService
{
public Task StartAsync(CancellationToken cancellationToken)
{
Expand All @@ -23,11 +22,6 @@ public Task StartedAsync(CancellationToken cancellationToken)
{
if (executionContext.IsRunMode)
{
if (distributedApplicationOptions.DashboardEnabled && configuration["AppHost:BrowserToken"] is { Length: > 0 } browserToken)
{
LoggingHelpers.WriteDashboardUrl(logger, configuration["ASPNETCORE_URLS"], browserToken);
}

logger.LogInformation("Distributed application started. Press Ctrl+C to shut down.");
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using Aspire.Hosting.Dashboard;
using Aspire.Hosting.Dcp;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
Expand Down Expand Up @@ -45,8 +46,16 @@ public static TestDistributedApplicationBuilder Create(DistributedApplicationOpt

builder.Services.Configure<DcpOptions>(o =>
{
o.DashboardPath = "dashboard";
o.CliPath = "dcp";
// Make sure we have a dashboard path and CLI path (but don't overwrite them if they're already set)
o.DashboardPath ??= "dashboard";
o.CliPath ??= "dcp";
});

builder.Services.Configure<DashboardOptions>(o =>
{
// Make sure we have a dashboard URL and OTLP endpoint URL (but don't overwrite them if they're already set)
o.DashboardUrl ??= "http://localhost:8080";
o.OtlpEndpointUrl ??= "http://localhost:4317";
});

return new(builder);
Expand Down

0 comments on commit 29e2b57

Please sign in to comment.