Skip to content
2 changes: 1 addition & 1 deletion Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
<PackageVersion Include="Azure.Provisioning" Version="1.4.0" />
<PackageVersion Include="Azure.Provisioning.AppConfiguration" Version="1.1.0" />
<PackageVersion Include="Azure.Provisioning.AppContainers" Version="1.1.0" />
<PackageVersion Include="Azure.Provisioning.AppService" Version="1.3.0" />
<PackageVersion Include="Azure.Provisioning.AppService" Version="1.3.1" />
<PackageVersion Include="Azure.Provisioning.ApplicationInsights" Version="1.1.0" />
<PackageVersion Include="Azure.Provisioning.ContainerRegistry" Version="1.1.0" />
<PackageVersion Include="Azure.Provisioning.CognitiveServices" Version="1.1.0" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -239,18 +239,30 @@ private async Task<string> GetAppServiceWebsiteNameAsync(PipelineStepContext con
var websiteSuffix = await computerEnv.WebSiteSuffix.GetValueAsync(context.CancellationToken).ConfigureAwait(false);
var websiteName = $"{TargetResource.Name.ToLowerInvariant()}-{websiteSuffix}";

if (!string.IsNullOrWhiteSpace(deploymentSlot))
if (string.IsNullOrWhiteSpace(deploymentSlot))
{
websiteName += $"-{deploymentSlot}";
return TruncateToMaxLength(websiteName, 60);
}

if (websiteName.Length > 60)
websiteName = TruncateToMaxLength(websiteName, MaxWebSiteNamePrefixLengthWithSlot);
websiteName += $"-{deploymentSlot}";

return TruncateToMaxLength(websiteName, MaxHostPrefixLengthWithSlot);
}

private static string TruncateToMaxLength(string value, int maxLength)
{
if (value.Length <= maxLength)
{
websiteName = websiteName.Substring(0, 60);
return value;
}
return websiteName;
return value.Substring(0, maxLength);
}

private const string AzureManagementScope = "https://management.azure.com/.default";
private const string AzureManagementEndpoint = "https://management.azure.com/";
// For Azure App Service, the maximum length for a host name is 63 characters. With slot, the host name is 59 characters, with 4 characters reserved for random slot suffix (very edge case).
// Source of truth: https://msazure.visualstudio.com/One/_git/AAPT-Antares-Websites?path=%2Fsrc%2FHosting%2FAdministrationService%2FMicrosoft.Web.Hosting.Administration.Api%2FCommonConstants.cs&_a=contents&version=GBdev
internal const int MaxHostPrefixLengthWithSlot = 59;
internal const int MaxWebSiteNamePrefixLengthWithSlot = 40;
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,11 @@ record struct EndpointMapping(string Scheme, BicepValue<string> Host, int Port,
/// <returns>A <see cref="BicepValue{T}"/> representing the slot hostname, truncated to 60 characters.</returns>
public BicepValue<string> GetSlotHostName(BicepValue<string> deploymentSlot)
{
var websitePrefix = BicepFunction.Take(
BicepFunction.Interpolate($"{BicepFunction.ToLower(resource.Name)}-{AzureAppServiceEnvironmentResource.GetWebSiteSuffixBicep()}"), AzureAppServiceWebSiteResource.MaxWebSiteNamePrefixLengthWithSlot);

return BicepFunction.Take(
BicepFunction.Interpolate($"{BicepFunction.ToLower(resource.Name)}-{AzureAppServiceEnvironmentResource.GetWebSiteSuffixBicep()}-{BicepFunction.ToLower(deploymentSlot)}"), 60);
BicepFunction.Interpolate($"{websitePrefix}-{BicepFunction.ToLower(deploymentSlot)}"), AzureAppServiceWebSiteResource.MaxHostPrefixLengthWithSlot);
}

public async Task ProcessAsync(CancellationToken cancellationToken)
Expand Down Expand Up @@ -284,6 +287,7 @@ public void BuildWebSite(AzureResourceInfrastructure infra)
/// <param name="acrMidParameter">The Azure Container Registry managed identity parameter.</param>
/// <param name="acrClientIdParameter">The Azure Container Registry client ID parameter.</param>
/// <param name="containerImage">The container image parameter.</param>
/// <param name="slotConfigNames">The slot configuration names resource.</param>
/// <param name="isSlot">Indicates whether this is a deployment slot.</param>
/// <param name="parentWebSite">The parent website when creating a slot.</param>
/// <param name="deploymentSlot">The deployment slot name.</param>
Expand All @@ -295,6 +299,7 @@ private object CreateAndConfigureWebSite(
BicepValue<string> acrMidParameter,
ProvisioningParameter acrClientIdParameter,
ProvisioningParameter containerImage,
HashSet<string> slotConfigNames,
bool isSlot = false,
WebSite? parentWebSite = null,
BicepValue<string>? deploymentSlot = null)
Expand Down Expand Up @@ -423,6 +428,12 @@ private object CreateAndConfigureWebSite(
{
slot.SiteConfig.AppSettings.Add(new AppServiceNameValuePair { Name = kv.Key, Value = value });
}

// make app service references as sticky settings for slots
if (kv.Value is EndpointReference)
{
slotConfigNames.Add(kv.Key);
}
}

