Skip to content
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,12 @@ public class AzureContainerAppEnvironmentResource(string name, Action<AzureResou
#pragma warning restore ASPIRECOMPUTE001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
{
internal bool UseAzdNamingConvention { get; set; }

/// <summary>
/// Gets or sets a value indicating whether the Aspire dashboard should be included in the container app environment.
/// Default is true.
/// </summary>
internal bool EnableDashboard { get; set; } = true;

/// <summary>
/// Gets the unique identifier of the Container App Environment.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -152,14 +152,17 @@ public static IResourceBuilder<AzureContainerAppEnvironmentResource> AddAzureCon

infra.Add(containerAppEnvironment);

var dashboard = new ContainerAppEnvironmentDotnetComponentResource("aspireDashboard", "2024-10-02-preview")
if (appEnvResource.EnableDashboard)
{
Name = "aspire-dashboard",
ComponentType = "AspireDashboard",
Parent = containerAppEnvironment
};
var dashboard = new ContainerAppEnvironmentDotnetComponentResource("aspireDashboard", "2024-10-02-preview")
{
Name = "aspire-dashboard",
ComponentType = "AspireDashboard",
Parent = containerAppEnvironment
};

infra.Add(dashboard);
infra.Add(dashboard);
}

var managedStorages = new Dictionary<string, ContainerAppManagedEnvironmentStorage>();

Expand Down Expand Up @@ -348,4 +351,16 @@ public static IResourceBuilder<AzureContainerAppEnvironmentResource> WithAzdReso
builder.Resource.UseAzdNamingConvention = true;
return builder;
}

/// <summary>
/// Configures whether the Aspire dashboard should be included in the container app environment.
/// </summary>
/// <param name="builder">The AzureContainerAppEnvironmentResource to configure.</param>
/// <param name="enable">Whether to include the Aspire dashboard. Default is true.</param>
/// <returns><see cref="IResourceBuilder{T}"/></returns>
public static IResourceBuilder<AzureContainerAppEnvironmentResource> WithDashboard(this IResourceBuilder<AzureContainerAppEnvironmentResource> builder, bool enable = true)
{
builder.Resource.EnableDashboard = enable;
return builder;
}
}
44 changes: 44 additions & 0 deletions tests/Aspire.Hosting.Azure.Tests/AzureContainerAppsTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1342,6 +1342,50 @@ await Verify(manifest.ToString(), "json")
.AppendContentAsFile(bicep, "bicep");
}

[Fact]
public async Task ContainerAppEnvironmentWithDashboardEnabled()
{
var builder = TestDistributedApplicationBuilder.Create(DistributedApplicationOperation.Publish);

builder.AddAzureContainerAppEnvironment("env")
.WithDashboard(true);

using var app = builder.Build();

await ExecuteBeforeStartHooksAsync(app, default);

var model = app.Services.GetRequiredService<DistributedApplicationModel>();

var containerAppEnvResource = Assert.Single(model.Resources.OfType<AzureContainerAppEnvironmentResource>());

var (manifest, bicep) = await GetManifestWithBicep(containerAppEnvResource);

await Verify(manifest.ToString(), "json")
.AppendContentAsFile(bicep, "bicep");
}

[Fact]
public async Task ContainerAppEnvironmentWithDashboardDisabled()
{
var builder = TestDistributedApplicationBuilder.Create(DistributedApplicationOperation.Publish);

builder.AddAzureContainerAppEnvironment("env")
.WithDashboard(false);

using var app = builder.Build();

await ExecuteBeforeStartHooksAsync(app, default);

var model = app.Services.GetRequiredService<DistributedApplicationModel>();

var containerAppEnvResource = Assert.Single(model.Resources.OfType<AzureContainerAppEnvironmentResource>());

var (manifest, bicep) = await GetManifestWithBicep(containerAppEnvResource);

await Verify(manifest.ToString(), "json")
.AppendContentAsFile(bicep, "bicep");
}

private static Task<(JsonNode ManifestNode, string BicepText)> GetManifestWithBicep(IResource resource) =>
AzureManifestUtils.GetManifestWithBicep(resource, skipPreparer: true);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
@description('The location for the resource(s) to be deployed.')
param location string = resourceGroup().location

param userPrincipalId string

param tags object = { }

resource env_mi 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' = {
name: take('env_mi-${uniqueString(resourceGroup().id)}', 128)
location: location
tags: tags
}

resource env_acr 'Microsoft.ContainerRegistry/registries@2023-07-01' = {
name: take('envacr${uniqueString(resourceGroup().id)}', 50)
location: location
sku: {
name: 'Basic'
}
tags: tags
}

