Skip to content

Commit

Permalink
feat: Retain existing settings during deployment - avm/res/web/site (
Browse files Browse the repository at this point in the history
…#3311)

## Description

This commit changes the app settings deployment in order to retain
existing app settings that are not defined in the Bicep file. This
change allows for updating **only** the app settings that are defined in
the Bicep file, while leaving the rest unchanged.

As this is a change in behavior, version number has been increased.

Fixes #949

## Pipeline Reference

<!-- Insert your Pipeline Status Badge below -->

| Pipeline |
| -------- |
|
[![avm.res.web.site](https://github.com/peterbud/bicep-registry-modules/actions/workflows/avm.res.web.site.yml/badge.svg)](https://github.com/peterbud/bicep-registry-modules/actions/workflows/avm.res.web.site.yml)
|

## Type of Change

<!-- Use the checkboxes [x] on the options that are relevant. -->

- [ ] Update to CI Environment or utilities (Non-module affecting
changes)
- [ ] Azure Verified Module updates:
- [ ] Bugfix containing backwards-compatible bug fixes, and I have NOT
bumped the MAJOR or MINOR version in `version.json`:
- [ ] Someone has opened a bug report issue, and I have included "Closes
#{bug_report_issue_number}" in the PR description.
- [ ] The bug was found by the module author, and no one has opened an
issue to report it yet.
- [x] Feature update backwards compatible feature updates, and I have
bumped the MINOR version in `version.json`.
- [ ] Breaking changes and I have bumped the MAJOR version in
`version.json`.
  - [ ] Update to documentation

## Checklist

- [x] I'm sure there are no other open Pull Requests for the same
update/change
- [x] I have run `Set-AVMModule` locally to generate the supporting
module files.
- [x] My corresponding pipelines / checks run clean and green without
any errors or warnings
  • Loading branch information
peterbud authored Sep 20, 2024
1 parent f1d14ed commit 07a0593
Show file tree
Hide file tree
Showing 14 changed files with 284 additions and 52 deletions.
108 changes: 89 additions & 19 deletions avm/res/web/site/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,9 @@ This module deploys a Web or Function App.
| `Microsoft.Insights/diagnosticSettings` | [2021-05-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Insights/2021-05-01-preview/diagnosticSettings) |
| `Microsoft.Network/privateEndpoints` | [2023-11-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-11-01/privateEndpoints) |
| `Microsoft.Network/privateEndpoints/privateDnsZoneGroups` | [2023-11-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-11-01/privateEndpoints/privateDnsZoneGroups) |
| `Microsoft.Web/sites` | [2022-09-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Web/2022-09-01/sites) |
| `Microsoft.Web/sites` | [2023-12-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Web/sites) |
| `Microsoft.Web/sites/basicPublishingCredentialsPolicies` | [2022-09-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Web/sites) |
| `Microsoft.Web/sites/config` | [2023-12-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Web/sites) |
| `Microsoft.Web/sites/config` | [2022-09-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Web/sites) |
| `Microsoft.Web/sites/extensions` | [2023-12-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Web/sites/extensions) |
| `Microsoft.Web/sites/hybridConnectionNamespaces/relays` | [2022-09-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Web/2022-09-01/sites/hybridConnectionNamespaces/relays) |
Expand All @@ -41,15 +42,16 @@ The following section provides usage examples for the module, which were used to
- [Function App, using only defaults](#example-1-function-app-using-only-defaults)
- [Function App, using large parameter set](#example-2-function-app-using-large-parameter-set)
- [Web App, using only defaults](#example-3-web-app-using-only-defaults)
- [Web App](#example-4-web-app)
- [WAF-aligned](#example-5-waf-aligned)
- [Web App, using only defaults](#example-6-web-app-using-only-defaults)
- [Web App, using large parameter set](#example-7-web-app-using-large-parameter-set)
- [Web App, using only defaults](#example-8-web-app-using-only-defaults)
- [Web App, using large parameter set](#example-9-web-app-using-large-parameter-set)
- [Web App](#example-10-web-app)
- [Windows Web App for Containers, using only defaults](#example-11-windows-web-app-for-containers-using-only-defaults)
- [Function App, using only defaults](#example-3-function-app-using-only-defaults)
- [Web App, using only defaults](#example-4-web-app-using-only-defaults)
- [Web App](#example-5-web-app)
- [WAF-aligned](#example-6-waf-aligned)
- [Web App, using only defaults](#example-7-web-app-using-only-defaults)
- [Web App, using large parameter set](#example-8-web-app-using-large-parameter-set)
- [Web App, using only defaults](#example-9-web-app-using-only-defaults)
- [Web App, using large parameter set](#example-10-web-app-using-large-parameter-set)
- [Web App](#example-11-web-app)
- [Windows Web App for Containers, using only defaults](#example-12-windows-web-app-for-containers-using-only-defaults)

### Example 1: _Function App, using only defaults_

Expand Down Expand Up @@ -515,7 +517,75 @@ module site 'br/public:avm/res/web/site:<version>' = {
</details>
<p>

### Example 3: _Web App, using only defaults_
### Example 3: _Function App, using only defaults_

This instance deploys the module as Function App with the minimum set of required parameters.


<details>

<summary>via Bicep module</summary>

```bicep
module site 'br/public:avm/res/web/site:<version>' = {
name: 'siteDeployment'
params: {
// Required parameters
kind: 'functionapp'
name: 'wsfaset001'
serverFarmResourceId: '<serverFarmResourceId>'
// Non-required parameters
appSettingsKeyValuePairs: {
AzureFunctionsJobHost__logging__logLevel__default: 'Trace'
FUNCTIONS_EXTENSION_VERSION: '~4'
FUNCTIONS_WORKER_RUNTIME: 'dotnet'
}
location: '<location>'
}
}
```

</details>
<p>

<details>

<summary>via JSON Parameter file</summary>

```json
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#",
"contentVersion": "1.0.0.0",
"parameters": {
// Required parameters
"kind": {
"value": "functionapp"
},
"name": {
"value": "wsfaset001"
},
"serverFarmResourceId": {
"value": "<serverFarmResourceId>"
},
// Non-required parameters
"appSettingsKeyValuePairs": {
"value": {
"AzureFunctionsJobHost__logging__logLevel__default": "Trace",
"FUNCTIONS_EXTENSION_VERSION": "~4",
"FUNCTIONS_WORKER_RUNTIME": "dotnet"
}
},
"location": {
"value": "<location>"
}
}
}
```

</details>
<p>

### Example 4: _Web App, using only defaults_

This instance deploys the module as a Linux Web App with the minimum set of required parameters.

Expand Down Expand Up @@ -591,7 +661,7 @@ module site 'br/public:avm/res/web/site:<version>' = {
</details>
<p>

### Example 4: _Web App_
### Example 5: _Web App_

This instance deploys the module as Web App with the set of logs configuration.

Expand Down Expand Up @@ -723,7 +793,7 @@ module site 'br/public:avm/res/web/site:<version>' = {
</details>
<p>

### Example 5: _WAF-aligned_
### Example 6: _WAF-aligned_

This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework.

Expand Down Expand Up @@ -865,7 +935,7 @@ module site 'br/public:avm/res/web/site:<version>' = {
</details>
<p>

### Example 6: _Web App, using only defaults_
### Example 7: _Web App, using only defaults_

This instance deploys the module as Web App with the minimum set of required parameters.

Expand Down Expand Up @@ -921,7 +991,7 @@ module site 'br/public:avm/res/web/site:<version>' = {
</details>
<p>

### Example 7: _Web App, using large parameter set_
### Example 8: _Web App, using large parameter set_

This instance deploys the module as Web App with most of its features enabled.

Expand Down Expand Up @@ -1389,7 +1459,7 @@ module site 'br/public:avm/res/web/site:<version>' = {
</details>
<p>

### Example 8: _Web App, using only defaults_
### Example 9: _Web App, using only defaults_

This instance deploys the module as a Linux Web App with the minimum set of required parameters.

Expand Down Expand Up @@ -1445,7 +1515,7 @@ module site 'br/public:avm/res/web/site:<version>' = {
</details>
<p>

### Example 9: _Web App, using large parameter set_
### Example 10: _Web App, using large parameter set_

This instance deploys the module asa Linux Web App with most of its features enabled.

Expand Down Expand Up @@ -1907,7 +1977,7 @@ module site 'br/public:avm/res/web/site:<version>' = {
</details>
<p>

### Example 10: _Web App_
### Example 11: _Web App_

This instance deploys the module as Web App with the set of api management configuration.

Expand Down Expand Up @@ -2003,7 +2073,7 @@ module site 'br/public:avm/res/web/site:<version>' = {
</details>
<p>

### Example 11: _Windows Web App for Containers, using only defaults_
### Example 12: _Windows Web App for Containers, using only defaults_

This instance deploys the module as a Windows based Container Web App with the minimum set of required parameters.

Expand Down
11 changes: 10 additions & 1 deletion avm/res/web/site/config--appsettings/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ This module deploys a Site App Setting.

| Resource Type | API Version |
| :-- | :-- |
| `Microsoft.Web/sites/config` | [2022-09-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Web/sites) |
| `Microsoft.Web/sites/config` | [2023-12-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Web/sites) |

## Parameters

Expand All @@ -35,6 +35,7 @@ This module deploys a Site App Setting.
| :-- | :-- | :-- |
| [`appInsightResourceId`](#parameter-appinsightresourceid) | string | Resource ID of the app insight to leverage for this resource. |
| [`appSettingsKeyValuePairs`](#parameter-appsettingskeyvaluepairs) | object | The app settings key-value pairs except for AzureWebJobsStorage, AzureWebJobsDashboard, APPINSIGHTS_INSTRUMENTATIONKEY and APPLICATIONINSIGHTS_CONNECTION_STRING. |
| [`currentAppSettings`](#parameter-currentappsettings) | object | The current app settings. |
| [`storageAccountResourceId`](#parameter-storageaccountresourceid) | string | Required if app of kind functionapp. Resource ID of the storage account to manage triggers and logging function executions. |
| [`storageAccountUseIdentityAuthentication`](#parameter-storageaccountuseidentityauthentication) | bool | If the provided storage account requires Identity based authentication ('allowSharedKeyAccess' is set to false). When set to true, the minimum role assignment required for the App Service Managed Identity to the storage account is 'Storage Blob Data Owner'. |

Expand Down Expand Up @@ -83,6 +84,14 @@ The app settings key-value pairs except for AzureWebJobsStorage, AzureWebJobsDas
- Required: No
- Type: object

### Parameter: `currentAppSettings`

The current app settings.

- Required: No
- Type: object
- Default: `{}`

### Parameter: `storageAccountResourceId`

Required if app of kind functionapp. Resource ID of the storage account to manage triggers and logging function executions.
Expand Down
16 changes: 12 additions & 4 deletions avm/res/web/site/config--appsettings/main.bicep
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ param appInsightResourceId string?
@description('Optional. The app settings key-value pairs except for AzureWebJobsStorage, AzureWebJobsDashboard, APPINSIGHTS_INSTRUMENTATIONKEY and APPLICATIONINSIGHTS_CONNECTION_STRING.')
param appSettingsKeyValuePairs object?

@description('Optional. The current app settings.')
param currentAppSettings object = {}

var azureWebJobsValues = !empty(storageAccountResourceId) && !(storageAccountUseIdentityAuthentication)
? {
AzureWebJobsStorage: 'DefaultEndpointsProtocol=https;AccountName=${storageAccount.name};AccountKey=${storageAccount.listKeys().keys[0].value};EndpointSuffix=${environment().suffixes.storage}'
Expand All @@ -51,9 +54,14 @@ var appInsightsValues = !empty(appInsightResourceId)
}
: {}

var expandedAppSettings = union(appSettingsKeyValuePairs ?? {}, azureWebJobsValues, appInsightsValues)
var expandedAppSettings = union(
currentAppSettings ?? {},
appSettingsKeyValuePairs ?? {},
azureWebJobsValues,
appInsightsValues
)

resource app 'Microsoft.Web/sites@2022-09-01' existing = {
resource app 'Microsoft.Web/sites@2023-12-01' existing = {
name: appName
}

Expand All @@ -62,15 +70,15 @@ resource appInsight 'Microsoft.Insights/components@2020-02-02' existing = if (!e
scope: resourceGroup(split(appInsightResourceId ?? '//', '/')[2], split(appInsightResourceId ?? '////', '/')[4])
}

resource storageAccount 'Microsoft.Storage/storageAccounts@2023-01-01' existing = if (!empty(storageAccountResourceId)) {
resource storageAccount 'Microsoft.Storage/storageAccounts@2023-05-01' existing = if (!empty(storageAccountResourceId)) {
name: last(split(storageAccountResourceId ?? 'dummyName', '/'))
scope: resourceGroup(
split(storageAccountResourceId ?? '//', '/')[2],
split(storageAccountResourceId ?? '////', '/')[4]
)
}

resource appSettings 'Microsoft.Web/sites/config@2022-09-01' = {
resource appSettings 'Microsoft.Web/sites/config@2023-12-01' = {
name: 'appsettings'
kind: kind
parent: app
Expand Down
17 changes: 12 additions & 5 deletions avm/res/web/site/config--appsettings/main.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"_generator": {
"name": "bicep",
"version": "0.29.47.4906",
"templateHash": "8777070640548664577"
"templateHash": "3998275265127709875"
},
"name": "Site App Settings",
"description": "This module deploys a Site App Setting.",
Expand Down Expand Up @@ -66,13 +66,20 @@
"metadata": {
"description": "Optional. The app settings key-value pairs except for AzureWebJobsStorage, AzureWebJobsDashboard, APPINSIGHTS_INSTRUMENTATIONKEY and APPLICATIONINSIGHTS_CONNECTION_STRING."
}
},
"currentAppSettings": {
"type": "object",
"defaultValue": {},
"metadata": {
"description": "Optional. The current app settings."
}
}
},
"resources": {
"app": {
"existing": true,
"type": "Microsoft.Web/sites",
"apiVersion": "2022-09-01",
"apiVersion": "2023-12-01",
"name": "[parameters('appName')]"
},
"appInsight": {
Expand All @@ -88,17 +95,17 @@
"condition": "[not(empty(parameters('storageAccountResourceId')))]",
"existing": true,
"type": "Microsoft.Storage/storageAccounts",
"apiVersion": "2023-01-01",
"apiVersion": "2023-05-01",
"subscriptionId": "[split(coalesce(parameters('storageAccountResourceId'), '//'), '/')[2]]",
"resourceGroup": "[split(coalesce(parameters('storageAccountResourceId'), '////'), '/')[4]]",
"name": "[last(split(coalesce(parameters('storageAccountResourceId'), 'dummyName'), '/'))]"
},
"appSettings": {
"type": "Microsoft.Web/sites/config",
"apiVersion": "2022-09-01",
"apiVersion": "2023-12-01",
"name": "[format('{0}/{1}', parameters('appName'), 'appsettings')]",
"kind": "[parameters('kind')]",
"properties": "[union(coalesce(parameters('appSettingsKeyValuePairs'), createObject()), if(and(not(empty(parameters('storageAccountResourceId'))), not(parameters('storageAccountUseIdentityAuthentication'))), createObject('AzureWebJobsStorage', format('DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1};EndpointSuffix={2}', last(split(coalesce(parameters('storageAccountResourceId'), 'dummyName'), '/')), listKeys(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(coalesce(parameters('storageAccountResourceId'), '//'), '/')[2], split(coalesce(parameters('storageAccountResourceId'), '////'), '/')[4]), 'Microsoft.Storage/storageAccounts', last(split(coalesce(parameters('storageAccountResourceId'), 'dummyName'), '/'))), '2023-01-01').keys[0].value, environment().suffixes.storage)), if(and(not(empty(parameters('storageAccountResourceId'))), parameters('storageAccountUseIdentityAuthentication')), union(createObject('AzureWebJobsStorage__accountName', last(split(coalesce(parameters('storageAccountResourceId'), 'dummyName'), '/'))), createObject('AzureWebJobsStorage__blobServiceUri', reference('storageAccount').primaryEndpoints.blob)), createObject())), if(not(empty(parameters('appInsightResourceId'))), createObject('APPLICATIONINSIGHTS_CONNECTION_STRING', reference('appInsight').ConnectionString), createObject()))]",
"properties": "[union(coalesce(parameters('currentAppSettings'), createObject()), coalesce(parameters('appSettingsKeyValuePairs'), createObject()), if(and(not(empty(parameters('storageAccountResourceId'))), not(parameters('storageAccountUseIdentityAuthentication'))), createObject('AzureWebJobsStorage', format('DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1};EndpointSuffix={2}', last(split(coalesce(parameters('storageAccountResourceId'), 'dummyName'), '/')), listKeys(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(coalesce(parameters('storageAccountResourceId'), '//'), '/')[2], split(coalesce(parameters('storageAccountResourceId'), '////'), '/')[4]), 'Microsoft.Storage/storageAccounts', last(split(coalesce(parameters('storageAccountResourceId'), 'dummyName'), '/'))), '2023-05-01').keys[0].value, environment().suffixes.storage)), if(and(not(empty(parameters('storageAccountResourceId'))), parameters('storageAccountUseIdentityAuthentication')), union(createObject('AzureWebJobsStorage__accountName', last(split(coalesce(parameters('storageAccountResourceId'), 'dummyName'), '/'))), createObject('AzureWebJobsStorage__blobServiceUri', reference('storageAccount').primaryEndpoints.blob)), createObject())), if(not(empty(parameters('appInsightResourceId'))), createObject('APPLICATIONINSIGHTS_CONNECTION_STRING', reference('appInsight').ConnectionString), createObject()))]",
"dependsOn": [
"app",
"appInsight",
Expand Down
3 changes: 2 additions & 1 deletion avm/res/web/site/main.bicep
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableT
}
}

resource app 'Microsoft.Web/sites@2022-09-01' = {
resource app 'Microsoft.Web/sites@2023-12-01' = {
name: name
location: location
kind: kind
Expand Down Expand Up @@ -294,6 +294,7 @@ module app_appsettings 'config--appsettings/main.bicep' = if (!empty(appSettings
storageAccountUseIdentityAuthentication: storageAccountUseIdentityAuthentication
appInsightResourceId: appInsightResourceId
appSettingsKeyValuePairs: appSettingsKeyValuePairs
currentAppSettings: !empty(app.id) ? list('${app.id}/config/appsettings', '2023-12-01').properties : {}
}
}

Expand Down
Loading

0 comments on commit 07a0593

Please sign in to comment.