if (Args.Count > 0)
Expand Down Expand Up @@ -559,6 +570,9 @@ static FunctionCallExpression Join(BicepExpression args, string delimeter) =>
if (environmentContext.Environment.EnableDashboard)
{
webSiteRa = AddDashboardPermissionAndSettings(webSite, acrClientIdParameter, deploymentSlot);

// Make OTEL_SERVICE_NAME a deployment slot sticky appsetting if dashboard is enabled
slotConfigNames.Add("OTEL_SERVICE_NAME");
}

if (webSite is WebSite webSiteObject)
Expand Down Expand Up @@ -602,6 +616,7 @@ private void BuildWebSiteCore(

// Create parent WebSite from existing
WebSite? parentWebSite = null;
HashSet<string> stickyConfigNames = new();

if (deploymentSlot is not null)
{
Expand All @@ -617,6 +632,7 @@ private void BuildWebSiteCore(
acrMidParameter,
acrClientIdParameter,
containerImage,
stickyConfigNames,
isSlot: deploymentSlot is not null,
parentWebSite: parentWebSite,
deploymentSlot: deploymentSlot);
Expand Down Expand Up @@ -644,6 +660,8 @@ private void BuildWebSiteCore(
}
}
}

AddStickySlotSettings(deploymentSlot is null ? (WebSite)webSite : parentWebSite, stickyConfigNames);
}

/// <summary>
Expand All @@ -662,6 +680,7 @@ private void BuildWebSiteAndSlot(
var acrMidParameter = environmentContext.Environment.ContainerRegistryManagedIdentityId.AsProvisioningParameter(infra);
var acrClientIdParameter = environmentContext.Environment.ContainerRegistryClientId.AsProvisioningParameter(infra);
var containerImage = AllocateParameter(new ContainerImageReference(Resource));
HashSet<string> stickyConfigNames = new();

// Main site
var webSite = (WebSite)CreateAndConfigureWebSite(
Expand All @@ -671,6 +690,7 @@ private void BuildWebSiteAndSlot(
acrMidParameter,
acrClientIdParameter,
containerImage,
stickyConfigNames,
isSlot: false);

// Slot
Expand All @@ -681,6 +701,7 @@ private void BuildWebSiteAndSlot(
acrMidParameter,
acrClientIdParameter,
containerImage,
stickyConfigNames,
isSlot: true,
parentWebSite: (WebSite)webSite,
deploymentSlot: deploymentSlot);
Expand All @@ -702,6 +723,8 @@ private void BuildWebSiteAndSlot(
customizeWebSiteSlotAnnotation.Configure(infra, webSiteSlot);
}
}

AddStickySlotSettings(webSite, stickyConfigNames);
}

private BicepValue<string> GetEndpointValue(EndpointMapping mapping, EndpointProperty property)
Expand Down Expand Up @@ -856,6 +879,31 @@ private void UpdateHostNameForSlot(BicepValue<string> slotName)
}
}

/// <summary>
/// Configures sticky slot settings to ensure deployment slot specific app settings remains with each slot during swaps.
/// </summary>
/// <param name="parentWebSite">The parent WebSite resource.</param>
/// <param name="stickyConfigNames">The set of deployment slot app settings</param>
private void AddStickySlotSettings(WebSite? parentWebSite, HashSet<string> stickyConfigNames)
{
if (stickyConfigNames.Count == 0)
{
return;
}

SlotConfigNames slotConfigNames = new("slotConfigNames")
{
Parent = parentWebSite
};

foreach (var stickyConfig in stickyConfigNames)
{
slotConfigNames.AppSettingNames.Add(stickyConfig);
}

Infra.Add(slotConfigNames);
}

enum SecretType
{
None,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,3 +92,13 @@ resource container1_website_ra 'Microsoft.Authorization/roleAssignments@2022-04-
}
scope: webapp
}

resource slotConfigNames 'Microsoft.Web/sites/config@2025-03-01' = {
name: 'slotConfigNames'
properties: {
appSettingNames: [
'OTEL_SERVICE_NAME'
]
}
parent: webapp
}
Original file line number Diff line number Diff line change
Expand Up @@ -130,3 +130,13 @@ resource project1_website_ra 'Microsoft.Authorization/roleAssignments@2022-04-01
}
scope: webapp
}

resource slotConfigNames 'Microsoft.Web/sites/config@2025-03-01' = {
name: 'slotConfigNames'
properties: {
appSettingNames: [
'OTEL_SERVICE_NAME'
]
}
parent: webapp
}
Original file line number Diff line number Diff line change
Expand Up @@ -114,3 +114,13 @@ resource project1_website_ra 'Microsoft.Authorization/roleAssignments@2022-04-01
}
scope: webapp
}

