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 @@ -87,8 +87,8 @@ public static IResourceBuilder<AzureAppServiceEnvironmentResource> AddAzureAppSe

var resource = new AzureAppServiceEnvironmentResource(name, static infra =>
{
var prefix = infra.AspireResource.Name;
var resource = (AzureAppServiceEnvironmentResource)infra.AspireResource;
var prefix = Infrastructure.NormalizeBicepIdentifier(resource.Name);

// This tells azd to avoid creating infrastructure
var userPrincipalId = new ProvisioningParameter(AzureBicepResource.KnownParameters.UserPrincipalId, typeof(string)) { Value = new BicepValue<string>(string.Empty) };
Expand All @@ -101,7 +101,7 @@ public static IResourceBuilder<AzureAppServiceEnvironmentResource> AddAzureAppSe

infra.Add(tags);

var identity = new UserAssignedIdentity(Infrastructure.NormalizeBicepIdentifier($"{prefix}-mi"))
var identity = new UserAssignedIdentity($"{prefix}_mi")
{
Tags = tags
};
Expand Down Expand Up @@ -133,7 +133,7 @@ public static IResourceBuilder<AzureAppServiceEnvironmentResource> AddAzureAppSe
pullRa.Name = BicepFunction.CreateGuid(containerRegistry.Id, identity.Id, pullRa.RoleDefinitionId);
infra.Add(pullRa);

var plan = new AppServicePlan(Infrastructure.NormalizeBicepIdentifier($"{prefix}-asplan"))
var plan = new AppServicePlan($"{prefix}_asplan")
{
Sku = new AppServiceSkuDescription
{
Expand Down Expand Up @@ -191,7 +191,7 @@ public static IResourceBuilder<AzureAppServiceEnvironmentResource> AddAzureAppSe

infra.Add(new ProvisioningOutput("AZURE_APP_SERVICE_DASHBOARD_URI", typeof(string))
{
Value = BicepFunction.Interpolate($"https://{AzureAppServiceEnvironmentUtility.GetDashboardHostName(prefix)}.azurewebsites.net")
Value = BicepFunction.Interpolate($"https://{AzureAppServiceEnvironmentUtility.GetDashboardHostName(resource.Name)}.azurewebsites.net")
});
}

Expand All @@ -206,7 +206,7 @@ public static IResourceBuilder<AzureAppServiceEnvironmentResource> AddAzureAppSe
else
{
// Create Log Analytics workspace
var logAnalyticsWorkspace = new OperationalInsightsWorkspace(prefix + "_law")
var logAnalyticsWorkspace = new OperationalInsightsWorkspace($"{prefix}_law")
{
Sku = new OperationalInsightsWorkspaceSku()
{
Expand All @@ -217,7 +217,7 @@ public static IResourceBuilder<AzureAppServiceEnvironmentResource> AddAzureAppSe
infra.Add(logAnalyticsWorkspace);

// Create Application Insights resource linked to the Log Analytics workspace
applicationInsights = new ApplicationInsightsComponent(prefix + "_ai")
applicationInsights = new ApplicationInsightsComponent($"{prefix}_ai")
{
ApplicationType = ApplicationInsightsApplicationType.Web,
Kind = "web",
Expand Down
20 changes: 20 additions & 0 deletions tests/Aspire.Hosting.Azure.Tests/AzureAppServiceTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -846,6 +846,26 @@ await Verify(manifest.ToString(), "json")
.AppendContentAsFile(bicep, "bicep");
}

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

builder.AddAzureAppServiceEnvironment("env-1").WithAzureApplicationInsights();

using var app = builder.Build();

await ExecuteBeforeStartHooksAsync(app, default);

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

var environment = Assert.Single(model.Resources.OfType<AzureAppServiceEnvironmentResource>());

var (_, bicep) = await GetManifestWithBicep(environment);

await Verify(bicep, "bicep");
}

[Fact]
public async Task AddAppServiceWithApplicationInsightsLocationParam()
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
@description('The location for the resource(s) to be deployed.')
param location string = resourceGroup().location

param userPrincipalId string = ''

param tags object = { }

param env_1_acr_outputs_name string

resource env_1_mi 'Microsoft.ManagedIdentity/userAssignedIdentities@2024-11-30' = {
name: take('env_1_mi-${uniqueString(resourceGroup().id)}', 128)
location: location
tags: tags
}

resource env_1_acr 'Microsoft.ContainerRegistry/registries@2025-04-01' existing = {
name: env_1_acr_outputs_name
}

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

resource env_1_asplan 'Microsoft.Web/serverfarms@2025-03-01' = {
name: take('env1asplan-${uniqueString(resourceGroup().id)}', 60)
location: location
properties: {
perSiteScaling: true
reserved: true
}
kind: 'Linux'
sku: {
name: 'P0V3'
tier: 'Premium'
}
}

resource env_1_contributor_mi 'Microsoft.ManagedIdentity/userAssignedIdentities@2024-11-30' = {
name: take('env_1_contributor_mi-${uniqueString(resourceGroup().id)}', 128)
location: location
}

resource env_1_ra 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
name: guid(resourceGroup().id, env_1_contributor_mi.id, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7'))
properties: {
principalId: env_1_contributor_mi.properties.principalId
roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')
principalType: 'ServicePrincipal'
}
}

resource dashboard 'Microsoft.Web/sites@2025-03-01' = {
name: take('${toLower('env-1')}-${toLower('aspiredashboard')}-${uniqueString(resourceGroup().id)}', 60)
location: location
properties: {
serverFarmId: env_1_asplan.id
siteConfig: {
numberOfWorkers: 1
linuxFxVersion: 'ASPIREDASHBOARD|1.0'
acrUseManagedIdentityCreds: true
acrUserManagedIdentityID: env_1_mi.properties.clientId
appSettings: [
{
name: 'DASHBOARD__FRONTEND__AUTHMODE'
value: 'Unsecured'
}
{
name: 'DASHBOARD__OTLP__AUTHMODE'
value: 'Unsecured'
}
{
name: 'DASHBOARD__OTLP__SUPPRESSUNSECUREDTELEMETRYMESSAGE'
value: 'true'
}
{
name: 'DASHBOARD__RESOURCESERVICECLIENT__AUTHMODE'
value: 'Unsecured'
}
{
name: 'DASHBOARD__UI__DISABLEIMPORT'
value: 'true'
}
{
name: 'WEBSITES_PORT'
value: '5000'
}
{
name: 'HTTP20_ONLY_PORT'
value: '4317'
}
{
name: 'WEBSITE_START_SCM_WITH_PRELOAD'
value: 'true'
}
{
name: 'AZURE_CLIENT_ID'
value: env_1_contributor_mi.properties.clientId
}
{
name: 'ALLOWED_MANAGED_IDENTITIES'
value: env_1_mi.properties.clientId
}
{
name: 'ASPIRE_ENVIRONMENT_NAME'
value: 'env-1'
}
]
alwaysOn: true
http20Enabled: true
http20ProxyFlag: 1
}
}
identity: {
type: 'UserAssigned'
userAssignedIdentities: {
'${env_1_contributor_mi.id}': { }
}
}
kind: 'app,linux,aspiredashboard'
}

resource env_1_law 'Microsoft.OperationalInsights/workspaces@2025-02-01' = {
name: take('env1law-${uniqueString(resourceGroup().id)}', 63)
location: location
properties: {
sku: {
name: 'PerGB2018'
}
}
}

resource env_1_ai 'Microsoft.Insights/components@2020-02-02' = {
name: take('env_1_ai-${uniqueString(resourceGroup().id)}', 260)
kind: 'web'
location: location
properties: {
Application_Type: 'web'
IngestionMode: 'LogAnalytics'
WorkspaceResourceId: env_1_law.id
}
}

output name string = env_1_asplan.name

output planId string = env_1_asplan.id

output webSiteSuffix string = uniqueString(resourceGroup().id)

output AZURE_CONTAINER_REGISTRY_NAME string = env_1_acr.name

output AZURE_CONTAINER_REGISTRY_ENDPOINT string = env_1_acr.properties.loginServer

output AZURE_CONTAINER_REGISTRY_MANAGED_IDENTITY_ID string = env_1_mi.id

output AZURE_CONTAINER_REGISTRY_MANAGED_IDENTITY_CLIENT_ID string = env_1_mi.properties.clientId

output AZURE_WEBSITE_CONTRIBUTOR_MANAGED_IDENTITY_ID string = env_1_contributor_mi.id

output AZURE_WEBSITE_CONTRIBUTOR_MANAGED_IDENTITY_PRINCIPAL_ID string = env_1_contributor_mi.properties.principalId

output AZURE_APP_SERVICE_DASHBOARD_URI string = 'https://${take('${toLower('env-1')}-${toLower('aspiredashboard')}-${uniqueString(resourceGroup().id)}', 60)}.azurewebsites.net'

output AZURE_APPLICATION_INSIGHTS_INSTRUMENTATIONKEY string = env_1_ai.properties.InstrumentationKey

output AZURE_APPLICATION_INSIGHTS_CONNECTION_STRING string = env_1_ai.properties.ConnectionString
Loading