resource env_acr_env_mi_AcrPull 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
name: guid(env_acr.id, env_mi.id, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7f951dda-4ed3-4680-a7ca-43fe172d538d'))
properties: {
principalId: env_mi.properties.principalId
roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7f951dda-4ed3-4680-a7ca-43fe172d538d')
principalType: 'ServicePrincipal'
}
scope: env_acr
}

resource env_law 'Microsoft.OperationalInsights/workspaces@2023-09-01' = {
name: take('envlaw-${uniqueString(resourceGroup().id)}', 63)
location: location
properties: {
sku: {
name: 'PerGB2018'
}
}
tags: tags
}

resource env 'Microsoft.App/managedEnvironments@2024-03-01' = {
name: take('env${uniqueString(resourceGroup().id)}', 24)
location: location
properties: {
appLogsConfiguration: {
destination: 'log-analytics'
logAnalyticsConfiguration: {
customerId: env_law.properties.customerId
sharedKey: env_law.listKeys().primarySharedKey
}
}
workloadProfiles: [
{
name: 'consumption'
workloadProfileType: 'Consumption'
}
]
}
tags: tags
}

output AZURE_LOG_ANALYTICS_WORKSPACE_NAME string = env_law.name

output AZURE_LOG_ANALYTICS_WORKSPACE_ID string = env_law.id

output AZURE_CONTAINER_REGISTRY_NAME string = env_acr.name

output AZURE_CONTAINER_REGISTRY_ENDPOINT string = env_acr.properties.loginServer

output AZURE_CONTAINER_REGISTRY_MANAGED_IDENTITY_ID string = env_mi.id

output AZURE_CONTAINER_APPS_ENVIRONMENT_NAME string = env.name

output AZURE_CONTAINER_APPS_ENVIRONMENT_ID string = env.id

output AZURE_CONTAINER_APPS_ENVIRONMENT_DEFAULT_DOMAIN string = env.properties.defaultDomain
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "azure.bicep.v0",
"path": "env.module.bicep",
"params": {
"userPrincipalId": ""
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
@description('The location for the resource(s) to be deployed.')
param location string = resourceGroup().location

param userPrincipalId string

param tags object = { }

resource env_mi 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' = {
name: take('env_mi-${uniqueString(resourceGroup().id)}', 128)
location: location
tags: tags
}

resource env_acr 'Microsoft.ContainerRegistry/registries@2023-07-01' = {
name: take('envacr${uniqueString(resourceGroup().id)}', 50)
location: location
sku: {
name: 'Basic'
}
tags: tags
}

resource env_acr_env_mi_AcrPull 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
name: guid(env_acr.id, env_mi.id, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7f951dda-4ed3-4680-a7ca-43fe172d538d'))
properties: {
principalId: env_mi.properties.principalId
roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7f951dda-4ed3-4680-a7ca-43fe172d538d')
principalType: 'ServicePrincipal'
}
scope: env_acr
}

resource env_law 'Microsoft.OperationalInsights/workspaces@2023-09-01' = {
name: take('envlaw-${uniqueString(resourceGroup().id)}', 63)
location: location
properties: {
sku: {
name: 'PerGB2018'
}
}
tags: tags
}

resource env 'Microsoft.App/managedEnvironments@2024-03-01' = {
name: take('env${uniqueString(resourceGroup().id)}', 24)
location: location
properties: {
appLogsConfiguration: {
destination: 'log-analytics'
logAnalyticsConfiguration: {
customerId: env_law.properties.customerId
sharedKey: env_law.listKeys().primarySharedKey
}
}
workloadProfiles: [
{
name: 'consumption'
workloadProfileType: 'Consumption'
}
]
}
tags: tags
}

resource aspireDashboard 'Microsoft.App/managedEnvironments/dotNetComponents@2024-10-02-preview' = {
name: 'aspire-dashboard'
properties: {
componentType: 'AspireDashboard'
}
parent: env
}

output AZURE_LOG_ANALYTICS_WORKSPACE_NAME string = env_law.name

output AZURE_LOG_ANALYTICS_WORKSPACE_ID string = env_law.id

output AZURE_CONTAINER_REGISTRY_NAME string = env_acr.name

output AZURE_CONTAINER_REGISTRY_ENDPOINT string = env_acr.properties.loginServer

output AZURE_CONTAINER_REGISTRY_MANAGED_IDENTITY_ID string = env_mi.id

output AZURE_CONTAINER_APPS_ENVIRONMENT_NAME string = env.name

output AZURE_CONTAINER_APPS_ENVIRONMENT_ID string = env.id

output AZURE_CONTAINER_APPS_ENVIRONMENT_DEFAULT_DOMAIN string = env.properties.defaultDomain
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "azure.bicep.v0",
"path": "env.module.bicep",
"params": {
"userPrincipalId": ""
}
}
Loading