resource slotConfigNames 'Microsoft.Web/sites/config@2025-03-01' = {
name: 'slotConfigNames'
properties: {
appSettingNames: [
'OTEL_SERVICE_NAME'
]
}
parent: webapp
}
Original file line number Diff line number Diff line change
Expand Up @@ -82,3 +82,14 @@ resource webapp 'Microsoft.Web/sites@2025-03-01' = {
}
}
}

resource slotConfigNames 'Microsoft.Web/sites/config@2025-03-01' = {
name: 'slotConfigNames'
properties: {
appSettingNames: [
'PROJECT1_HTTP'
'services__project1__http__0'
]
}
parent: webapp
}
Original file line number Diff line number Diff line change
Expand Up @@ -126,3 +126,15 @@ resource project2_website_ra 'Microsoft.Authorization/roleAssignments@2022-04-01
}
scope: webapp
}

resource slotConfigNames 'Microsoft.Web/sites/config@2025-03-01' = {
name: 'slotConfigNames'
properties: {
appSettingNames: [
'PROJECT1_HTTP'
'services__project1__http__0'
'OTEL_SERVICE_NAME'
]
}
parent: webapp
}
Original file line number Diff line number Diff line change
Expand Up @@ -119,3 +119,13 @@ resource project1_website_slot_ra 'Microsoft.Authorization/roleAssignments@2022-
}
scope: webappslot
}

resource slotConfigNames 'Microsoft.Web/sites/config@2025-03-01' = {
name: 'slotConfigNames'
properties: {
appSettingNames: [
'OTEL_SERVICE_NAME'
]
}
parent: webapp
}
Original file line number Diff line number Diff line change
Expand Up @@ -121,3 +121,13 @@ resource project1_website_slot_ra 'Microsoft.Authorization/roleAssignments@2022-
}
scope: webappslot
}

resource slotConfigNames 'Microsoft.Web/sites/config@2025-03-01' = {
name: 'slotConfigNames'
properties: {
appSettingNames: [
'OTEL_SERVICE_NAME'
]
}
parent: webapp
}
Original file line number Diff line number Diff line change
Expand Up @@ -128,3 +128,17 @@ resource project2_website_ra 'Microsoft.Authorization/roleAssignments@2022-04-01
}
scope: webapp
}

resource slotConfigNames 'Microsoft.Web/sites/config@2025-03-01' = {
name: 'slotConfigNames'
properties: {
appSettingNames: [
'PROJECT1_HTTPS'
'services__project1__https__0'
'PROJECT1_HTTP'
'services__project1__http__0'
'OTEL_SERVICE_NAME'
]
}
parent: webapp
}
Original file line number Diff line number Diff line change
Expand Up @@ -116,3 +116,13 @@ resource project2_website_ra 'Microsoft.Authorization/roleAssignments@2022-04-01
}
scope: webapp
}

resource slotConfigNames 'Microsoft.Web/sites/config@2025-03-01' = {
name: 'slotConfigNames'
properties: {
appSettingNames: [
'OTEL_SERVICE_NAME'
]
}
parent: webapp
}
Original file line number Diff line number Diff line change
Expand Up @@ -115,3 +115,13 @@ resource api_website_ra 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
}
scope: webapp
}

resource slotConfigNames 'Microsoft.Web/sites/config@2025-03-01' = {
name: 'slotConfigNames'
properties: {
appSettingNames: [
'OTEL_SERVICE_NAME'
]
}
parent: webapp
}
Original file line number Diff line number Diff line change
Expand Up @@ -96,3 +96,13 @@ resource api_website_ra 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
}
scope: webapp
}

resource slotConfigNames 'Microsoft.Web/sites/config@2025-03-01' = {
name: 'slotConfigNames'
properties: {
appSettingNames: [
'OTEL_SERVICE_NAME'
]
}
parent: webapp
}
Original file line number Diff line number Diff line change
Expand Up @@ -112,3 +112,13 @@ resource api_website_ra 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
}
scope: webapp
}

resource slotConfigNames 'Microsoft.Web/sites/config@2025-03-01' = {
name: 'slotConfigNames'
properties: {
appSettingNames: [
'OTEL_SERVICE_NAME'
]
}
parent: webapp
}
Original file line number Diff line number Diff line change
Expand Up @@ -122,3 +122,15 @@ resource project2_website_ra 'Microsoft.Authorization/roleAssignments@2022-04-01
}
scope: webapp
}

resource slotConfigNames 'Microsoft.Web/sites/config@2025-03-01' = {
name: 'slotConfigNames'
properties: {
appSettingNames: [
'PROJECT1_HTTP'
'services__project1__http__0'
'OTEL_SERVICE_NAME'
]
}
parent: webapp
}
Original file line number Diff line number Diff line change
Expand Up @@ -172,3 +172,13 @@ resource api_website_ra 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
}
scope: webapp
}

resource slotConfigNames 'Microsoft.Web/sites/config@2025-03-01' = {
name: 'slotConfigNames'
properties: {
appSettingNames: [
'OTEL_SERVICE_NAME'
]
}
parent: webapp
}
Loading